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

// similar to the forked, but no noise on the tubes
// and some more color :)

#define P(z) vec3(cos((z) * .11)  * 4.0, \
                  cos((z) * .13)  * 4.0, (z))
#define R(a) mat2(cos(a+vec4(0,33,11,0)))
#define T (iTime * 6.0)

float light = 0.0;

float sdfWisp(vec3 p) {

    // subtract path xy from p.xy
    p.xy -= P(p.z).xy;
   
    // move wisp left, right, up, down, back, and forth
    return length(p - vec3(
                    // X
                    sin(sin(T*0.5)+T*0.6)*1.0,
                    // Y
                    sin(sin(T*0.5)+T*0.6)*1.0,
                    // Z + T
                    T+16.0+cos(T*0.1)*10.0)) - 0.5;
                   
}

float sdfTube(vec3 p){
    // subtract path xy from p.xy
    p.xy -= P(p.z).xy;
    // repeat
    p.xy = mod(p.xy ,6.0) - 3.0;
    // distance to a cylinder relative to p.xy
    return length(p.xy) - 2.0;
}

float map(vec3 p) {

    // wisp distance
    float wisp = sdfWisp(p);
    // sample a bit for light
    light += wisp * 0.0125;
   
    // tube distance
    float tube = sdfTube(p);

    // return distance to tunnel, tube, or wisp
    return min(0.001+abs(wisp*0.8), 0.0005+abs(tube));
}

vec4 tanh_v(vec4 x) {
    vec4 e1 = exp(x);
    vec4 e2 = exp(-x);
    return (e1 - e2) / (e1 + e2);
}

// DEBUG: keep mainImage signature similar to original
void mainImage( out vec4 o, in vec2 u )
{
    float s, d=0.0, i=0.0;
    vec3 r = iResolution;
    u = (u - r.xy/2.0)/r.y;
   
    //light = 0.0;

    vec3 p = P(T), ro = p,
          Z = normalize(P(T+3.0) - p),
          X = normalize(vec3(Z.z,0.0,-Z)),
          D = vec3(R(sin(p.z*0.07)*1.5) * u, 1.0) * mat3(-X, cross(X, Z), Z);
    //if(abs(u.y) > 0.4) { o = vec4(0.0); return; }


    for(o *= i; i++ < 1e2;o += 1./s)
        p = ro + D * d * .9,
        d += s = map(p),
        o += (1.+cos(.2*p.z+vec4(3,1,0,0))/s);

   
    // protect light from zero to avoid NaNs and compute final color
    float safeLight = light; //max(light, 1e-6);
    //o = tanh_v(o * vec4(8.0, d/4.0, i/d*4.0, 0.0) / safeLight / 1e4);
    // ensure fragment is opaque so it overwrites the clear color
    //o.a = 1.0;
    o = vec4(tanh(o*vec4(8,d/4.,i/d*4.,0)/light/1e4 ));
    o.a = 1.0;
}

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