#ifdef GL_ES
precision mediump float;
#endif

// glslsandbox uniforms
uniform float time;
uniform vec2 resolution;
uniform vec2 mouse;

// shadertoy emulation
#define iTime time
#define iResolution resolution
vec4 iMouse = vec4(0.);

// raymarching based from https://www.shadertoy.com/view/wdGGz3
#define USE_MOUSE 0
#define MAX_STEPS 100
#define MAX_DIST 100.
#define SURF_DIST .001
#define Rot(a) mat2(cos(a),-sin(a),sin(a),cos(a))
#define Slice(p,a) dot(p,vec2(cos(a),sin(a)))
#define antialiasing(n) n/min(iResolution.y,iResolution.x)
#define S(d,b) smoothstep(antialiasing(1.0),b,d)
#define B(p,s) max(abs(p).x-s.x,abs(p).y-s.y)
#define Tri(p,s,a) max(-dot(p,vec2(cos(-a),sin(-a))),max(dot(p,vec2(cos(a),sin(a))),max(abs(p).x-s.x,abs(p).y-s.y)))
#define DF(a,b) length(a) * cos( mod( atan(a.y,a.x)+6.28/(b*8.0), 6.28/((b*8.0)*0.5))+(b-1.)*6.28/(b*8.0) + vec2(0,11) )
#define MATERIAL_UPPER 0
#define MATERIAL_OUTSOLE 1
#define MATERIAL_EFFECT 2
#define SCENE0 3.0
#define SCENE1 10.0
#define SCENE2 20.0
#define SCENE3 30.0
#define SCENE_LENGTH 38.0

float getSceneTime(){
   return mod(iTime,SCENE_LENGTH);
}

float Hash21(vec2 p) {
   p = fract(p*vec2(234.56,789.34));
   p+=dot(p,p+34.56);
   return fract(p.x+p.y);
}

// https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
float dot2( in vec2 v ) { return dot(v,v); }
float dot2( in vec3 v ) { return dot(v,v); }
float opSmoothUnion( float d1, float d2, float k ) {
   float h = clamp( 0.5 + 0.5*(d2-d1)/k, 0.0, 1.0 );
   return mix( d2, d1, h ) - k*h*(1.0-h);
}

// IQ's 3D noise function. It's faster than the FBM and enough for me to design.
// The compile is also faster.
float noise3d( vec3 p )
{
   const vec3 s = vec3(27, 111, 57);
   vec3 ip = floor(p); p -= ip;
   vec4 h = vec4(0., s.yz, s.y + s.z) + dot(ip, s);
   p = p*p*(3. - 2.*p);
   //p *= p*p*(p*(p*6. - 15.) + 10.); // option
   h = mix(fract(sin(h) * 43758.545), fract(sin(h + s.x) * 43758.545), p.x);
   h.xy = mix(h.xz, h.yw, p.y);
   return mix(h.x, h.y, p.z);
}

vec2 combine(vec2 val1, vec2 val2  ){
   return (val1.x < val2.x)?val1:val2;
}

vec2 smoothCombine(vec2 val1, vec2 val2, float k ){
   if(val1.x < val2.x){
       val1.x = opSmoothUnion(val1.x,val2.x,k);
       return val1;
   }
   val2.x = opSmoothUnion(val1.x,val2.x,k);
   return val2;
}

// https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
float sdTorus( vec3 p, vec2 t )
{
 vec2 q = vec2(length(p.xz)-t.x,p.y);
 return length(q)-t.y;
}

// https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
float sdCappedCylinder( vec3 p, float h, float r )
{
 vec2 d = abs(vec2(length(p.yz),p.x)) - vec2(r,h);
 return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}

// https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
float sdBox( 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);
}

// https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
float sdEllipsoid( vec3 p, vec3 r )
{
 float k0 = length(p/r);
 float k1 = length(p/(r*r));
 return k0*(k0-1.0)/k1;
}

// https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
float sdCappedCone( vec3 p, float h, float r1, float r2 )
{
 vec2 q = vec2( length(p.xz), p.y );
 vec2 k1 = vec2(r2,h);
 vec2 k2 = vec2(r2-r1,2.0*h);
 vec2 ca = vec2(q.x-min(q.x,(q.y<0.0)?r1:r2), abs(q.y)-h);
 vec2 cb = q - k1 + k2*clamp( dot(k1-q,k2)/dot2(k2), 0.0, 1.0 );
 float s = (cb.x<0.0 && ca.y<0.0) ? -1.0 : 1.0;
 return s*sqrt( min(dot2(ca),dot2(cb)) );
}

float sdSimpleCylinder(vec3 p, float r, float h){
   float d = length(p.xz)-r;
   d = max(abs(p.y)-h,d);
   return d;
}

// =========== 3D Model ===========

float baseOutsole(vec3 p, float h){
   vec3 prevP = p;

   p.xz*=Rot(radians(17.0));
   p.z*=0.4;
   p.x*=0.57;
   p.x+=0.03;
   p.z-=0.07;

   float d =sdSimpleCylinder(p,0.1,h);

   p = prevP;
   p.xy*=Rot(radians(90.0));
   p.y*=1.5;
   p.z*=1.2;
   float d2 = sdCappedCylinder(p-vec3(0.0,0.0,-0.25),h,0.2);
   d = opSmoothUnion(d, d2,0.13);

   p = prevP;
   d = max(abs(p.y)-h,d);

   return (d)*0.6;
}

float outsole(vec3 p){
   p.z*=0.9;
   vec3 prevP = p;

   float d = baseOutsole(p-vec3(0.0,0.02,0.),0.06);

   // wave traction pattern
   float scene = getSceneTime();
   if(scene<SCENE0){
       p.z+=scene*0.1;
   }
   p.z+=sin(p.x*80.0)*0.01;
   p.z = mod(p.z,0.09)-0.045;
   float d2 = sdBox(p,vec3(0.2,0.03,0.03));


   d = max(d,d2);
   p = prevP;
   d2 = baseOutsole(p-vec3(0.0,0.025,0.0),0.035);
   d = min(d,d2);

   p = prevP;
   float a  = radians(4.0);
   p.y-=0.06;
   float mask = dot(p.yz,vec2(cos(a),sin(a)));
   d = max(mask,d);

   p = prevP;
   a  = radians(-8.0);
   p.y+=0.07;
   mask = dot(p.yz,vec2(cos(a),sin(a)));
   d = max(-mask,d);

   p = prevP;
   a  = radians(10.0);
   p.y+=0.08;
   mask = dot(p.yz,vec2(cos(a),sin(a)));
   d = max(-mask,d);

   p = prevP;
   p.xz*=0.95;
   p.y+=sin(p.x*50.0)*0.01;
   d2 = baseOutsole(p-vec3(0.0,0.017,0.),0.002);
   d = min(d,d2);

   return d;
}

float upperBase(vec3 p){
   p.z*=0.9;
   vec3 prevP2 = p;
   p.z+=sin(p.x*300.0)*0.005;
   p.x+=cos(p.y*70.0)*0.005;
   vec3 prevP = p;

   //p.x*=1.;
   p.z*=0.8;

   float d =sdCappedCone(p-vec3(0.0,0.18,-0.15),0.13,0.15,0.06);

   p = prevP;
   p.xz*=Rot(radians(15.0));
   p.yz*=Rot(radians(-6.0));
   p.x*=1.2;
   p.z*=0.8;

   float d2 = sdEllipsoid(p-vec3(-0.05,0.1,0.14),vec3(0.2,0.08,0.2));
   d = opSmoothUnion(d,d2,0.1);//0.1

   p = prevP;
   p.xz*=Rot(radians(0.0));
   p.x*=1.1;
   p.z*=0.8;
   p.yz*=Rot(radians(-35.0));

   d2 = sdEllipsoid(p-vec3(0.0,0.21,-0.1),vec3(0.1,0.04,0.15));

   d = opSmoothUnion(d,d2,0.17);//0.15

   p = prevP2;
   p.xy*=Rot(radians(90.0));
   p.xz*=Rot(radians(18.0));
   p.y*=1.5;
   p.z*=1.0;
   d2 = sdCappedCylinder(p-vec3(-0.1,0.0,-0.2),0.001,0.2);
   d = opSmoothUnion(d, d2,0.07);

   p = prevP2;
   p.xy*=Rot(radians(90.0));
   p.xz*=Rot(radians(15.0));
   p.y*=1.3;
   p.z*=0.99;
   d2 = sdCappedCylinder(p-vec3(-0.04,0.0,-0.22),0.001,0.2);
   d = opSmoothUnion(d, d2,0.07);

   return d;
}

float upper(vec3 p){
   vec3 prevP = p;
   float d = upperBase(p);
   p.x*=1.5;
   p.y*=1.1;
   p.z*=1.12;

   float d2 = upperBase(p-vec3(0.0,0.02,0.0));
   d = max(-d2,d);

   p = prevP;

   p.x*=1.6;
   p.z*=0.7;

   d2 =sdCappedCone(p-vec3(-0.01,0.25,-0.1),0.14,0.14,0.09);
   d = max(-d2,d);

   p = prevP;
   float a  = radians(8.0);
   p.y-=0.31;
   float mask = dot(p.yz,vec2(cos(a),sin(a)));
   d = max(mask,d);

   p = prevP;
   p.yz*=Rot(radians(-15.0));
   p.x*=1.2;
   p.y*=1.1;
   p.z*=0.65;
   d2 = sdTorus(p-vec3(-0.005,0.31,-0.145),vec2(0.1,0.02));

   d = opSmoothUnion(d,d2,0.05);

   p = prevP;
   p.x*=1.4;
   p.z*=0.75;
   d2 =sdSimpleCylinder(p-vec3(-0.005,0.35,-0.115),0.1,0.2);
   d = max(-d2,d);

   return d*0.8;
}

vec2 GetDist(vec3 p) {
   //p+=noise3d(p*600.0)*0.0002;
   vec3 prevP = p;

   p.y+=0.125;

   float d = outsole(p);
   float d2 = upper(p-vec3(0.0,0.0,0.0));

   vec2 model = vec2(d2,MATERIAL_UPPER);
   vec2 model2 = vec2(d,MATERIAL_OUTSOLE);

   float scene = getSceneTime();
   if(scene>=SCENE3){
       p.xz*=Rot(radians(iTime*50.0));
       d = sdTorus(p,vec2(0.45,0.005));
       d = max(-(abs(p.x)-0.455),d);

       p = prevP;
       p.y+=0.125;
       p.xy*=Rot(radians((iTime*-50.0)));
       p.yz*=Rot(radians(90.0));
       d2 = sdTorus(p,vec2(0.45,0.005));
       d2 = max(-(abs(p.x)-0.455),d2);

       vec2 model3 = vec2(min(d,d2),MATERIAL_EFFECT);
       return combine(smoothCombine(model,model2,0.03),model3);
   }
   return smoothCombine(model,model2,0.03);
}

vec2 RayMarch(vec3 ro, vec3 rd, float side) {
   vec2 dO = vec2(0.0);

   for(int i=0; i<MAX_STEPS; i++) {
       vec3 p = ro + rd*dO.x;
       vec2 dS = GetDist(p);
       dO.x += dS.x*side;
       dO.y = dS.y;

       if(dO.x>MAX_DIST || abs(dS.x)<SURF_DIST) break;
   }

   return dO;
}

vec3 GetNormal(vec3 p) {
   float d = GetDist(p).x;
   vec2 e = vec2(.001, 0);

   vec3 n = d - vec3(
       GetDist(p-e.xyy).x,
       GetDist(p-e.yxy).x,
       GetDist(p-e.yyx).x);

   return normalize(n);
}

vec3 R(vec2 uv, vec3 p, vec3 l, float z) {
   vec3 f = normalize(l-p),
       r = normalize(cross(vec3(0,1,0), f)),
       u = cross(f,r),
       c = p+f*z,
       i = c + uv.x*r + uv.y*u,
       d = normalize(i-p);
   return d;
}

// https://www.shadertoy.com/view/3lsSzf
float calcOcclusion( in vec3 pos, in vec3 nor )
{
   float occ = 0.0;
   float sca = 1.0;
   for( int i=0; i<3; i++ )
   {
       float h = 0.01 + 0.15*float(i)/4.0;
       vec3 opos = pos + h*nor;
       float d = GetDist( opos ).x;
       occ += (h-d)*sca;
       sca *= 0.95;
   }
   return clamp( 1.0 - 2.0*occ, 0.0, 1.0 );
}

vec3 diffuseMaterial(vec3 n, vec3 rd, vec3 p, vec3 col) {
   float occ = calcOcclusion(p,n);
   vec3 diffCol = vec3(0.0);
   vec3 lightDir = normalize(vec3(1,2,-2));
   float diff = clamp(dot(n,lightDir),0.0,1.0);
   float skyDiff = clamp(0.5+0.5*dot(n,vec3(0,1,0)),0.0,1.0);
   float bounceDiff = clamp(0.5+0.5*dot(n,vec3(0,-1,0)),0.0,1.0);
   diffCol = col*vec3(-0.1)*diff*occ;
   diffCol += col*vec3(1.0,0.95,1.0)*skyDiff*occ;
   diffCol += col*vec3(1.0,0.9,0.85)*bounceDiff*occ;
   diffCol += col*pow(max(dot(rd, reflect(lightDir, n)), 0.0), 20.)*occ; // spec

   return diffCol;
}

vec3 evaTex(vec2 uv, vec3 col){
   uv.y+=iTime*0.1;
   vec2 prevUV = uv;
   uv*=30.0;

   vec2 gv = fract(uv)-0.5;
   vec2 id = floor(uv);

   float n = Hash21(id);
   gv.y*=n;

   gv.x+=cos(uv.y*5.0)*0.2+sin(uv.y*2.0)*0.05;
   float d = length(gv)-0.5*abs(n);
   if(n<0.5){
       col = mix(col,vec3(1.3),S(d,0.0));
   }

   return col;
}

vec3 upperTex(vec2 uv, vec3 col){
   vec2 prevUV = uv;
   uv.y*=0.3;
   uv.x*=1.5;
   uv.x+=cos(uv.y*100.0)*0.01+sin(uv.y*80.0)*0.02;
   float d = -uv.x+0.13;
   col = mix(col,vec3(1.5,1.4,1.4),S(d,0.0));

   return col;
}

vec3 materials(int mat, vec3 n, vec3 rd, vec3 p, vec3 col){
   if(mat == MATERIAL_UPPER){
       col = diffuseMaterial(n,rd,p,vec3(0.7,0.6,0.6)*evaTex(p.xz+p.yy,col)*upperTex(p.yz,col));
   }
    if(mat == MATERIAL_OUTSOLE){
       col = diffuseMaterial(n,rd,p,vec3(0.9));
   }
   if(mat == MATERIAL_EFFECT){
       col = diffuseMaterial(n,rd,p,vec3(1.2,1.2,1.2));
   }
   return col;
}

// =========== UI part ===========

// https://www.iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
float sdBox( in vec2 p, in vec2 b )
{
   vec2 d = abs(p)-b;
   return length(max(d,0.0)) + min(max(d.x,d.y),0.0);
}

// https://www.iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
float sdRoundedBox( in vec2 p, in vec2 b, in vec4 r )
{
   r.xy = (p.x>0.0)?r.xy : r.zw;
   r.x  = (p.y>0.0)?r.x  : r.y;
   vec2 q = abs(p)-b+r.x;
   return min(max(q.x,q.y),0.0) + length(max(q,0.0)) - r.x;
}

// https://www.iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
float sdPie( in vec2 p, in vec2 c, in float r )
{
   p.x = abs(p.x);
   float l = length(p) - r;
   float m = length(p-c*clamp(dot(p,c),0.0,r)); // c=sin/cos of aperture
   return max(l,m*sign(c.y*p.x-c.x*p.y));
}

float dTri(vec2 p, vec2 s){
   p*=-1.0;
   return Tri(p,s,radians(30.0));
}

float animationMask(vec2 p, float speed){
   float t = mod(iTime*speed,360.0);
   float rad = radians(t);
   float d = sdPie(p,vec2(sin(rad),cos(rad)),0.15);
   return d;
}

float charT(vec2 p, int animate, float speed) {
   vec2 prevP = p;
   float w = 0.03;
   float size = 0.1;
   float d = sdBox(p,vec2(size));

   float mask = sdBox(p-vec2(0.031,-0.031),vec2(0.071));
   d = max(-mask,d);

   p*=Rot(radians(45.0));
   p.x+=0.075;
   d = max(-p.x,d);

   p = prevP;
   p*=Rot(radians(45.0));
   d = max(p.x,d);

   p = prevP;
   if(animate == 1){
       mask = animationMask(p,speed);
       d = max(-mask,d);
   }
   return d;
}

float charD(vec2 p, int animate, float speed) {
   vec2 prevP = p;
   float w = 0.03;
   float size = 0.1;
   float d = sdRoundedBox(p,vec2(size),vec4(0.05,0.05,0,0));
   float d2 = sdRoundedBox(p,vec2(0.04,0.04),vec4(0.025,0.025,0,0));
   d = max(-d2,d);
   p*=Rot(radians(45.0));
   p.x+=0.04;
   d = max(-p.x,d);

   p = prevP;

   if(animate == 1){
       float mask = animationMask(p,speed);
       d = max(-mask,d);
   }

   return d;
}

float charF(vec2 p, int animate, float speed) {
   vec2 prevP = p;
   float size = 0.1;
   float d = sdBox(p,vec2(size));
   p*=Rot(radians(45.0));
   d = max(p.x,d);
   p = prevP;
   float mask = sdBox(p-vec2(0.06,0.025),vec2(0.1,0.015));
   d = max(-mask,d);

   if(animate == 1){
       mask = animationMask(p,speed);
       d = max(-mask,d);
   }
   return d;
}

float drawTDFLogo(vec2 p, int animate, float speed){
   float d = charT(p-vec2(-0.13,0.0),animate,speed);
   float d2 = charD(p-vec2(-0.05,0.0),animate,speed);
   d = min(d,d2);
   d2 = charF(p-vec2(0.17,0.0),animate,speed);

   return min(d,d2);
}

float drawTDFLogoPararell(vec2 p, int animate, float speed){
   float d = charT(p-vec2(-0.13,0.0),animate,speed);
   float d2 = charD(p-vec2(-0.05,0.0),animate,speed*0.5);
   d = min(d,d2);
   d2 = charF(p-vec2(0.17,0.0),animate,speed*0.75);

   return min(d,d2);
}

vec3 drawHUD(vec2 p, vec3 col){
   vec2 prevP = p;

   p*=Rot(radians(-iTime*10.0));
   p = DF(p,16.0);
   p = abs(p);
   p -= vec2(0.215);
   p*=Rot(radians(45.0));
   float d = B(p,vec2(0.001,0.005));
   col = mix(col,vec3(1.0),S(d,0.0));

   p = prevP;
   p*=Rot(radians(-iTime*10.0));
   p = DF(p,4.0);
   p = abs(p);
   p -= vec2(0.21);
   p*=Rot(radians(45.0));
   d = B(p,vec2(0.001,0.015));
   col = mix(col,vec3(1.0),S(d,0.0));

   p = prevP;
   p*=Rot(radians(iTime*20.0));
   d = abs(length(p)-0.32)-0.005;
   d = max(-B(p,vec2(1.0,0.2)),d);

   p = mod(p,0.005)-0.0025;
   d = max(-B(p,vec2(0.003)),d);

   col = mix(col,vec3(1.0),S(d,0.0));

   p = prevP;
   p*=Rot(radians(sin(iTime*1.0)*45.0));
   p = DF(p,1.0);
   p = abs(p);
   p -= vec2(0.24);
   p*=Rot(radians(45.0));
   d = dTri(p,vec2(0.015));
   col = mix(col,vec3(1.0),S(d,0.0));

   return col;
}

vec3 drawUI(vec2 p, vec3 col){
   vec2 prevP = p;

   p*=3.5;
   p = abs(p);
   p.x -=2.7;
   p.y -=1.3;
   p*=Rot(radians(-90.0));

   float d = drawTDFLogo(p,1,0.0);
   col = mix(col,vec3(1.0),S(d,0.0));
   p = prevP;
   p*=0.8;

   float scene = getSceneTime();
   if((scene>=SCENE0 && scene<SCENE1)||(scene>=SCENE2 && scene<SCENE3)){
       col = drawHUD(p,col);
   }
   return col;
}

vec3 startSceneBg(vec2 p, vec3 col){
   p = mod(p,0.2)-0.1;
   float d = B(p,vec2(0.00001,0.01));
   float d2 = B(p,vec2(0.01,0.00001));
   d = min(d,d2);
   col = mix(col,vec3(0.9,0.9,0.1)*0.5,S(d,0.0));

   return col;
}

vec3 endSceneBg(vec2 p, vec3 col){
   vec2 gv = fract(p)-0.5;
   vec2 id = floor(p);

   float n = Hash21(id);

   gv*=0.3;
   float d = charT(gv,1,100.0);
   if(n>=0.4 && n<0.7){
       d = charD(gv,1,120.0*n);
   } else if(n>=0.7){
       d = charF(gv,1,140.0*n);
   }

   col = mix(col,vec3(0.9,0.9,0.1),S(d,0.0));

   return col;
}

vec3 postEffect(vec2 p, vec3 col){
   p*=8.0;

   float y = fract(p.y)-0.5;
   vec2 gv = fract(p)-0.5;
   vec2 id = floor(p);
   float n = Hash21(id);

   p.y = y;

   float d = B(p,vec2(cos(iTime*n*20.0)*100.0*n*n,sin(iTime*n*20.0)*100.0*n*n));
   col = mix(col,vec3(0.9,0.9,0.1)*0.75,S(d,0.0));
   return col;
}

vec3 logoAnimationBg(vec2 p, vec3 col){
   float brightness = 0.2;
   vec2 prevP = p;
   p.x+=iTime*0.1;
   p.x = mod(p.x,0.54)-0.27;
   p.y = mod(p.y,0.45)-0.225;
   float d = drawTDFLogoPararell(p,1,100.0);
   col = mix(col,vec3(0.9,0.9,0.1)*brightness,S(d,0.0));
   p = prevP;
   p.x-=iTime*0.1;
   p.y+=0.225;
   p.x = mod(p.x,0.54)-0.27;
   p.y = mod(p.y,0.45)-0.225;
   d = drawTDFLogoPararell(p,1,120.0);
   col = mix(col,vec3(0.9,0.9,0.1)*brightness,S(d,0.0));

   return col;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
   vec2 uv = (fragCoord-.5*iResolution.xy)/iResolution.y;
   vec2 prevUV = uv;

   float scene = getSceneTime();

   if(scene>=SCENE1 && scene<SCENE2){
       uv.y+=scene*0.1;
       uv*=2.4;
       uv = fract(uv)-0.5;
   } else if(scene>=SCENE3){
       uv.y+=scene*0.1;
       uv*=1.4;
       uv.y = fract(uv.y)-0.5;
   }

   vec2 m = iMouse.xy/iResolution.xy -.3;

   float cz = 0.85;
   if(scene>=SCENE0 && scene<=SCENE1){
       cz = 1.;
   }  else if(scene>=SCENE1 && scene<=SCENE2){
       cz = 1.2;
   } else if(scene>=SCENE2){
       cz = 1.0;
   }

   vec3 ro = vec3(0, 0, cz);
   #if USE_MOUSE == 1
   ro.yz *= Rot(-m.y*3.14+1.);
   ro.xz *= Rot(-m.x*6.2831);
   #else
   if(scene<SCENE0){
       ro.yz *= Rot(radians(90.0));
       ro.xz *= Rot(radians(-90.0));
   } else {
       if(scene>=SCENE1 && scene<SCENE2){
           ro.yz *= Rot(radians(-35.0));
           ro.xz *= Rot(radians(-5.0+scene*20.0));
       } else if(scene>=SCENE2 && scene<SCENE3){
           ro.yz *= Rot(radians(30.0));
           ro.xz *= Rot(radians(-5.0+scene*20.0));
       } else if(scene>=SCENE3){

           ro.xz *= Rot(radians(-25.0+scene*20.0));
           ro.yz *= Rot(radians(85.0));

       } else {
           ro.xz *= Rot(radians(-5.0+scene*20.0));
       }

   }
   #endif

   vec3 rd = R(uv, ro, vec3(0,0.0,0), 1.0);
   vec2 d = RayMarch(ro, rd, 1.);
   vec3 col = vec3(1.0);

   if(d.x<MAX_DIST) {
       vec3 p = ro + rd * d.x;
       vec3 n = GetNormal(p);
       int mat = int(d.y);
       col = materials(mat,n,rd,p,col);
       //col *= exp( -0.038*d.x*d.x*d.x );//fog
   } else {
       //col = upperTex(uv,col);
       uv = prevUV;

       col = vec3(0.0);

       uv.y+=scene*0.1;
       uv*=0.5;

       if(scene<SCENE0){
           uv = prevUV;
           uv.y+=scene*0.1;
           col = startSceneBg(uv,col);
       }

       if(scene>=SCENE0 && scene<SCENE1){
           uv.y = mod(uv.y,0.4)-0.2;
           float ld = drawTDFLogo(uv-vec2(0.0,0.08),0,0.0);
           col = mix(col,vec3(0.9,0.9,0.1)*0.25,S(ld,0.0));
           ld = drawTDFLogo(uv,0,0.0);
           col = mix(col,vec3(0.9,0.9,0.1)*0.5,S(ld,0.0));
           ld = drawTDFLogo(uv-vec2(0.0,-0.08),0,0.0);
           col = mix(col,vec3(0.9,0.9,0.1),S(ld,0.0));
       }

       uv = prevUV;
       if(scene>=SCENE2 && scene<SCENE3){
               uv.xy *= Rot(radians(sin(scene*.3)*20.0));
               float d2 = abs(uv.y);
               float k = 0.5 / d2;
               uv = uv * k + vec2(0, k);
               uv-=iTime*0.5;
               col = endSceneBg(uv,col);
               col*=d2*2.0;
       }

       if(scene>=SCENE3){
           col = logoAnimationBg(uv,col);
       }
   }

   // UI
   //float ld = drawTDFLogo(uv,1,60.0);
   if(scene<SCENE0){
       uv = prevUV;
       float ld = drawTDFLogo(uv,0,0.0);
       col = mix(col,vec3(0.9,0.9,0.1),S(ld,0.0));
   }

   // gamma correction
   col = pow( col, vec3(0.9545) );

   uv = prevUV;
   col = drawUI(uv,col);

   if(scene>=SCENE0-0.2 && scene<SCENE0+0.1){
       col = postEffect(uv,col);
   } else if(scene>=SCENE1-0.2 && scene<SCENE1+0.1){
       col = postEffect(uv,col);
   } else if(scene>=SCENE2-0.2 && scene<SCENE2+0.1){
       col = postEffect(uv,col);
   } else if(scene>=SCENE3-0.1 && scene<SCENE3+0.1){
       col = postEffect(uv,col);
   } else if(scene>SCENE_LENGTH-0.2 || scene<0.1){
       col = postEffect(uv,col);
   }

   fragColor = vec4(col,1.0);
}

void main(void)
{
   iMouse = vec4(mouse * resolution, 01., 10.);
   mainImage(gl_FragColor, gl_FragCoord.xy);
   gl_FragColor.a = 1.2;
}