#include <metal_stdlib>
using namespace metal;

constant float PI = 3.14159265358979323846;

struct Uniforms_MaskingEchoCircleCurve {
    float2 canvas_size;
    
    float line_width;
    float x_space_scale;
    float y_space_scale;
    float x_offset;
    float y_offset;
    float pinch_amount;
    
    float repeat_count;
    float repeat_x_spacing;
    float repeat_y_spacing;
    float repeat_rotation;
};

struct VertexOut_MaskingEchoCircleCurve {
    float4 position [[ position ]];
    float2 uv;
};


float masking_echo_circle_curve_mod(float a, float b) {
    return a - b * floor(a / b);
}

float2 masking_echo_circle_curve_mod_v2(float2 a, float b) {
    float x = masking_echo_circle_curve_mod(a.x, b);
    float y = masking_echo_circle_curve_mod(a.y, b);
    return float2(x, y);
}

float masking_echo_circle_curve_sdf(float2 p, float tb, float ra) {
    tb = 3.1415927 * 5.0 / 6.0 * max(tb, 0.0001);
    float2 co = ra * float2(sin(tb), cos(tb));

    p.x = abs(masking_echo_circle_curve_mod(p.x, co.x * 4.0) - co.x * 2.0);

    float2 p1 = p;
    float2 p2 = float2(abs(p.x - 2.0 * co.x), -p.y + 2.0 * co.y);
    float d1 = ((co.y * p1.x > co.x * p1.y) ? length(p1 - co) : abs(length(p1) - ra));
    float d2 = ((co.y * p2.x > co.x * p2.y) ? length(p2 - co) : abs(length(p2) - ra));
    
    return min(d1, d2);
}

float masking_echo_circle_curve_two_pi_ratio(float ratio) {
    return (2.0 * PI) * ratio;
}

float2 masking_echo_circle_curve_rotate_point(float2 point, float angle) {
    float cosTheta = cos(angle);
    float sinTheta = sin(angle);
    float2x2 rotationMatrix = float2x2(
        cosTheta, -sinTheta,
        sinTheta,  cosTheta
    );
    return rotationMatrix * point;
}

fragment float4 masking_echo_circle_curve_frag(
VertexOut_MaskingEchoCircleCurve in [[ stage_in ]],
constant Uniforms_MaskingEchoCircleCurve &u [[ buffer(0) ]],
float4 color [[ color(0) ]]) {
    
    float2 uv = in.uv;
    float2 size = u.canvas_size;
    uv.x *= size.x / size.y;
    
    float2 originalUV = uv;
    
    float line_width            = u.line_width;
    float x_space_scale         = u.x_space_scale;
    float y_space_scale         = u.y_space_scale;
    float x_offset              = u.x_offset;
    float y_offset              = u.y_offset;
    float pinch_amount          = u.pinch_amount;
    
    float repeat_count          = u.repeat_count;
    float repeat_x_spacing      = u.repeat_x_spacing;
    float repeat_y_spacing      = u.repeat_y_spacing;
    float repeat_rotation       = u.repeat_rotation;

    float dFinal = 0.0;
    for (float i=0.0; i<repeat_count; i++) {
        float2 localUV = originalUV;
        localUV -= 0.5;
        localUV = masking_echo_circle_curve_rotate_point(localUV, (repeat_rotation * i));
        localUV += 0.5;
        
        localUV.x = localUV.x - (x_offset + i * repeat_x_spacing);
        localUV.y = localUV.y - (y_offset + i * repeat_y_spacing);
        
        localUV.x *= x_space_scale;
        localUV.y *= y_space_scale;

        float d = masking_echo_circle_curve_sdf(localUV, pinch_amount, 0.4);
        d = smoothstep(line_width, line_width + 0.00001, d);
        d = 1.0 - d;
        
        float visibility_factor = 1.0 - (i / repeat_count);
        d *= visibility_factor;
        
        dFinal = max(dFinal, d);
    }
    
    dFinal = 1.0 - dFinal;
    
    return float4(dFinal, dFinal, dFinal, 1.0);
    
//    float space_scale = u.space_scale;
//    float repeat_value_scalar = u.repeat_value_scalar;
//    float x_offset = u.x_offset;
//    float y_offset = u.y_offset;
//    float radius = u.radius;
//    float invert_mix = u.invert_mix;
//    
//    float2 uv = in.uv;
//    
//    uv -= 0.5;
//    uv *= space_scale;
//    uv.x -= (x_offset * space_scale);
//    uv.y += (y_offset * space_scale);
//    
//    float dist = masking_echo_circle_sdf(uv, radius);
//    // dist = masking_echo_circle_mod(dist, 1.0);
//    dist = floor(dist) * repeat_value_scalar;
//    
//    return float4(dist, dist, dist, 1.0);
//    
//    float color_value = 1.0 - dist;
//    float invert_color_value = 1.0 - color_value;
//    
//    float final_color = mix(color_value, invert_color_value, invert_mix);
//    return float4(final_color, final_color, final_color, 1.0);
    
}
