#version 330 core
const float PI = 3.14159265358979323846;

uniform vec3 iResolution;
uniform float iTime;
uniform float uAlpha;

out vec4 FragColor;

void mainImage(out vec4 O, in vec2 I)
{
    O = vec4(0.0);
    float t = 0.0;
    float v = 0.0;
    vec3 a = vec3(0.0);

    // iterate ~50 times as in original
    for (int ii = 0; ii < 50; ++ii)
    {
        float i = float(ii);

        // Ray position
        vec3 p = t * normalize(vec3(I + I, 0.0) - iResolution.xyy);

        // Rotation axis (matches original expression)
        a = normalize(cos(vec3(6.0, 3.0, 0.0) + iTime - i * 0.01));

        // Move back camera
        p.xz += 10.0;

        // Rotate by (approx) 1.5*pi using the original compact expression
        // original: p = a*dot(a,p)-cross(a,p);
        p = a * dot(a, p) - cross(a, p);

        // Rotation & repetition in xz plane
        // emulate the mat2(cos(...-vec4(...))) trick from the original by computing 4 cos values
        float cy = cos(p.y * 0.02 - 0.0);
        float c1 = cos(p.y * 0.02 - 11.0);
        float c2 = cos(p.y * 0.02 - 33.0);
        float c3 = cos(p.y * 0.02 - 0.0);
        mat2 m = mat2(cy, -c1, c2, c3);
        vec2 xz = mod(p.xz * m, 30.0) - 15.0;
        p = vec3(xz, 0.1 * tan(p.y - iTime * 20.0));

        // Cylinder + sine distortion
        // The original used 'dot(sin(p), p++-p)' which relies on a post-increment trick.
        // That expression effectively yields the negative sum of ones multiplied by sin(p) -> approximate with sum of sin components.
        float ssum = sin(p.x) + sin(p.y) + sin(p.z);
        v = 4.0 * max(0.03, length(p.xy) - 5.0) + abs(ssum);

        // Color based on iter count
        O += exp(cos(i * 0.1 + vec4(0.0, 1.0, 2.0, 0.0))) / v;

        // advance ray distance
        t += v * 0.1;
    }

    O = tanh(O / 70.0);
}

void main()
{
    vec2 fragCoord = gl_FragCoord.xy;
    vec2 uv = fragCoord.xy / iResolution.xy;
    vec2 pos = -1.0 + 2.0 * uv;
    vec4 o;
    mainImage(o, pos * iResolution.xy); // pass coordinates scaled similarly to original usage
    o.a *= uAlpha;
    FragColor = o;
}
