#define time iTime
#define ZPOS -10. + 1. * time
#define PI acos(-1.)


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

float cyl(vec3 p, vec3 c){
  return length(p.xy - c.xy) - c.z;
}


vec3 glow = vec3(0, 0, 0);
float at = 0.;

float map(vec3 p) {
    float s = 1.;
    float d = p.y + s;
    d = min(d, s - p.y);
    d = min(d, p.x + s);
    d = min(d, s - p.x);
    
    vec3 pc1 = p;
    vec3 pc2 = p;
    vec3 pc3 = p;
    vec3 pc4 = p;
    
    pc1.xy *= rot2d(cos(p.z * .9));
    pc2.xy *= rot2d(sin(p.z * .8));
    pc3.xy *= rot2d(-sin(p.z * .7));
    pc4.xy *= rot2d(-cos(p.z * .5));
    
    vec3 offset = vec3(0, .5, 0);
    float radius = .007;
    float m = 50.;
    
    for (float i = 0.; i < m; i++) {
        vec3 pc = p;
        pc.xy *= rot2d(PI * cos(pc.z * (i / m)));
        vec3 oc = offset;
        oc.xy *= rot2d(2. * PI * (i / m));
        float c = cyl(pc - oc, vec3(0, 0, radius));
        d = min(d, c);
    }

    at += 1. / (d * 3.1);
 
    return d;
}


void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
  vec2 uv = vec2(fragCoord.x / iResolution.x, fragCoord.y / iResolution.y);
  uv -= 0.5;
  uv /= vec2(iResolution.y / iResolution.x, 1);

  vec3 col = vec3(0);
  vec3 ro = vec3(0, 0., ZPOS);
  vec3 rd = normalize(vec3(uv.x, uv.y, 1.));
  rd.xy *= rot2d(time * .1);

  float d = 0.;
  vec3 glow = vec3(0);

  for (int i = 0; i < 100; i++) {
    vec3 p = ro + d * rd;
    float ds = map(p);
    
    if (ds < 0.01 || ds > 100.) {
      break;
    }
    d += ds * 1.;
    glow += .005 * at * vec3(
      .75,
      .33, 
      .4
    );
  }
  
  vec3 p = ro + d * rd;
  vec2 e = vec2(0.01, 0);
  vec3 n = normalize(map(p) - 
    vec3(
      map(p - e.xyy),
      map(p - e.yxy),
      map(p - e.yyx)
    )
  );

  vec3 lp = ro;
  vec3 tl = lp - p;
  vec3 tln = normalize(tl);
  float dif = dot(tln, n);
  
  col = 1.5 * vec3(dif);
  col = dif * glow;
  fragColor = vec4(col, 1.);
}
