#version 330 core
out vec4 FragColor;

uniform vec3 iResolution;
uniform float iTime;
uniform float uAlpha;
uniform float uAngleMultiplier;
uniform float uDepthScale;
uniform float uMainIterations;
uniform float uZOffset;
uniform float uInnerIterations;
uniform float uSinFreqFactor;
uniform float uCosPhaseFactor;
uniform float uDepthFactor;
uniform float uCosAmplitude;
uniform float uFrequencyScale;
uniform float uColorPhase;
uniform float uTanhScale;

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec4 O = vec4(0.0);
    vec2 I = fragCoord;

    float z = 0.0;
    float d = 1.0;
    float i = 0.0;
    float t = iTime;

    for (O *= i; i++ < uMainIterations;)
    {
        vec3 p = z * normalize(vec3(I + I, 0.0) - iResolution.xyx);
        p = vec3(atan(p.y, p.x) * uAngleMultiplier, p.z / uDepthScale, length(p.xy) - uZOffset);

        for (d = 1.0; d < uInnerIterations;)
            p += sin(p.yzx * d - t + uSinFreqFactor * i) / d++;

        z += d = uDepthFactor * length(vec4(p.z, uCosAmplitude * cos(p * uFrequencyScale) - uCosAmplitude));
        O += (1.0 + cos(i * uColorPhase + vec4(6.0, 1.0, 2.0, 0.0))) / d / i;
    }

    O = tanh(O * O / uTanhScale);
    O.a = uAlpha;
    fragColor = O;
}

void main()
{
    mainImage(FragColor, gl_FragCoord.xy);
}
