const float PI=acos(-1.);
const float TAU=2.*PI;

#define rep(i,n) for(int i=0;i<n;i++)
#define sat(x) clamp(x,0.,1.)
#define norm(x) normalize(x)
float box(vec3 p, vec3 b)
{
  vec3 q = abs(p) - b;return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
}
vec3 hash(vec3 x)
{
  uvec3 v = floatBitsToUint(x);v = v * 1664525u + 1013904223u;v.x += v.y * v.z;v.y += v.z * v.x;v.z += v.x * v.y;v ^= v >> 16u;v.x += v.y * v.z;v.y += v.z * v.x;v.z += v.x * v.y;return vec3(v) / float(0xffffffffu);
}
mat3 bnt(vec3 T)
{
  T = norm(T);vec3 N = vec3(0, 1, 0);vec3 B = norm(cross(N, T));N = norm(cross(T, B));return mat3(B, N, T);
}
mat2 rot(float a)
{
  float s=sin(a),c=cos(a);
  return mat2(c,s,-s,c);
}

float alt,lt;
int bt;
float tr;
#define sc hash(vec3(bt))
float sdf(vec3 p)
{
  float d=1e9;
  
  float m=sat(dot(vec3(1),smoothstep(.05,.0,abs(fract(p*4.)-.5))))*.01;
  
  int b=bt%4;
  if(b==0){
  p.z=mod(p.z,4.)-2.;
  p.y=mod(p.y+2.5,5.)-2.5;
  p.x=abs(p.x);
  d=abs(box(p,vec3(2,2,10)))-.1;
  d=max(d,-box(p-vec3(2,0,0),vec3(1,1.5,1)));
  }else if(b==1){
    d=p.y+1.8;
    p.xz=mod(p.xz,6.)-3.;
    d=min(d,box(p,vec3(0,1e9,0))-1.);
  }else if(b==2){
    p.z=mod(p.z,4.)-2.;
    d=min(d,box(p,vec3(4,4,1)));
    d=max(d,-box(p,vec3(3,3,1.5)));
  }else if(b==3){
    p=mod(p,4.)-2.;
    vec3 s=vec3(.1,.1,1);
    d=min(d,box(p,s));
    d=min(d,box(p,s.yzx));
    d=min(d,box(p,s.zxy));
  }
  
  d+=m;

  return d*.5;
}

vec3 normal(vec3 p)
{
  vec2 k=vec2(1,-1);
  float e=1e-3;
  return norm(k.xyy*sdf(p+e*k.xyy)+k.yxy*sdf(p+e*k.yxy)+k.yyx*sdf(p+e*k.yyx)+k.xxx*sdf(p+e*k.xxx));
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
  vec3 col=vec3(0);
	vec2 fc = gl_FragCoord.xy,res=iResolution.xy,asp=res/min(res.x,res.y);
  vec2 uv=fc/res;
  float bpm=240./140.;
  alt=lt=iTime/bpm;
  tr=pow(fract(lt),.3);
  bt=int(lt);
  lt=(tr+float(bt))*bpm;
  vec2 suv=(uv*2.-1.)*asp;
  
  if(hash(sc).x<.3)suv=abs(suv)*rot(tr*PI);
  else bt+=dot(suv,vec2(0,1)*rot(tr*TAU))<.0?4:0;

  vec3 ro=vec3(0,0,lt*5.);
  vec3 dir=vec3(0,0,1);
  if(sc.x<.5)
  {
    ro=vec3(10.*sin(lt),0,lt*5.);
    dir=vec3(-sin(lt),sin(lt)*.3+.3,1);
  }
  vec3 rd=norm(bnt(dir)*vec3(suv,mix(.3,3.,tr)));
  
  float l=0.,d;
  vec3 rp;
  rep(i,256)
  {
    rp=rd*l+ro;
    if(sc.z<.5)
    {
      rp.xy*=rot(l*.05);
    }
    l+=d=sdf(rp);
    if(d<1e-3||l>1000.)break;
  }
  
  vec3 ld=norm(vec3(-1,1,1));
  vec3 n=normal(rp);
  vec3 sro=rp+n*.1;
  float sl=0.,vi=1.;
  rep(i,64)
  {
    vec3 srp=sro+ld*sl;
    sl+=d=sdf(srp);
    vi=min(vi,exp2(4.+4.*hash(srp).x)*d/sl);
    if(d<1e-3){vi=0.;break;}
  }
  float ao=sqrt(sat(sdf(rp+n*.2)/.2));
  
  col=vec3(vi+ao);
  if(sc.y<.5)
  {
  col*=hash(floor(rp*4.+.5)).x<.1?vec3(1,.4,.1):vec3(1);
  }else{
    ivec3 x=ivec3(rp*20.)+1000;
    col*=(x.x^x.y^x.z)%109%64<8?vec3(.3,.3,.8):vec3(1);
  }
  
  col=sat(col);
  vec3 sk=vec3(.5,.6,.7)*pow(sat(rd.y+.9),2.);
  col=mix(sk,col,exp(-l*.04));
  
  uv=fc/res;
  suv=(uv*2.-1.)*asp;
  
  vec2 ruv=suv*8.;
  vec2 auv=abs(fract(ruv)-.5);
  col+=hash(ceil(vec3(ruv,alt*16.))).x<.1?float(any(lessThan(auv,vec2(.02)))&&all(lessThan(auv,vec2(.3)))):.0;
  col+=step(abs(uv.y-.1),.03)*step(abs(uv.x-.5),.5*fract(alt))*step(fract(dot(vec2(1),suv)*20.+10.*alt),.5);
  
  col*=smoothstep(.8,.4,length(uv-.5));
  col+=hash(vec3(fc,alt))*.05;
  col.r=smoothstep(.0,1.,col.r);
  
  
  col=mix(col,texture(iChannel0,uv).rgb,.5);

	fragColor = vec4(col,1);
}
