#version 330 core

in vec2 vUV;
out vec4 FragColor;

uniform vec3 iResolution; // x=width, y=height
uniform float iTime;
uniform float uAlpha;

vec2 rot(vec2 p, float a) {
    float c = cos(a);
    float s = sin(a);
    return vec2(p.x * c - p.y * s, p.x * s + p.y * c);
}

float map(vec3 p) {
    float t = 10.0 + dot(p, vec3(0.0, 1.0, 0.0));
    float ti = iTime * 0.1;
    float tir = floor(ti);
    float tif = fract(ti);
    vec3 tp = p;
    for(int i = 0 ; i < 3; i++) {
        p = tp;
        p.x += 1.0;
        t = min(t, length(mod(p.xz, 2.0) - 1.0) - 0.12);
        p.x += sin(p.y * 40.0 - iTime * 15.0) * 0.1;
        p.z += cos(p.y * 40.0 - iTime * 15.0) * 0.1;
        t = min(t, length(mod(p.xz, 2.0) - 1.0) - 0.1);
        tp = tp.zxy;
    }
    return t;
}

vec3 getnor(vec3 p) {
    vec2 dd = vec2(0.01, 0.0);
    vec3 kn = vec3(0.0);
    kn.x = map(p) - map(p + dd.xyy);
    kn.y = map(p) - map(p + dd.yxy);
    kn.z = map(p) - map(p + dd.yyx);
    return normalize(kn);
}

void mainImage(out vec4 O, in vec2 fragCoord)
{
    vec2 uv = (fragCoord / iResolution.xy) * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;
    float ti = iTime * 0.1;
    vec3 pos = vec3(ti, ti, ti) * 5.0;
    vec3 dir = normalize(vec3(uv, 1.0));

    float tir = floor(ti);
    float tif = fract(ti);
    float tism = smoothstep(0.01, 0.5, tif);

    dir.xy = rot(dir.xy, tism + tir);
    dir.xz = rot(dir.xz, tism + tir);

    float t = 0.0;
    // raymarch
    for(int i = 0 ; i < 256; i++) {
        float tm = map(pos + dir * t);
        if (tm < 0.01) break;
        t += tm * 0.2;
        if (t > 100.0) break;
    }
    vec3 ip = pos + dir * t;
    vec3 L = normalize(vec3(1.0,2.0,3.0));
    vec3 V = normalize(ip);
    vec3 N = getnor(ip);
    vec3 H = normalize(V + N);
    float D = max(0.1, dot(L, N));
    float S = pow(max(0.1, dot(L, H)), 16.0);
    vec3 color = D * S * vec3(1.0,2.0,10.0) + vec3(3.0,2.0,1.0) * vec3(pow(t, 2.0)) * 0.002 + vec3(map(ip + 0.01));
    O = vec4(color, 1.0);
}

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