#version 330 core
out vec4 FragColor;
in vec2 vUV;
uniform vec3 iResolution;
uniform float iTime;
uniform float uAlpha;

#define R(a) mat2(cos((a) + vec4(0.0, 11.0, 33.0, 0.0)))

float smax(float a, float b, float k)
{
    float h = clamp(0.5 + 0.5 * (a - b) / k, 0.0, 1.0);
    return mix(b, a, h) + k * h * (1.0 - h);
}

float map(vec3 p)
{
    vec3 q = p;
    p.xy *= R(p.z * 0.04 + iTime * 0.2);

    float scale = 1.0;

    for (float i = 0.0; i < 4.0; i++)
    {
        p.xy *= R(0.6 + i * 0.2);
        p.xy = abs(p.xy);
        p.xy -= 1.8 + 0.2 * sin(iTime * 0.5 + i);
        p.z = abs(fract(p.z * 0.15) * 6.66 - 3.33);
        p.xz *= R(0.2);
        p *= 1.3;
        scale *= 1.3;
    }

    float tri = max(abs(p.x) * 0.866 + p.y * 0.5, -p.y) - 1.5;
    float d = max(tri, abs(p.z) - 0.6) / scale;

    d = smax(d, 1.5 - length(q.xy), 0.8);
    d += (sin(q.x * 2.0 + iTime) * cos(q.y * 2.0) * sin(q.z * 2.0 - iTime)) * 0.15;

    return d;
}

void mainImage(out vec4 O, vec2 u)
{
    vec2 uv = (u + u - iResolution.xy) / iResolution.y;
    vec3 ro = vec3(sin(iTime * 0.5) * 0.4, cos(iTime * 0.3) * 0.4, iTime * 6.0);
    vec3 rd = normalize(vec3(uv, 1.0));

    rd.xy *= R(sin(iTime * 0.2) * 0.3);

    float t = 0.0;
    float d = 0.0;
    vec3 c = vec3(0.0);

    for (int i = 0; i < 70; i++)
    {
        vec3 p = ro + rd * t;
        d = map(p);

        vec3 palette = 0.5 + 0.5 * cos(p.z * 0.2 + p.y * 0.5 - iTime * 2.0 + vec3(0.0, 1.5, 3.0));
        c += palette * 0.015 / (0.3 + abs(d));

        t += d * 0.5;
    }

    O = vec4(tanh(c), 1.0);
}

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