#version 330 core

#define T iTime
#define PI 3.141596
const float EPSILON = 1e-6;

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

out vec4 FragColor;

vec3 path(float v){
  return vec3(cos(v*.2+2.*cos(v*.2))*4.,
              sin(v*.2+2.*sin(v*.2))*4., v);
}

float hash12(vec2 p)
{
    vec3 p3  = fract(vec3(p.xyx) * .1031);
    p3 += dot(p3, p3.yzx + 33.33);
    return fract((p3.x + p3.y) * p3.z);
}

void mainImage(out vec4 O, in vec2 I){
  vec2 R = iResolution.xy;
  vec2 uv = (I*2.0 - R)/R.y;

  O.rgb *= 0.0;
  O.a = 1.0;

  float t = T*1.2;

  vec3 ro = path(t);
  vec3 front = normalize(path(t+1.0)-ro);
  vec3 up = vec3(0.0,1.0,0.0);
  vec3 right = normalize(cross(front, up));
  vec3 rd = mat3(right, up, front)*normalize(vec3(uv, 1.0));

  float zMax = 50.0;
  float z = 0.1;
  float d = hash12(uv*40.0);

  vec3 col = vec3(0.0);
  for(float i=0.0;i<100.0;i++){
    vec3 p = ro + rd * z;

    float f = 1.0;
    float a = 0.26;
    for(float k=0.0; k<6.0; k++){
      p += sin(p.zxy*f+T*3.0)*a;
      f += 1.0;
    }

    d += length(p.xy - path(p.z).xy) - 4.0;
    d = abs(d)*0.1 + 0.005;

    col += (1.1+sin(vec3(3.0,2.0,1.0)+p.x*0.1+p.z*0.4))/d;

    if(d<EPSILON || z>zMax) break;
    z += d;
  }

  col = tanh(col / 4000.0);

  O.rgb = col;
}

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