#version 330 core

in vec2 vUV;
out vec4 FragColor;

uniform vec3 iResolution;
uniform float iTime;
uniform float uAlpha;
// Helper: 2D rotation matrix
mat2 rot(float a) {
    float c = cos(a);
    float s = sin(a);
    return mat2(c, -s, s, c);
}

// Macros converted to functions (operate on vec2)
void M(inout vec2 p) {
    p = abs(p) - 0.5;
    p *= rot(0.78539816339); // ~45deg
    p = abs(p) - 0.2;
}

void Q(inout vec2 p) {
    float ang = round(atan(p.y, p.x) * 4.0) / 4.0;
    p *= rot(ang);
}

// safe tanh for vec3
vec3 tanh_v3(vec3 v) {
    return vec3(tanh(v.x), tanh(v.y), tanh(v.z));
}

void main()
{
    // reconstruct fragment coords in pixels
    vec2 fragCoord = vUV * iResolution.xy;
    vec3 i = iResolution;

    vec3 O = vec3(0.0);
    vec3 f = vec3(0.0);
    float r_acc = 1.0;
    float t = -iTime * 2.0;

    // Prepare normalized screen coordinate used as ray origin XY
    vec2 F = fragCoord;

    // iterate: original used float loop up to 100
    const int ITER = 100;
    for (int ia = 0; ia < ITER; ia++) {
        float a = float(ia);

        // build point/ray similar to original intent
        vec3 p = vec3((F + F - i.xy) / i.y, 1.0);
        p *= r_acc; // scale by accumulated r

        p.z -= 12.0;

        // apply time-dependent rotations (approximation of R macro)
        p.xz *= rot(1.0 + cos(iTime));
        p.yz *= rot(1.0 + sin(iTime));

        // apply macro-like transforms
        M(p.xz);
        Q(p.xy);
        M(p.yz);
        M(p.xy);

        // contribution term (closely following original expression)
        float len_xy = length(p.xy);
        float osc = cos(length(p.xy + vec2(p.z)) * 2.0 - t);
        float contrib = (0.002 + 0.02 * smoothstep(0.9, 1.0, osc));
        vec3 col = (1.0 + cos(len_xy * 2.0 + a * 0.2 + vec3(0.0, 1.0, 2.0)));
        O += contrib * col / max(len_xy, 1e-5);

        // additional rotations with angle derived from local values
        p.yx *= rot(atan(p.y, p.x));
        p.zx *= rot(atan(max(p.z, 0.0), p.x));

        // compute f.x and update r accumulator following original intent
        // protect log domain
        float lx = max(abs(p.x), 1e-6);
        f.x = pow(0.67, floor(t - log(lx) / 0.4) - t);
        float d1 = length(p.xy);
        float d2 = abs(length(p - f) - f.x * 0.2);
        float d3 = abs(length(p - f * 0.67) - f.x * 0.134);
        r_acc += min(d1, min(d2, d3)) + 0.01;
    }

    // compress dynamic range similar to original tanh
    O = tanh_v3(O);

    FragColor = vec4(O, uAlpha);
}
