#extension GL_OES_standard_derivatives : enable

precision highp float;

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;



//part 2
//

//--------utill---------
float pi = acos(-1.);
mat2 rot(float a){return mat2(cos(a),sin(a),-sin(a),cos(a));}
float bo(vec3 p , vec3 s){p = abs(p)-s;return max(p.x,max(p.y,p.z));}
//float bar(vec2 p , vec2 s){p = abs(p)-s;return max(p.x,p.y);}
float bar(vec2 p,vec2 s,float r){p-=clamp(p,-s,s);return length(p)-r;}
vec2 min2(vec2 a,vec2 b){if(a.x < b.x){return a;}return b;}
#define TT(x,y) floor(x)+pow(fract(x),y)
float rand(vec3 p){p  = fract( p*0.3183099+.1 );p *= 17.0;return fract( p.x*p.y*p.z*(p.x+p.y+p.z) );}
float noise(vec3 p){vec3 fp = floor(p);vec3 fs = fract(p);vec3 sf = vec3(1.,0.,0.); float a = rand(fp);float b = rand(fp + sf);float c = rand(fp + sf.yxz);float d = rand(fp + sf.xxz);float e = rand(fp + sf.yyx);float f = rand(fp + sf.xyx);float g = rand(fp + sf.yxx);float h = rand(fp + sf.xxx); vec3 u = smoothstep(0.,1.,fs); return mix(mix(mix(a,b,u.x),mix(c,d,u.x),u.y),mix(mix(e,f,u.x),mix(g,h,u.x),u.y),u.z);}
//point light
vec3 lightEffect(vec3 mat,float lPower,vec3 N,vec3 rd ,vec3 lightPos, vec3 lightDir,vec3 lightCol,vec3 pos,float shadow)
{
   vec3 col = vec3(0.);
   float surfToLight = length(lightPos - pos);
   vec3 surfToLightDir = normalize(pos - lightPos);
   float range = clamp(dot(lightDir , surfToLightDir),0.,1. );

   float attenuation = 1./(1. + pow(surfToLight,2.));
   float diff = max(0.,dot(N,lightDir) - range) * attenuation * lPower;
   col += diff * lightCol * (attenuation ) + mat * diff;

   float sp = max(0.,dot(rd,reflect(-lightDir,N)) - range) * attenuation;
   sp = pow(sp,1.5);
   col += sp * vec3(1.);
   float rim = pow(clamp(1. - dot(N, -rd), 0., 1.), 1.) * 1. * attenuation;
   col += rim * diff * mat;
   col -= shadow;

   return col;
}
//----------------------
//-------------------------------------------
//walk
       float walk(vec3 p,float gtime){

       float sig = sign(p.z);
       float l = 1.;
       p.x += sig/2. - 1.4;
       l += floor((gtime - sig/2.)/2. );
       float s = 2.;
       p.x -=s*clamp(floor(p.x/s + .5),-l,l);

       p.y -=1.8;
       vec3 wp = p;
       wp.x += .01;
       p.x -= clamp(p.x,-.15,.1);
       p.z = abs(p.z)-.3;

       float o = length(p)-.15 - max(0.,sin(p.x/2.-3.2 ));
       o=max(o,p.y-.1);
       o = max(o,-(length(wp.xy)-.04));
       return o;
   }
       vec2 road(vec3 p,float gtime)
   {
       vec2 o = vec2(bar(p.yz-vec2(12.,0.),vec2(10.,1.),.2),0.);
       o.x = max(o.x,-walk(p,gtime));
       if(o.x < .01){
               o.x+=noise(p*100.)/195.;
       }
       return o;
   }
       vec2 lead(vec3 p,float gtime)
   {
       vec2 o = vec2(10.,1.);
       p.x += gtime;
       p.yz *= rot(sin(gtime*10.)/10.);
       p.y += sin(-gtime*pi + pi/2. + p.x)/12.+.1;
     //  p.xy *= rot(pi/4.);
       p.xy *= rot(-sin(sin(p.x/10.)-.02)+pi/4.);
      // p.xy *= rot(-smoothstep(0.,-3.,p.x));
       vec3 lp = p;
       float l = 30.;
       p.x -= l;
       p.yz *= rot(p.x*13.3);

       p.yz = abs(p.yz)-.02;
       p.x -= clamp(p.x,-l,l*2.);

       o.x = length(p)-.02;
       lp.yz *= rot(2.3);
       lp.x += 0.2;
       lp.x -= clamp(lp.x,-.03,.03);
       o.x = min(o.x,length(vec2(length(lp.xy)-.2,lp.z))-.03);
       if(o.x < 0.01)
       {
           o.x -= noise(p * 40.)/390.;
       }
       return o;
   }
   vec2 map1(vec3 p,float gtime)
   {
       vec2 o = vec2(10.);
       p.x -= TT((gtime+.5),1.5);
       //p.x -=time;
               o = min2(o,road(p,gtime));
       o = min2(o,lead(p,gtime));
       return o;
   }

   vec2 march1(vec3 cp , vec3 rd,float gtime)
   {
       float depth = 0.;
       for(int i = 0 ; i< 99 ; i++)
       {
           vec3 rp = cp + rd * depth;
           vec2 d = map1(rp,gtime);
           if(abs(d.x) < 0.001)
           {
               return vec2(depth,d.y);
           }
           if(depth > 30.)break;
           depth += d.x;
       }
       return vec2(-depth , 0.);

   }

   float shadowmarch1(vec3 cp , vec3 rd,float gtime)
   {
       float depth = 0.;
       for(int i = 0 ; i< 256 ; i++)
       {
           vec3 rp = cp + rd * depth;
           vec2 d = map1(rp,gtime);
           if(d.x < 0.01)
           {
               return -1.;
           }
           if(depth > 60.)break;
           depth += d.x;
       }
       return 1.;
   }
       vec3 getMat1(vec3 pos,float id)
   {
       vec3 col = vec3(1.);
       if(id == 0.)
       {
           col = vec3(0.6);
       }else if(id == 1.){
               col = vec3(1.5,0.3,0.);
       }
       return col;
   }
       vec3 eye(vec3 rd)
   {
       vec3 col = vec3(0.);
       //rd.z = abs(rd.z)-1.;
       float shift = 0.1;
       float th = step(0.,pow(max(dot(rd,vec3(1.,0.,shift)),0.)-1.003,10.));
       th += step(0.,pow(max(dot(rd,vec3(1.,0.,-shift)),0.)-1.003,10.));
       rd.z = abs(rd.z)-shift;
       vec2 eyep = rd.yz;
       col = vec3(1.,1.,0.) * th;
       col -= smoothstep(0.,1.,1.-length(eyep)*12.) * vec3(0.,0.,1.);

       col = th * col;
       return col;
   }
   vec4 scene1(vec3 cp,vec3 target,float gtime) {
       vec2 p = (gl_FragCoord.xy * 2.0 - resolution.xy) / min(resolution.x, resolution.y);
       p.y -= 0.2;
       vec3 col = vec3(0.);
       vec3 cd = normalize(vec3(target - cp));
       vec3 cs = normalize(cross(cd , vec3(0.,1.,0.)));
       vec3 cu = normalize(cross(cd,cs));
       float fov = 2.5;
       vec3 rd = normalize(cd * fov + cs * p.x + cu * p.y);
       vec2 d = march1(cp,rd,gtime);
       float side = max(0.,dot(rd,vec3(-1.,0.,0.))-.03);
       col += pow(side,3.5)*1.3;
       vec3 bcol = col;

     //  col += eye(rd);
       if( d.x > 0.)
       {
           vec2 e = vec2(1.0, -1.0) * .003;
           vec3 pos = cp + rd * d.x;
           vec3 N = normalize(
                     e.xyy * map1(pos + e.xyy,gtime).x +
                     e.yyx * map1(pos + e.yyx,gtime).x +
                     e.yxy * map1(pos + e.yxy,gtime).x +
                     e.xxx * map1(pos + e.xxx,gtime).x);
           vec3 lightPos = vec3(0.,-1.5,0.);
           vec3 lightDir = vec3(0.,-1.,0.);
           vec3 lightCol = vec3(0.,1.,1.);
           float lpower = 3.;
           float shadow = step(shadowmarch1(pos + N*.01,lightDir,gtime),0.);
           vec3 mat = getMat1(pos,d.y);
           //vec3 lightEffect(vec3 mat,float lPower,vec3 N,vec3 rd ,vec3 lightPos, vec3 lightDir,vec3 lightCol,vec3 pos,float shadow)
           col += lightEffect(mat,lpower,N,rd ,lightPos, lightDir,lightCol,pos,shadow);

           float t = 1.-exp(-.001 * d.x * d.x * d.x);
           col = mix(col,bcol,t);
       }

       //col = pow(col,vec3(.4545));
       return vec4(col,abs(d.x));
   }
//-------------------------------------------
       float dogWalk(vec3 p,float gtime){

       float sig = sign(p.z);
       //p.x -=s*clamp(floor(p.x/s),-l,l);
       p.x = mod(p.x+sig/4.,1.)-.5;

       p.y -=1.79;

       vec3 wp = p;
       wp.x += .01;
       //p.x -= clamp(p.x,-.15,.1);

       p.z = abs(p.z)-.3;

       float o = length(p * vec3(1.6,1.1,1.3)+vec3(.1,0.,0.))-.1;
       p.z = abs(p.z);
       o = min(o,length(p - vec3(-.18,0.,0.06))-.03);
       o = min(o,length(p - vec3(-.1,0.,0.12))-.03);
       o=max(o,p.y-.1);
       //o = max(o,-(length(wp.xy)-.04));
       return o;
   }
       vec2 road2(vec3 p,float gtime)
   {
       vec2 o = vec2(bar(p.yz-vec2(12.,0.),vec2(10.,1.),.2),0.);
       o.x = max(o.x,-walk(p,gtime));
       o.x = max(o.x,-dogWalk(p,gtime));
       if(o.x < .01){
               o.x+=noise(p*100.)/195.;
       }
       return o;
   }
       vec2 lead2(vec3 p,float gtime)
   {
       vec2 o = vec2(10.,1.);
       p.x += gtime;
       p.xz *= rot(pi);
       p.yz *= rot(sin(gtime*10.)/10.);
       p.y += sin(-gtime*pi + pi/2. + p.x)/12.+.1;
     //  p.xy *= rot(pi/4.);
       p.xy *= rot(-sin(sin(p.x/10.)-.02)+pi/4.);
      // p.xy *= rot(-smoothstep(0.,-3.,p.x));
       vec3 lp = p;
       float l = 30.;
       p.x -= l;
       p.yz *= rot(p.x*13.3);

       p.yz = abs(p.yz)-.02;
       p.x -= clamp(p.x,-l,l*2.);

       o.x = length(p)-.02;
       lp.yz *= rot(2.3);
       lp.x += 0.2;
       lp.x -= clamp(lp.x,-.03,.03);
       o.x = min(o.x,length(vec2(length(lp.xy)-.2,lp.z))-.03);
       if(o.x < 0.01)
       {
           o.x -= noise(p * 40.)/390.;
       }
       return o;
   }
   vec2 map2(vec3 p,float gtime)
   {
       vec2 o = vec2(10.);
       p.x -= TT((gtime+.5),1.5);
       //p.x -=time;
               o = min2(o,road2(p,gtime));
       o = min2(o,lead2(p,gtime));
       return o;
   }

   vec2 march2(vec3 cp , vec3 rd,float gtime)
   {
       float depth = 0.;
       for(int i = 0 ; i< 99 ; i++)
       {
           vec3 rp = cp + rd * depth;
           vec2 d = map2(rp,gtime);
           if(abs(d.x) < 0.001)
           {
               return vec2(depth,d.y);
           }
           if(depth > 30.)break;
           depth += d.x;
       }
       return vec2(-depth , 0.);

   }

   float shadowmarch2(vec3 cp , vec3 rd,float gtime)
   {
       float depth = 0.;
       for(int i = 0 ; i< 256 ; i++)
       {
           vec3 rp = cp + rd * depth;
           vec2 d = map2(rp,gtime);
           if(d.x < 0.01)
           {
               return -1.;
           }
           if(depth > 60.)break;
           depth += d.x;
       }
       return 1.;
   }
   vec4 scene2(vec3 cp,vec3 target,float gtime) {
       vec2 p = (gl_FragCoord.xy * 2.0 - resolution.xy) / min(resolution.x, resolution.y);
      // p.x += (rand(vec3(p.yyy))*1.);
       p.x += step(0.,sin(sin(p.y * 6. + time * 1.) * 2.)-.999);
       p.y -= 0.2;
       vec3 col = vec3(1.,1.,.6)/2.;
       vec3 cd = normalize(vec3(target - cp));
       vec3 cs = normalize(cross(cd , vec3(0.,1.,0.)));
       vec3 cu = normalize(cross(cd,cs));
       float fov = 2.5;
       vec3 rd = normalize(cd * fov + cs * p.x + cu * p.y);
       vec2 d = march2(cp,rd,gtime);
       float side = max(0.,dot(rd,vec3(-1.,0.,0.))-.03);
       col += pow(side,3.5)*1.3;
       vec3 bcol = col;

     //  col += eye(rd);
       if( d.x > 0.)
       {
           vec2 e = vec2(1.0, -1.0) * .003;
           vec3 pos = cp + rd * d.x;
           vec3 N = normalize(
                     e.xyy * map2(pos + e.xyy,gtime).x +
                     e.yyx * map2(pos + e.yyx,gtime).x +
                     e.yxy * map2(pos + e.yxy,gtime).x +
                     e.xxx * map2(pos + e.xxx,gtime).x);
           vec3 lightPos = vec3(0.,-1.5,0.);
           vec3 lightDir = vec3(0.,-1.,0.);
           vec3 lightCol = vec3(0.,1.,1.);
           float lpower = 33.;
           float shadow = step(shadowmarch2(pos + N*.01,lightDir,gtime),0.);
           vec3 mat = getMat1(pos,d.y);
           //vec3 lightEffect(vec3 mat,float lPower,vec3 N,vec3 rd ,vec3 lightPos, vec3 lightDir,vec3 lightCol,vec3 pos,float shadow)
           col += lightEffect(mat,lpower,N,rd ,lightPos, lightDir,lightCol,pos,shadow);

           float t = 1.-exp(-.001 * d.x * d.x * d.x);
           col = mix(col,bcol,t);
       }
       col *= mix(vec3(1.),vec3(floor(noise(p.xyx*600.)+.5),floor(noise(1.-p.xxy*300.)+.5),floor(noise(p.yxx*860.))+.5),step(noise(vec3(p.yx,time/2900.)*500.),.3));
       //col = pow(col,vec3(.4545));
       return vec4(col,abs(d.x));
   }
//-------------------------------------------

vec3 sceneManager()
{
   vec4 scol = vec4(0.);
   float gtime = mod(time ,46.);
   if(gtime < 23.)
   {
       gtime -= 0.;
       vec3 cam = vec3(-5.,-1.5,-8.)/1.6;
       vec3 tar = vec3(1.,0.,0.);
       //------------------------
       if(gtime < 7. )
       {
           cam = vec3(0.,0.,-6.);
               tar = vec3(0.);
       }else if(gtime < 9.)
       {
           cam = vec3(-.3,-2.,0.);
           cam.xy += sin(gtime)/10.;
           gtime -= 7.;
               tar = vec3(-.4,-0.,0.);
       }else if(gtime < 13.)
       {
           cam = vec3(-.3,-2.,0.);
           cam.xy += sin(gtime)/10.;
               gtime -= 9.;
               tar = vec3(-.4,-0.,0.);
           tar = mix(tar,vec3(-2.,-1.7,0.),smoothstep(0.,1.,gtime/4. + sin(gtime/4.)));
       }
       else if(gtime < 17.)
       {
           cam = vec3(-.3,-2.,0.);
           cam.xy += sin(gtime)/10.;
           gtime -= 13.;
               tar = vec3(-2.,-1.7,0.);
           tar.xz *= rot(pi/1.03*smoothstep(0.,1.,gtime/3.));
           tar.y = mix(tar.y,-1.6,smoothstep(0.,1.,gtime/3.));
       }
       else if(gtime < 23.)
       {
           cam = vec3(-.3,-2.,0.);
           cam.xy += sin(gtime)/10.;
           gtime -= 17.;
               tar = vec3(-2.,-1.6,0.);
           tar.xz *= rot(pi/1.03);
       }
       scol += scene1(cam,tar,gtime);
   }else if(gtime < 46.){
       float gt = gtime - 23.;
       vec3 cam = vec3(-5.,-1.5,-8.)/1.6;
       vec3 tar = vec3(1.,0.,0.);
       if(gt < 7. )
       {
           cam = vec3(0.,0.,-6.);
               tar = vec3(0.);
       }else if(gt < 9.)
       {
           cam = vec3(-.3,-2.,0.);
           cam.xy += sin(gtime)/10.;
           gtime -= 7.;
               tar = vec3(-.4,-0.,0.);
       }else if(gt < 13.)
       {
           cam = vec3(-.3,-2.,0.);
           cam.xy += sin(gtime)/10.;
               gtime -= 9.;
               tar = vec3(-.4,-0.,0.);
           tar = mix(tar,vec3(-2.,-1.7,0.),smoothstep(0.,1.,gtime/4. + sin(gtime/4.)));
       }
       else if(gtime < 17.)
       {
           cam = vec3(-.3,-2.,0.);
           cam.xy += sin(gtime)/10.;
           gtime -= 13.;
               tar = vec3(-2.,-1.7,0.);
           tar.xz *= rot(pi/1.03*smoothstep(0.,1.,gtime/3.));
           tar.y = mix(tar.y,-1.6,smoothstep(0.,1.,gtime/3.));
       }
       else if(gt < 23.)
       {
           cam = vec3(-.3,-2.,0.);
           cam.xy += sin(gtime)/10.;
           gtime -= 17.;
               tar = vec3(-2.,-1.6,0.);
           tar.xz *= rot(pi/1.03);
       }
       scol += scene2(cam,tar,gtime);
   }
   return scol.rgb;
}

void main(void){
       vec3 col = vec3(0.);
   col = sceneManager();
   gl_FragColor = vec4(col,1.);
}