#version 330 core

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

in vec2 vTex;
out vec4 FragColor;

vec4 tanh_vec4(vec4 x)
{
    vec4 e = exp(2.0 * x);
    return (e - vec4(1.0)) / (e + vec4(1.0));
}

void mainImage(out vec4 O, in vec2 I)
{
    vec2 fragCoord = I;
    vec3 r = normalize(vec3(fragCoord + fragCoord, 0.0) - iResolution.xyy);

    float t = 0.0;
    O = vec4(0.0);

    // Rotate camera
    float ang = iTime * 0.1;
    r.xy *= mat2(cos(ang), -sin(ang), sin(ang), cos(ang));

    // Raymarching loop
    for (int k = 0; k < 50; k++)
    {
        vec3 p = t * r;
        // Rotate xz plane based on distance travelled
        float ang2 = t * 0.5;
        p.xz *= mat2(cos(ang2), -sin(ang2), sin(ang2), cos(ang2));
        // Move forward
        p.z -= iTime * 0.2;
        // Density inspired by fractal approach
        p = fract(p.zyx - 0.5) - 0.5;
        for (int jj = 0; jj < 7; jj++)
        {
            p = abs(p);
            p = (p.x < p.y) ? p.zxy : p.zyx;
            p = p * 1.5;
            p.x -= 1.0;
        }
        float v = abs(min(length(p.yz + p.x), length(p.xy)) + 0.005) / 50.0;
        v = max(v, 1e-6);
        O += exp(sin(float(k) * 0.1 * vec4(1.0, 2.0, 3.0, 1.0))) / v;
        t += v;
    }

    O = tanh_vec4(O / 20000.0);
}

void main()
{
    vec2 fragCoord = vTex * iResolution.xy;
    vec4 o;
    mainImage(o, fragCoord);
    o.a *= uAlpha;
    FragColor = o;
}
