#version 330 core

uniform vec3 iResolution;
uniform float iTime;
uniform float uAlpha;
uniform sampler2D iChannel0;

out vec4 FragColor;

// stable tanh for tone mapping
vec4 tanh4(vec4 x) {
    vec4 e = exp(clamp(2.0 * x, vec4(-20.0), vec4(20.0)));
    return (e - vec4(1.0)) / (e + vec4(1.0));
}

void mainImage(out vec4 o, in vec2 fragCoord)
{
    // follow the original compact Shadertoy logic but with clearer steps
    vec2 u = fragCoord;
    float i = 0.0;
    float r;
    float s;
    float t = iTime;

    // sample alpha from iChannel0 as seed (use ivec2 wrap similar to original)
    ivec2 tc = ivec2(u) % 1024;
    float d = 0.5 * texelFetch(iChannel0, tc, 0).a;

    vec3 p = iResolution;

    // normalize coordinates as in original
    u = (u - p.xy / 2.0) / p.y;

    // initialize accumulator
    o = vec4(0.0);

    // iterative loop (70 iterations like original 7e1)
    for (i = 0.0; i < 70.0; i += 1.0)
    {
        // compute procedural position
        p = vec3(u * d, d + t + t) + cos(t + 0.3 * p.zzx) * 0.5;
        // apply same mat2 from original (cos over vec4 produces four scalars used by mat2)
        p.xy *= mat2(cos(0.3 * t + vec4(0.0, 33.0, 11.0, 0.0)));
        // density increment term
        s = 0.006 + 0.6 * abs(dot(tanh(cos(0.1 * t + p * 0.5) * 2.0), cos(p + sin(t + p.zxy * 4.0) / 8.0)));
        d += s;
        // accumulate color vector as in original
        o += (1.0 + cos(0.3 * p.z + vec4(3.0, 1.0, 0.0, 0.0))) / s;
    }

    // final tonemapping like original
    o = tanh4(o / 5e3 * exp(d / 24.0));
}

void main()
{
    mainImage(FragColor, gl_FragCoord.xy);
    FragColor.a *= uAlpha;
}
