#version 330 core

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

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

out vec4 FragColor;

mat2 rotate(float a){
  float s = sin(a);
  float c = cos(a);
  return mat2(c,-s,s,c);
}

float fbm(vec3 p){
  float amp = 1.;
  float fre = 1.;
  float n = 0.;
  for(float i=0.;i<5.;i++){
    n += amp*abs(dot(cos(p*fre), vec3(.06)));
    amp *= .5;
    fre *= 2.;
  }
  return n;
}

vec3 path(float v){
  return vec3(cos(v*.2+sin(v*.1+T))*4.,
              sin(v*.2+cos(v*.1)+T)*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.-R)/R.y;

  O.rgb *= 0.;
  O.a = 1.;

  float t = iTime * 4.;
  vec3 ro = path(t);
  vec3 front = normalize(path(t+2.) - ro);
  vec3 up = vec3(0,1,0);
  vec3 right = normalize(cross(front, up));
  vec3 rd = mat3(right, up, front) * normalize(vec3(uv, 1));

  float zMax = 50.;
  float z = .1;

  vec3 col = vec3(0);
  for(float i=0.;i<100.;i++){
    vec3 p = ro + rd * z;

    float d = length(p.xy-path(p.z).xy)-3.;
    d = d * (1.-hash12(uv.xy*100.+iTime)*.2);

    d = abs(d)+.01;
    d += fbm(p*2.);

    float k = sin(p.z+p.x*.5+p.y*.3)*.5+.5;

    col += k * (1.1+sin(vec3(3,2,1)+p.x+p.z))/d;

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

  col = tanh(col / 1e2);
  O.rgb = col;
}

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