#version 330 core

in vec2 vUV;
out vec4 FragColor;

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

float tau = 2.0 * acos(-1.0);

mat2 rot(float r){
    float c = cos(r), s = sin(r);
    return mat2(c,s,-s,c);
}

vec2 pmod(vec2 p, float r){
    float a = atan(p.x,p.y) + tau / r / 2.0;
    float n = tau / r;
    a = floor(a / n) * n;
    return p * rot(-a);
}

float sdCube(vec3 p, float r){
    vec3 q = abs(p) - r;
    return length(max(q, vec3(0.0)));
}

float map(vec3 p){
    vec3 q = p;
    q.z += iTime;
    q.xy *= rot(q.z * 0.1 - iTime * 0.2);
    q.xy = pmod(q.xy, 5.0);
    q.xz = fract(q.xz + 0.5) - 0.5;
    vec2 i = floor(q.xz + 0.5);
    q.y -= 5.0 + 1.0 * sin(q.z * 0.5 + iTime);
    return sdCube(q, 0.4);
}

float glow(vec3 ro, vec3 rd, float ma){
    float t = 0.0;
    float ac = 0.0;
    vec3 rp = ro;
    for(int i = 0; i < 24; i++){
        if(t > ma) break;
        float d = map(rp);
        ac += exp(-d * 1000.0);
        rp += rd * d;
        t += d;
    }
    return ac;
}

void main(){
    vec2 fragCoord = vUV * iResolution.xy;
    vec2 p = (2.0 * fragCoord - iResolution.xy) / min(iResolution.x, iResolution.y);
    vec3 color = vec3(0.0);

    vec3 ro = vec3(0.0, 0.0, -5.0);
    vec3 ta = vec3(0.0);
    vec3 ww = normalize(ta - ro);
    vec3 uu = normalize(cross(ww, vec3(0.0, 1.0, 0.0)));
    vec3 vv = normalize(cross(uu, ww));
    float sd = 1.0;
    vec3 rd = normalize(uu * p.x + vv * p.y + ww * sd);
    vec3 rp = ro;
    float d, t = 0.0;

    for(int i = 0; i < 64; i++){
        d = map(rp);
        rp += rd * d;
        t += d;
    }

    color = vec3(glow(ro, rd, t)) * 0.2 * vec3(
        0.25 * sin(t + iTime * 10.0) + 0.25,
        0.25 * sin(t + iTime * 2.0)  + 0.25,
        0.25 * sin(t + iTime * 3.0)  + 0.25);

    FragColor = vec4(color, uAlpha);
}
