#version 330 core

uniform vec3 iResolution;
uniform float iTime;
uniform float uAlpha;
uniform sampler2D iChannel0;
out vec4 FragColor;

#define A 9.0
#define T (iTime/3e2)
#define H(a) (cos(radians(vec3(180.0, 90.0, 0.0))+(a)*6.2832)*0.5+0.5)

float map(vec3 u, float v)
{
    float t = T,
          l = 5.0,
          f = 1e10,
          i = 0.0,
          y, z;

    u.xy = vec2(atan(u.x, u.y), length(u.xy));
    u.x += t * v * 3.1416 * 0.7;

    for (; i++ < l; )
    {
        vec3 p = u;
        y = round((p.y - i) / l) * l + i;
        p.x *= y;
        p.x -= y * y * t * 3.1416;
        p.x -= round(p.x / 6.2832) * 6.2832;
        p.y -= y;
        z = cos(y * t * 6.2832) * 0.5 + 0.5;
        f = min(f, max(length(p.xy), -p.z - z * A) - 0.1 - z * 0.2 - p.z / 1e2);
    }
    return f;
}

// replace iMouse with time-driven sine function -- return pixel coords matching iMouse.xy
vec2 syntheticMouse(float t, vec2 R)
{
    // center in pixels
    vec2 centerPixels = R * 0.5;
    // clear sway motion (different frequencies) and sensible amplitude in pixels
    vec2 sway = vec2(sin(t * 1.5), sin(t * 1.12 + 1.4));
    float amp = 0.35 * R.y; // amplitude relative to viewport height
    return centerPixels + sway * amp;
}

void mainImage(out vec4 C, vec2 U)
{
    vec2 R = iResolution.xy;
    vec2 M = syntheticMouse(iTime, R);
    vec2 m = (M - R / 2.0) / R.y;

    vec3 o = vec3(0.0, 0.0, -130.0);
    vec3 u = normalize(vec3(U - R / 2.0, R.y));
    vec3 c = vec3(0.0);
    vec3 p, k;

    float t = T;
    float v = -o.z / 3.0;
    float i = 0.0;
    float d = i;
    float s, f, z, r;

    bool b;

    for (; i++ < 70.0; )
    {
        p = u * d + o;
        p.xy /= v;
        r = length(p.xy);
        z = abs(1.0 - r * r);
        b = r < 1.0;
        if (b) z = sqrt(z);
        p.xy /= z + 1.0;
        p.xy -= m;
        p.xy *= v;
        p.xy -= cos(p.z / 8.0 + t * 3e2 + vec2(0.0, 1.5708) + z / 2.0) * 0.2;

        s = map(p, v);

        r = length(p.xy);
        f = cos(round(r) * t * 6.2832) * 0.5 + 0.5;
        k = H(0.2 - f / 3.0 + t + p.z / 2e2);
        if (b) k = 1.0 - k;

        c += min(exp(s / -0.05), s) * (f + 0.01) * min(z, 1.0) * sqrt(cos(r * 6.2832) * 0.5 + 0.5) * k * k;

        d += s * clamp(z, 0.3, 0.9);
        if (s < 1e-3 || d > 1e3) break;
    }

    c += texture(iChannel0, (u * d + o).xy).rrr * vec3(0.0, 0.4, s) * s * z * 0.03;
    c += min(exp(-p.z - f * A) * z * k * 0.01 / s, 1.0);

    vec2 j = p.xy / v + m;
    c /= clamp(dot(j, j) * 4.0, 0.04, 4.0);

    C = vec4(exp(log(c) / 2.2), 1.0);
}

void main()
{
    vec2 fragCoord = gl_FragCoord.xy;
    vec4 outColor = vec4(0.0);
    mainImage(outColor, fragCoord);
    outColor.a = uAlpha;
    FragColor = outColor;
}
