uniform int pixh;
uniform int pixw;
uniform float frame_t;
float t;
uniform float seconds;
uniform float fader;
float x,y;
float pi = 3.1416;
vec4 gcolor;
float xpix,ypix;

void truth_shade_back() {
	float r = 0.1+0.1*sin((x+y)/80);
	gl_FragColor = vec4(r,r,r,0.0);
}

void truth_shade2() {
	float r = y/600.0;
	float g = x/800.0;
	float b = sin(t/100);
	gl_FragColor = 0.8*vec4 (r,g,b,0.0);
}

void truth_shade1() {
	float r = y/600.0;
	float g = x/800.0;
	float b = sin(t/100);
	gl_FragColor = vec4 (r,g,b,0.0);
}

void truth_main(void) {
	x = floor(gl_FragCoord.x);
	y = floor(gl_FragCoord.y);

	t *= 0.3;
	
	truth_shade_back();

	if ((mod(x*0.1*sin(t/100)-y*0.1*cos(t/100),32) < 12+sin(t/20)*5)&&(mod(y*cos(t/100)+x*sin(t/100),32) < 12+sin(t/20)*5)) {
		truth_shade1();
	}
	else if ((mod(x+t-4,32) < 4)||(mod(y+t/2-4,32) < 4))
		truth_shade2();
}


vec4 land_shade_back();

float land_distToPlane(vec3 pos) {
	return (pos.y*-1) + 5;
}

float land_distToBall(float x, float y, float z) {
	vec3 center = vec3(sin(t/100),cos(t/80),5.0);
	vec3 cam = vec3(x,y,z);
	float r = 4.0;
	return length(center-cam) - r + 0.1*(sin(t/80))*sin(10*x+t/9) + 0.15*(sin(t/110))*cos(5*y+t/49);
}

float land_dist(vec3 cpos) {
	float d1 = land_distToBall(cpos.x, cpos.y, cpos.z);
	return d1;
}

float land_dist2(vec3 cpos) {
	float d2 = land_distToPlane(cpos);
	return d2;
}
vec3 land_calc_norm(vec3 sect) {
	vec3 n = vec3(0.0,0.0,0.0);
	float dx = 0.1;
	n.x = land_dist(sect) - land_dist(sect + vec3(dx,0.0,0.0));
	n.y = land_dist(sect) - land_dist(sect + vec3(0.0,dx,0.0));
	n.z = land_dist(sect) - land_dist(sect + vec3(0.0,0.0,dx));
	return n;
}

vec3 land_calc_norm2(vec3 sect) {
	vec3 n = vec3(0.0,0.0,0.0);
	float dx = 0.1;
	n.x = land_dist(sect) - land_dist2(sect + vec3(dx,0.0,0.0));
	n.y = land_dist(sect) - land_dist2(sect + vec3(0.0,dx,0.0));
	n.z = land_dist(sect) - land_dist2(sect + vec3(0.0,0.0,dx));
	return n;
}

void land_shade(vec3 sect, float iter) {
	vec3 light = vec3(6.0,12.0,22.0);
	vec3 norm = land_calc_norm(sect);
	float diff = dot(normalize(light-sect), normalize(norm));
	diff = clamp(diff,0.0,1.0);
	vec4 color = vec4 (1.0,0.3,abs(sin(t/1000)),0.0);
	gcolor = diff * color;
}

void land_shade2(vec3 sect, float iter) {
	vec3 light = vec3(6.0,12.0,22.0);
	vec3 norm = land_calc_norm2(sect);
	float diff = dot(normalize(light-sect), normalize(norm));
	diff = clamp(diff,0.0,1.0);
	vec4 color = vec4 (0.5,0.3,0.0,0.0);
	gcolor = diff * color;
}

void land_raymarch(vec3 pos, vec3 dir) {
	float iter = 0;
	while (length(pos)<200) {
		float d = land_dist(pos);
		if (d<0.001) {
			land_shade(pos, iter);
			break;
		}
		pos += d*dir;
		iter++;
	}
}			

void land_raymarch2(vec3 pos, vec3 dir) {
	float iter = 0;
	while (length(pos)<200) {
		float d = land_dist2(pos);
		if (d<0.001) {
			land_shade2(pos, iter);
			break;
		}
		pos += d*dir;
		iter++;
	}
}			

vec4 land_shade_back() {
	float x = floor(gl_FragCoord.x);
	float y = floor(gl_FragCoord.y);
	float m = mod(x/8+t/22, 4);
	float n = mod(y/8+t/16, 4);
	if ((m < 2)&&(n<2))
		m = 0.2;
	else
		m = 0.3;
	return m * vec4 (x/pixw,0.0,y/pixh,1.0);
}

void land_main(void) {
	gcolor = land_shade_back();
	vec3 cpos = vec3(0.0,0.0,0.0);
	vec3 offset = vec3((pixw/2)-gl_FragCoord.x, (pixh/2)-gl_FragCoord.y, 0.0);
	offset = 0.01*offset;
	vec3 angle = offset+vec3(0.0,0.0,1.0);
	//land_raymarch2(cpos, normalize(angle));
	land_raymarch(cpos, normalize(angle));

	gl_FragColor = fader * gcolor;
}


void wheels_shade_back() {
	float b = clamp((x+y)/1600,0.0,0.2);
	gl_FragColor = vec4(0.6+b,0.6+b,0.7,0.0);
}

void wheels_shade_wheel(float a) {
	gl_FragColor = a*vec4(a,1.0,0.7,0.0);
}

void wheels_shade_rim() {
	gl_FragColor = vec4(0.0,0.0,0.0,0.0);
}


void wheels_main(void) {
	x = floor(gl_FragCoord.x) - pixw/2;
	y = floor(gl_FragCoord.y) - pixh/2;
	t *= 0.4;
	wheels_shade_back();

	if ((x == floor(100*cos(pi/6)))&&(y == floor(100*sin(pi/6))))
		wheels_shade_rim();
	
	for (int j=0; j<6; j++) {
		for (int i=0; i<12; i++) {
			float ro = 50+(j*50)*sin(t/100);
			float xo = ro*cos(i*(t/(100))*pi/6);
			float yo = ro*sin(i*(t/(100))*pi/6);
			float r = 20.0+10*sin(t/100);
			if (length(vec2(x-xo,y-yo)) < r)
				wheels_shade_wheel(0.8+0.2*abs(sin(t/100)));
			if ((length(vec2(x-xo,y-yo)) >= r)&&(length(vec2(x-xo,y-yo)) <= r+3))
				wheels_shade_rim();
		}
	}


}

vec4 snake_raymarch(vec3 pos, vec3 dir, bool reflect);

float snake_distToSnake(vec3 p) {
	vec3 center = vec3(-3.0+sin(t/20),3.0,0.0);
	return length(center.xy - p.xy + vec2(sin(p.z+ t/20),0)) - 1;
}

float snake_distToPlane(vec3 p) {
	return -p.y + 5;
}

float snake_dist(vec3 cpos) {
	float d1 = snake_distToSnake(cpos);
	float d2 = snake_distToPlane(cpos);
	return min(d1,d2);
}

vec3 snake_calc_norm(vec3 sect) {
	vec3 n = vec3(0.0,0.0,0.0);
	float dx = 0.1;
	n.x = snake_dist(sect) - snake_dist(sect + vec3(dx,0.0,0.0));
	n.y = snake_dist(sect) - snake_dist(sect + vec3(0.0,dx,0.0));
	n.z = snake_dist(sect) - snake_dist(sect + vec3(0.0,0.0,dx));
	return n;
}

vec4 snake_shade(vec3 sect, float iter, bool reflect) {
	vec3 light = vec3(-6.0,18.0,15.0);
	vec3 norm = snake_calc_norm(sect);
	float diff = dot(normalize(light-sect), normalize(norm));
	diff = clamp(diff,0.0,1.0);
	float bl = 1-clamp(sect.y/5,0,1);
	vec4 color = vec4 (1.0,0.3,bl,0.0);
	if ((bl<=0.1)&&((mod(sect.x+t/100,2)<1)))
		color *= 0.8;
	vec3 refray = sect - 2*dot(sect,norm)*norm;
	return diff * color;
}

vec4 snake_shade_back() {
	return vec4(0.0,0.0,0.0,0.0);
}

vec4 snake_raymarch(vec3 pos, vec3 dir, bool reflect) {
	float iter = 0;
	while (length(pos)<200) {
		float d = snake_dist(pos);
		if (d<0.001) {
			return snake_shade(pos, iter, reflect);
		}
		pos += d*dir;
		iter++;
	}
	return snake_shade_back();
}

void snake_main(void) {
	xpix = gl_FragCoord.x;
	ypix = gl_FragCoord.y;
	//gcolor = snake_shade_back();
	vec3 cpos = vec3(0.0,0.0,0.0);
	vec3 offset = vec3((pixw/2)-gl_FragCoord.x, (pixh/2)-gl_FragCoord.y, 0.0);
	offset = 0.01*offset;
	vec3 angle = offset+vec3(0.0,0.0,1.0);
	
	gl_FragColor = fader * snake_raymarch(cpos, normalize(angle), true);
}


float bulbs_dist(vec3 pos) {
	vec3 center = vec3(50.0,50.0,50.0);
	pos = center-pos;
	float m = clamp(-cos(t/800), 0, 1);
	pos.x = mix(pos.x,floor(pos.x),m);
	pos.y = mix(pos.y,floor(pos.y),m);
	pos.z += +sin(cos(t/10)+t/20);

	float theta = t/30+floor(pos.z/100);
	float yy = pos.y;
	pos.y = pos.y*cos(theta) - pos.x*sin(theta);
	pos.x = pos.x*cos(theta) + yy*sin(theta);
	float l = length(vec2(length(pos.xy) - 5.0+2*sin(t/130), mod(pos.z,100))) - 3.0;
	l+=sin(5*sin(t/20+floor(pos.z/100))+pos.x);
	l+=1+sin(t/100)*sin(pos.y);
	return l;
}

vec3 bulbs_calc_norm(vec3 sect) {
	vec3 n = vec3(0.0,0.0,0.0);
	float dx = 0.01;
	n.x = bulbs_dist(sect) - bulbs_dist(sect + vec3(dx,0.0,0.0));
	n.y = bulbs_dist(sect) - bulbs_dist(sect + vec3(0.0,dx,0.0));
	n.z = bulbs_dist(sect) - bulbs_dist(sect + vec3(0.0,0.0,dx));
	return n;
}

void bulbs_shade(vec3 sect, float iter, vec3 ipos) {
	vec3 light = vec3(50.0,3.0,200.0+t);
	vec3 norm = bulbs_calc_norm(sect);
	float diff = dot(normalize(light-sect), normalize(norm));
	//diff = clamp(diff*1.5,0.0,1.0);
	float ao = clamp(exp(-iter * 0.05), 0, 1);
	vec4 color = vec4(sect.z/1000,0.5+sect.z/10000,0.8,0.0);
	gcolor = mix(ao,diff,0.99) * color;
}

void bulbs_raymarch(vec3 pos, vec3 dir) {
	vec3 ipos = pos;
	float iter = 0;
	while (length(pos-ipos)<200) {
		float d = bulbs_dist(pos);
		if (d<0.01) {
			bulbs_shade(pos, iter, ipos);
			break;
		}
		pos += d*dir;
		iter++;
	}
}

vec4 bulbs_shade_back() {
	return 0.4*vec4(0.0,0.0,cos(xpix/20)-sin(t/100),0.0);
}

void bulbs_main(void) {
	t *= 1.1;
	xpix = gl_FragCoord.x;
	ypix = gl_FragCoord.y;
	gcolor = bulbs_shade_back();
	vec3 cpos = vec3(50.0,50.0,t);
	vec3 offset = vec3((pixw/2)-gl_FragCoord.x, (pixh/2)-gl_FragCoord.y, 0.0);
	offset = 0.001*offset;
	vec3 angle = offset+vec3(0.0,0.0,1.0);
	bulbs_raymarch(cpos, normalize(angle));

	gl_FragColor = fader * gcolor;
}
float tilenoise(float x, float y) {
	return sin(y*x*cos(x+y*100)+100*cos(y)+100*cos(y)*sin(x));
}

vec2 grad(float n) {
	float angle = (n+t/100)*2*pi;
	vec2 gr = vec2(cos(angle),sin(angle));
	return normalize(gr);
}

float gtilenoise(float x, float z) {
	vec2 p = vec2(x,z);
	vec2 c1 = vec2(floor(x), floor(z));
	vec2 c2 = vec2(floor(x)+1, floor(z));
	vec2 c3 = vec2(floor(x)+1, floor(z)+1);
	vec2 c4 = vec2(floor(x), floor(z)+1);
	vec2 r1 = grad(tilenoise(c1.x,c1.y));
	vec2 r2 = grad(tilenoise(c2.x,c2.y));
	vec2 r3 = grad(tilenoise(c3.x,c3.y));
	vec2 r4 = grad(tilenoise(c4.x,c4.y));
	float n1 = dot(r1, normalize(p-c1));
	float n2 = dot(r2, normalize(p-c2));
	float n3 = dot(r3, normalize(p-c3));
	float n4 = dot(r4, normalize(p-c4));
	return (n1+n2+n3+n4)/4;
}

float tile_distToPlane(vec3 p) {
	return -p.y + 5;
}

float tile_dist(vec3 cpos) {
	float d1 = tile_distToPlane(cpos);
	return 5.0;
}

vec3 tile_calc_norm(vec3 sect) {
	vec3 n = vec3(0.0,0.0,0.0);
	float dx = 0.1;
	n.x = tile_dist(sect) - tile_dist(sect + vec3(dx,0.0,0.0));
	n.y = tile_dist(sect) - tile_dist(sect + vec3(0.0,dx,0.0));
	n.z = tile_dist(sect) - tile_dist(sect + vec3(0.0,0.0,dx));
	return n;
}

void tile_shade(vec3 sect, float iter) {
	vec3 light = vec3(-6.0,18.0,15.0);
	vec3 norm = tile_calc_norm(sect);
	float diff = dot(normalize(light-sect), normalize(norm));
	diff = clamp(diff,0.0,1.0);
	vec4 color = vec4 (1.0,0.3,0.0,0.0);
	gcolor = diff * color;
}

vec4 tile_shade_back() {
	return gtilenoise((xpix+t)/50,(ypix+t/2)/50)*vec4(0.0,1.0,1.0,1.0);
}

void tile_raymarch(vec3 pos, vec3 dir) {
	float iter = 0;
	while (length(pos)<200) {
		float d = tile_dist(pos);
		if (d<0.001) {
			tile_shade(pos, iter);
			break;
		}
		pos += d*dir;
		iter++;
	}
}

void tile_main(void) {
	t *= 0.1;
	xpix = gl_FragCoord.x;
	ypix = gl_FragCoord.y;
	gcolor = tile_shade_back();
	vec3 cpos = vec3(0.0,0.0,0.0);
	vec3 offset = vec3((pixw/2)-gl_FragCoord.x, (pixh/2)-gl_FragCoord.y, 0.0);
	offset = 0.01*offset;
	vec3 angle = offset+vec3(0.0,0.0,1.0);
	tile_raymarch(cpos, normalize(vec3(gl_FragCoord.x,gl_FragCoord.y,1.0)));

	gl_FragColor = fader * gcolor;
}


float nnoise(float x, float y) {
	return sin(y*x*cos(x+y*100)+100*cos(y)+100*cos(y)*sin(x));
	//vec2 co = vec2(x,y);
	//return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

vec2 ngrad(float n) {
	float angle = n*2*pi;
	vec2 gr = vec2(cos(angle),sin(angle));
	return normalize(gr);
}

float fade(float t) {
  return t*t*t*(t*(t*6.0-15.0)+10.0);
}


float gnnoise(float x, float z) {
	vec2 p = vec2(x,z);
	vec2 pf = fract(p);
	vec2 pn = floor(p);
	vec2 r1 = ngrad(nnoise(pn.x,pn.y));
	vec2 r2 = ngrad(nnoise(pn.x,pn.y+1));
	vec2 r3 = ngrad(nnoise(pn.x+1,pn.y));
	vec2 r4 = ngrad(nnoise(pn.x+1,pn.y+1));
	float n1 = dot(r1, pf);
	float n2 = dot(r2, pf-vec2(0.0,1.0));
	float n3 = dot(r3, pf-vec2(1.0,0.0));
	float n4 = dot(r4, pf-vec2(1.0,1.0));

	vec2 n_x = mix(vec2(n1, n2), vec2(n3, n4), fade(pf.x));
	float n_xy = mix(n_x.x, n_x.y, fade(pf.y));
		
	return n_xy*0.5+0.5;
}

float fbm(float x, float z) {
	float m = 0;
	for (int i=1; i<8; i++) {
		float j = pow(2,i);
		m += pow(0.5,i) * gnnoise(j*x,j*z);
	}
	return m;
}


float n_distToPlane(vec3 p) {
	p.y = floor(p.y/3);
	return -p.y + 100 - 95*sin(fbm((p.x+2100)/211,p.z/211)*t/120);
}

float n_dist(vec3 cpos) {
	float d1 = n_distToPlane(cpos);
	return d1;
}

vec3 n_calc_norm(vec3 sect) {
	vec3 n = vec3(0.0,0.0,0.0);
	float dx = 0.01;
	n.x = n_dist(sect) - n_dist(sect + vec3(dx,0.0,0.0));
	n.y = n_dist(sect) - n_dist(sect + vec3(0.0,dx,0.0));
	n.z = n_dist(sect) - n_dist(sect + vec3(0.0,0.0,dx));
	return n;
}

void n_shade(vec3 sect, float iter, vec3 ipos) {
	vec3 light = vec3(0.0,900.0,0.0);
	vec3 norm = n_calc_norm(sect);
	float diff = dot(normalize(light-sect), normalize(norm));
	diff = clamp(diff*1.5,0.0,1.0);
	diff = mix(diff, 1 - (sect.z - ipos.z)/200, 0.5);
	diff = 1.0;
	vec4 color;
	//float sh = fbm(sect.x/4, sect.z/4);
	float sh = 1.0;
	color = sh*vec4 (0.8,0.4,0.0,0.0);
	float b = 0.004;
	float fog = 1-exp(-length(sect-ipos)*b);
	vec4 fogc = vec4(0.5,0.6,0.7,1.0);
	float ao = clamp(exp(-iter * 0.05), 0, 1);
	gcolor = mix(diff * ao * color, fogc, fog);
}

vec4 n_shade_back() {
	return (fbm((xpix+t/20)/200,ypix/200)+0.5)*vec4(0.5,0.6,0.7,1.0)*clamp((pixh-ypix)/300,0,1);
}

void n_raymarch(vec3 pos, vec3 dir) {
	vec3 ipos = pos;
	float iter = 0;
	while (length(pos-ipos)<500) {
		float d = n_dist(pos);
		if (d<0.5) {
			n_shade(pos, iter, ipos);
			break;
		}
		pos += d*dir/2;
		iter++;
	}
}

void n_main(void) {
	t *= 0.3;
	xpix = gl_FragCoord.x;
	ypix = gl_FragCoord.y;
	gcolor = n_shade_back();
	vec3 cpos = vec3(0.0,0.0,t);
	vec3 offset = vec3((pixw/2)-gl_FragCoord.x, (pixh/2)-gl_FragCoord.y, 0.0);
	offset = 0.01*offset;
	vec3 angle = offset+vec3(0.0,0.0,3.0);
	n_raymarch(cpos, normalize(angle));

	gl_FragColor = fader * gcolor;
}

void duck_shade_back(float x, float y) {
	float b = clamp((x+y)/1600,0.0,0.2);
	gl_FragColor = vec4(0.4+b,0.6+b,0.8+b,0.0);
}

void duck_shade_wheel(float a) {
	gl_FragColor = a*vec4(a,1.0,0.7,0.0);
}

void duck_shade_duck(float x,float y) {
	gl_FragColor = mix( vec4(1.0,0.9,0.5,0.0), vec4(1.0,1.0,1.0,0.0),  vec4((400-x)/1200) );
}

void duck_shade_water() {
	gl_FragColor -= vec4(0.5,0.5,0.0,0.0);
}


void duck_main(void) {
	x = floor(gl_FragCoord.x) - pixw/2;
	y = floor(gl_FragCoord.y) - pixh/2;

	t *= 1.8;
	float fixedx = x;
	float fixedy = y;
	
	x -= t*0.2 - 500;
	y += 10*sin(t*0.03);
	
	duck_shade_back(fixedx,fixedy);

	if ((x == floor(100*cos(pi/6)))&&(y == floor(100*sin(pi/6))))
		duck_shade_duck(x,y);
	
	if(y>0) { y = pow(y,0.9); x*=(1-(y)*0.003); }
	if(y>0 && y < 50 && x > 0) { x *= (0.70 + 0.008*(y - 15)); }
	

	float angle = atan(-y,x);
	float radius = length(vec2(x,y));
	if(radius < 40*(angle+3.4))  duck_shade_duck(x,y);
	
	if(fixedy < -60-20*abs(sin(fixedx*0.08)) ) {
		duck_shade_water();
	}
	
}


void main() {
	float seclength = 7.771429;
	t = frame_t;
	if(seconds < 2*seclength)
		n_main();
	else if(seconds < 4*seclength)
		bulbs_main();
	else if(seconds < 6*seclength)
		snake_main();
	else if(seconds < 8*seclength)
		wheels_main();
	else if(seconds < 9*seclength)
		land_main();
	else if(seconds < 10*seclength)
		truth_main();
	else if(seconds < 12*seclength)
		duck_main();
	else if(seconds < 13*seclength)
		tile_main();
	else if(seconds < 14*seclength)
		truth_main();
}