

float det=.005, maxdist=50., pi=3.1416, gl=0.;

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


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


//---Chess -----------------------------------------------------------


#define PI 3.1416
const float det2=.005;
const float max_dist=5.;
float obj_id;
vec3 light_dir2;

// polynomial smooth min (k = 0.1);
float smin( float a, float b, float k )
{
    float h = max( k-abs(a-b), 0.0 )/k;
    return min( a, b ) - h*h*k*(1.0/4.0);
}

float de2(vec3 p) {
    p.z+=.2;
    vec3 sphp=p;
    sphp.y+=.1;
    sphp.xy*=rot(sin(iTime)*.3);
    float sph=100.;
    
    for (float a=0.; a<PI*2.; a+=PI/10.) {
        float an=a-iTime*.5;
        sphp.xz=p.xz+vec2(cos(an),sin(an));
		sphp.y+=sin(an*PI)*.5;
        sph=smin(sph,length(sphp)-.2,.3);    
    }
	sph*=.5;
    float spec=texture(iChannel0,vec2(p.x*.05+.5,0.)).r;
    float flo=p.y+.7-spec*.3;
    float d=smin(sph,flo,.2);
    float d2=min(sph,flo);
    obj_id=step(flo,d2);
    return d;
}

vec3 normal2(vec3 p) {
	vec3 d=vec3(0.,det*2.,0.);
    return normalize(vec3(de2(p+d.yxx),de2(p+d.xyx),de2(p+d.xxy))-de2(p));
}

float shadow2(vec3 from) {
    float td=.1,sh=1.,d;
    for (int i=0; i<30; i++) {
		vec3 p=from-light_dir2*td;
        d=de2(p);
        td+=d;
		sh=min(sh,20.*d/td);
		if (sh<.001) break;
    }
    return clamp(sh,0.,1.);
}

float ao2(vec3 p, vec3 n) {
	float st=.02;
	float ao=0.;

    for(float i=0.; i<6.; i++ ) {
        float td=st*i;
        float d=de2(p+n*td);
        ao+=max(0.,(td-d)/td);
    }
    return clamp(1.-ao*.15,0.,1.);
}

float is_id(float id1, float id2) {
	return step(abs(id1-id2),.1);
}


vec3 color(vec3 p, float id) {
    vec3 col=vec3(0.);
	float lin=mod(floor(p.x*3.)+floor(p.z*3.),2.);
    col+=vec3(lin)*is_id(obj_id,1.);
	return col;
}


vec3 light(vec3 p, vec3 dir, vec3 n, vec3 col){
    float aoc=ao2(p,n);
    float sh=shadow2(p);
	float amb=.25;
    float diff=max(0.,dot(light_dir2,-n))*.7*sh;
	vec3 ref=reflect(dir,n);
    float spec=pow(max(0.,dot(light_dir2,-ref)),5.)*.7*sh;
    return col*(amb+diff)*aoc+spec;
}


vec4 march2(vec3 from, vec3 dir) {
	float d, tot_dist, id;
    vec3 p, col=vec3(0.);
    float foc=1.;
    float min_d=100.;
    float g=0.;
    for (int i; i<100; i++) {
    	p=from+dir*tot_dist;
        d=de2(p);
    	tot_dist+=d;
        min_d=min(d,min_d);
        if (d<det || tot_dist>max_dist) break;
        g+=(1.-obj_id);
    }
    vec3 back_col;;
    if (d<det2) {
    	p-=dir*det2*2.;
        id=obj_id;
        vec3 n=normal2(p);
     	col=color(p,id);
        col=light(p,dir,n,col);
    } else {
    	tot_dist=max_dist;
        p=from+dir*tot_dist;
        back_col=smoothstep(0.,4.,vec3(p.y+1.))*step(7.,mod(gl_FragCoord.y,10.));
        back_col+=pow(max(0.,dot(dir,light_dir2)),5.);
    }
    float norm_dist=tot_dist/max_dist;
    col=mix(col,back_col,norm_dist);
	col+=g*g*.0001;
    col*=1.+abs(p);
    return vec4(col,norm_dist);

}



vec4 mainImage2( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv=fragCoord/iResolution.xy;
    uv-=.5;
    uv.x*=iResolution.x/iResolution.y;
    vec3 dir=normalize(vec3(uv,1.3));
    vec3 from=vec3(0.,(sin(iTime*.2)-1.)*.2,-3.2+sin(iTime*.3));
    float t=iTime*.2;
    from.xz*=rot(t);
    dir.xz*=rot(t);
	light_dir2=normalize(vec3(1.,-0.5,0.));
	light_dir2.xz*=rot(iTime*.5);
    vec4 col=march2(from, dir)*min(1.,iTime);
    fragColor=col;
    return fragColor;
}

// -- occasional spectators ------------------------------------------------------------------


float s;
float t;
vec3 ot;
vec3 colo=vec3(0);

float de3(vec3 p) 
{
  float z=p.z;
  ot=vec3(100);
  colo=p;
  float sc=1.;
  p.xy*=rot(p.z*.1);
  p=abs(15.-mod(p,30.))-1.;
  for (int i=0; i<8; i++) {
    p.xy*=rot(1.);
    p.yz*=rot(t*10.);
    ot=min(ot,abs(p.xyz));
    p.xy=abs(p.xy+5.)-abs(p.xy-5.)-p.xy;
    float s=1.5;
    sc*=s;
    p=p*s;
  }
  colo=exp(-15.*ot);
  return (length(p)/sc-.5)*.8;
  
}


vec3 march3(vec3 from, vec3 dir) {
  float d, td=0.;
  vec3 p, c=vec3(0.);
  for (int i=0; i<50; i++) 
  {
    p=from+dir*td;
    d=de3(p);
    td+=max(.01,abs(d));
    c+=colo*exp(-.1*td);
  }
  return (c*c*.05);
  
}
 
vec4 mainImage3( out vec4 fragColor, in vec2 fragCoord )
{
  t=floor(iTime*10.)*.001;
  s=texture(iChannel0,vec2(.3)).r;
  vec2 uv = vec2(gl_FragCoord.x / iResolution.x, gl_FragCoord.y / iResolution.y);
  uv-=.5;
  uv.x*=iResolution.x/iResolution.y;
  if (fract(t*4.)<.5) t+=floor(length(uv)*4.-t*100.); else t+=floor(length(uv.y+uv.x)*1.5-t*100.);
  vec3 dir=normalize(vec3(uv,.5+s*.5));
  vec3 from=vec3(cos(t*.5)*2.,sin(t)*2.,t*200.);
  from.xy*=rot(t*100.);
  dir.yz*=rot(smoothstep(-.5,.5,sin(t*10.))*10.);
  vec3 c = march3(from,dir);
  c=abs(cross(c,dir));
  c.xy*=rot(t*50.+s*20.);
  fragColor = vec4(c,1.);
  return fragColor;
}



//-gumball----------------------------------------------------------------------------

float det3=.005, maxdist3=50.,sphit=0.,t2;
vec3 g=vec3(0.), from, blobcol=vec3(1.,.3,.5);
float sou;

vec3 hsv2rgb(vec3 c)
{
    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}


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



vec3 path(float t)
{
    vec3 p=vec3(vec2(sin(sin(t*.1)),cos(t*.05))*10.,t);
    p.x+=pow(smoothstep(.2,.5,abs(.5-fract(t*.01))),3.)*10.;
    return p;
}

vec3 fractal2(vec2 p)
{
    p=abs(5.-mod(p,10.))-5.;
    float ot=1000., it;
    for (int i=0; i<8; i++)
    {
        p=abs(p)/(p.x*p.y)-1.;
        float d=abs(p.y)+fract(abs(p.x)*.1+iTime*.3+float(i)*.25+sou*.5);
        if (ot>d) {
            ot=d;
            it=float(i);
        }
    }
    ot=exp(-10.*ot);
    return hsv2rgb(vec3(it*.02+.6,.8,ot));
//    return vec3(ot*ot*ot,ot*ot,ot);
}

float box2(vec3 p, vec3 l)
{
    vec3 c=abs(p)-l;
    return length(max(vec3(0.),c))+min(0.,max(c.x,max(c.y,c.z)));
}

float road(vec3 p)
{
    float s=sign(p.y);
    p.y=-abs(p.y)-3.;
    float z=p.z;
    float d=p.y+3.;
    p.z=mod(p.z,20.)-10.;
    float der=1., sc=1.2;
    for (int i=0; i<4; i++)
    {
        p=abs(p)-1.;
        p.xz*=rot(radians(s*-45.));
        p.xy*=rot(radians(45.));
    }
    d=max(d, -box2(p,vec3(5.,5.,10.)));
    return d*.7;
}

float de4(vec3 p)
{
    float sph=length(p-path(t2+10.))-1.5-length(sin(p))*.5;
    p.xy-=path(p.z).xy;
    float roa=road(p);
    float d=min(sph,roa);
    if (d==sph) sphit=1.; else sphit=0.;
    return d;
}

vec3 normal4(vec3 p)
{
    vec2 e=vec2(0.,det);
    return normalize(vec3(de4(p+e.yxx),de4(p+e.xyx),de4(p+e.xxy))-de4(p));
}

vec3 shade(vec3 p)
{
    vec3 n=normal4(p);
    p.xy-=path(p.z).xy;
    if(sphit>.5) p.y-=t2;
    vec3 col=fractal2(p.xy)*abs(n.z)+fractal2(p.xz)*abs(n.y)+fractal2(p.yz)*abs(n.x);
    //col*=sphit;
    return col;
}

vec3 march4(vec3 from, vec3 dir)
{
    vec3 p, col=vec3(0.);
    float d, td=0.;
    for (int i=0; i<80; i++)
    {
        p=from+td*dir;
        d=de4(p)*(1.-hash(gl_FragCoord.xy+iTime)*.1);
        if (d<det3 || td>maxdist3) break;
        td+=d;
        if (d<1.5) g+=shade(p)/(1.+d*d)*exp(-.001*td*td)*.5*step(5.,td)+sphit*.03*blobcol;
    }
    if (d<det) {
        vec3 n=normal4(p);
        g+=abs(n.x)*.3*exp(-.002*td*td)+sphit*blobcol;
        vec3 ref=reflect(normalize(dir-vec3(.5,1.,0.)),n);
        g+=pow(max(0.,dot(ref,n)),20.)*sphit*.7;
    } else
    {
        td=maxdist;
      //  g+=dir.y*vec3(1.,.6,.5)*.5;
    }
    return g;
}

mat3 lookat(vec3 dir, vec3 up) 
{
	dir=normalize(dir);vec3 rt=normalize(cross(dir,normalize(up)));
    return mat3(rt,cross(rt,dir),dir);
}


vec4 mainImage4( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = (fragCoord-iResolution.xy*.5)/iResolution.y;
    t2=iTime*7.;
    float inv=0.;
    if (mod(iTime,15.)<8.) from=path(t2); else from=path(floor(t2+20.)),inv=.7;
    uv*=rot(iTime*inv);
    vec3 adv=path(t2+1.);
    vec3 dir=normalize(vec3(uv,.7));
    dir=lookat(adv-from,vec3(0.,1.,0.))*dir;
    //from.xz*=rot(t);
    //dir.xz*=rot(t);
    //dir.xy*=rot(-(adv-from).x*.5);
    vec3 col=abs(inv-march4(from, dir));
    
    // Output to screen
    fragColor=vec4(col,1.0);
    return fragColor;
}


//------------------------------------------------------


void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv=fragCoord/iResolution.xy-.5;
    sou = texture(iChannel0,vec2(.0,.7)).r;
    float tt=mod(iTime,300.);
    vec4 col1=mainImage2(fragColor, fragCoord);
    vec4 col2=mainImage3(fragColor, fragCoord);
    fragColor = col1+col2*.5;
}
