#version 330 core


out vec4 FragColor;

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

float Noise(vec3 pos, vec3 x, vec3 r, float s)
{
    return abs(dot(sin(x * pos * s), r)) / s;
}

void mainImage(out vec4 o, vec2 u)
{
    float i = 0.0;
    float d = 0.0;
    float s = 0.03;
    float t = iTime;

    mat2 m;
    vec3 q;
    vec3 p3 = vec3(0.0);
    vec2 res = iResolution.xy;

    u = (u - res * 0.5) / res.y;
    o = vec4(0.0);

    for (; i < 100.0; i += 1.0)
    {
        q = p3 = vec3(u * d, d + t * 6.0) * 0.5;

        float c = cos(t * 0.6) * 0.12;
        m = mat2(
            cos(c), -sin(c),
            sin(c),  cos(c)
        );

        q.xy *= m;
        p3.xy *= m;
        p3.y += sin(t * 0.3);

        for (s = 0.03; s < 2.0; s += s)
        {
            p3 += vec3(Noise(p3, vec3(16.0), vec3(0.012), s));
            q  += vec3(Noise(q, t + q + 24.0, vec3(0.002), s));
        }

        float d1 = 0.2 * abs(3.0 - q.y - cos(p3.x) * 0.2) + 0.001;
        float d2 = 0.9 * abs(1.0 + p3.y) + 0.005;

        s = 0.04 + min(d1, d2);
        d += s;
        o += vec4(1.0 / s);
    }

    u -= vec2(0.3, 0.2);
    o *= mix(pow(vec4(1.0, 0.25, 0.5, 0.0), vec4(1.5)), vec4(3.5, 3.0, 4.0, 0.0), smoothstep(0.2, -0.5, u.y));
    o = tanh(o * o / 3e6 / max(length(u), 0.001));
    o.a = uAlpha;
}

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

