uniform vec2 iResolution;
uniform float iTime;
out vec4 fragColor;

//#define DUR (5.323173125 / 4.0) // duration
//#define DUR 0.8571428571428571 // duration
//#define DUR 0.7058823529411765
#define DUR (60. / 155. * 2. + 0.00045) // 155bpm
//#define DUR 0.6733675

// noise: thanks to morgan3d
// https://www.shadertoy.com/view/4dS3Wd
float hash(float n) { return fract(sin(n) * 1e4); }
float hash(vec2 p) { return fract(1e4 * sin(17.0 * p.x + p.y * 0.1) * (0.1 + abs(sin(p.y * 13.0 + p.x)))); }
float noise(float x) {
	float i = floor(x);
	float f = fract(x);
	float u = f * f * (3 - f*2);
	return mix(hash(i), hash(i + 1), u);
}
float noise(vec2 x) {
	vec2 i = floor(x);
	vec2 f = fract(x);
	float a = hash(i);
	float b = hash(i + vec2(1.0, 0.0));
	float c = hash(i + vec2(0.0, 1.0));
	float d = hash(i + vec2(1.0, 1.0));
	vec2 u = f * f * (3.0 - 2.0 * f);
	return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}
float noise(vec3 x) {
	const vec3 step = vec3(110, 241, 171);
	vec3 i = floor(x);
	vec3 f = fract(x);
	float n = dot(i, step);
	vec3 u = f * f * (3.0 - 2.0 * f);
	return mix(mix(mix( hash(n + dot(step, vec3(0, 0, 0))), hash(n + dot(step, vec3(1, 0, 0))), u.x),
					mix( hash(n + dot(step, vec3(0, 1, 0))), hash(n + dot(step, vec3(1, 1, 0))), u.x), u.y),
				mix(mix( hash(n + dot(step, vec3(0, 0, 1))), hash(n + dot(step, vec3(1, 0, 1))), u.x),
					mix( hash(n + dot(step, vec3(0, 1, 1))), hash(n + dot(step, vec3(1, 1, 1))), u.x), u.y), u.z);
}

// sphere density: thanks to iq
// http://www.iquilezles.org/www/articles/spheredensity/spheredensity.htm
float computeFog(vec3 rayOrigin, vec3 rayDirection, vec3 sphereCenter, float sphereRadius, float dbuffer)
{
	float ndbuffer = dbuffer / sphereRadius;
	vec3 rc = (rayOrigin - sphereCenter) / sphereRadius;
	float b = dot(rayDirection,rc);
	float c = dot(rc,rc) - 1.;
	float h = b * b - c;
	if(h<0.) return 0.;
	h = sqrt(h);
	float t1 = -b - h;
	float t2 = -b + h;
	if( t2 < 0.0f || t1 > ndbuffer ) return 0.;
	t1 = max(t1, 0.);
	t2 = min(t2, ndbuffer);
	float i1 = -(c*t1 + b*t1*t1 + t1*t1*t1/3.);
	float i2 = -(c*t2 + b*t2*t2 + t2*t2*t2/3.);
	return (i2 - i1) * (3./4.);
}

// returns a polygon distance field with x sides
float poly(vec2 uv, float sides)
{
	float m = (step(0., uv.x) * 2.) - 1.;
	float a = atan(uv.x, uv.y) + PI * m;
	float r = TAU / sides;
	return cos(floor(.5 + a / r) * r - a) * length(uv);
}

float rand(float x)
{
	return fract(sin(dot(x, 12.9898)) * 43758.5453123);
}

float lpsnow(vec2 uv, float n)
{
	n = floor(n * 10.);
	uv += rand(n * 1000.) * 10.;

	return 
		max(0., noise(floor(uv * 100.)) - 0.98) * 2. + 
		max(0., noise(floor(uv * 10.)) - 0.98) * 1.
		;
}

float grain(vec2 uv, float n)
{
	pR45(uv);
	return (0.5 - noise(uv * 10000. + rand(n) * 100000.)) * 0.05;
}

float letterbox(vec2 uv)
{
	return 1. -step(0.35, abs(uv.y));
}

float vignette(vec2 uv)
{
	float c = 0.;
	c -= smoothstep(0.5, 1.2, abs(uv.x));
	c -= smoothstep(0.2, 0.6, abs(uv.y));
	c *= 0.15;
	return 1. + c;
}

float ambience(vec2 uv, float n)
{
	return sin(n * 0.4) * 0.005;
}

vec3 origin_a(float n, vec3 off) {

	float i = mod(floor(n * 1.), 4.);
	float f = fract(n * 1.);

	// return -vec3(4., -20., -20.) * 3.0;

	if(i == 0.) {
		return vec3(f * 10., 10., 20.) * (1.1 + n * 0.03);
	}
	else if(i == 1) {
		return -vec3(4., -f * 40, f * 10. + 10.);
	}
	else if(i == 2) {
		return vec3(0., 0., 40.);
	}
	else if(i == 3) {
		return vec3(0., 0., 80. + n * 0.1);
	}
	
}

vec3 origin_b(float n, vec3 off)
{
	float i = mod(floor(n * 0.5), 4.);
	float f = fract(n * 0.5);

	if(i == 0.)
	{
		return vec3(0., 0., 30.);
	}
	else if(i == 1.)
	{
		return vec3(5., 9., 0.);
	}
	else if(i == 2.)
	{
		vec3 p = vec3(-0., 6.6, 0.8) + off;
		pR(p.xz, -(n + 1.53) * 6.);
		
		// p.y -= 4. - min(n * 0.3, 15.5);
		p.y -= 13.45 - min(n * 0.3, 15.5);
		return p;
	}
	else if(i == 3.)
	{
		vec3 p = vec3(28., 35., -16.) * 0.7;
		pR(p.xz, -sin(f));
		return p;
	}
}

vec3 origin_c(float n, vec3 off)
{
	float i = mod(floor(n * 0.5), 4.);
	float f = fract(n * 0.5);

	// return vec3(5., 9., 0.);
	return vec3(-10. + f * 20., 4., 10. - f * 10);
}

vec3 origin_d(float n, vec3 off)
{
	float i = mod(floor(n * 0.5), 4.);
	float f = fract(n * 0.5);

	if(i == 0.)
	{
		return vec3(0., 0., 40.) + off;
	}
	else if(i == 1.)
	{
		return vec3(-80., 0., 0.) + off;
	}
	else if(i == 2.)
	{
		return vec3(-5., -5., 30.) + off;
	}
	else if(i == 3.)
	{
		if(n > 158.) {
			vec3 p = vec3(-10., 0., 0.) + off;
			pR(p.xy, n * 4.);
			pR(p.yz, -n * 8.);
			pR(p.yx, n * 2.);

			return p;
		}
		else {
			return vec3(0., 0., 40.) + off;
		}
	}
	// else if(i == 2.)
	// {
	// 	vec3 p = vec3(-0., 6.6, 0.8) + off;
	// 	pR(p.xz, -(n + 1.53) * 6.);
		
	// 	// p.y -= 4. - min(n * 0.3, 15.5);
	// 	p.y -= 13.45 - min(n * 0.3, 15.5);
	// 	return p;
	// }
	// else if(i == 3.)
	// {
	// 	vec3 p = vec3(28., 35., -16.) * 0.7;
	// 	pR(p.xz, -sin(f));
	// 	return p;
	// }

}

vec3 target_a(float n) {
	return vec3(0.);
}

vec3 target_b(float n)
{
	float i = mod(floor(n * 0.5), 4.);
	float f = fract(n * 0.5);

	if(i == 0.)
	{
		return vec3(0., 10., 0.);
	}
	else if(i == 1.)
	{
		return vec3(0., 10.35, -0.5);
	}
	else if(i == 2.)
	{
		vec3 off = vec3(-0.7, 0.8, -0.27);
		pR(off.yz, 0.19);
		pR(off.yx, 0.3);
		return origin_b(n, off);
	}
	else if(i == 3.)
	{
		return vec3(-1., 14., 8.);
	}
}

vec3 target_c(float n) {
	return vec3(0.);
}

vec3 target_d(float n) {
	return vec3(0.);
	// return origin_d(n, vec3(0., 0., -1.));
}

float epsilon_a(float n) {
	return 0.2;
}

float epsilon_b(float n) {
	return 0.1;
}

float epsilon_c(float n) {
	return 0.15;
}

float epsilon_d(float n) {
	return 0.25;
}

// death by drillbit
// three feet meatbeat
// meatbit

// doggo drill
// egg excavation
// penetration of peanut

// safety schranz
// kamarellschranzen
// allsång på schranzen

vec4 scene_a(vec3 p, float n)
{
	float eps = epsilon_a(n);
	vec3 c = vec3(0.);
	float r = 1. / 0.;


	if(n > 31.)
	{
		// ketchup
		vec3 ket_p = p;
		pR45(ket_p.zy);
		pR45(ket_p.zy);
		ket_p.x += sin(ket_p.y * 0.1 + n * PI * 2.) * 3. * (1. + (p.z + 50.) * 0.03);
		ket_p.z += cos(ket_p.y * 0.1 + n * PI * 2.) * 3. * (1. + (p.z + 50.) * 0.01);
		ket_p += noise(ket_p * 0.15) * 5.;
		ket_p.y += n * 120.;
		float ket_noise1 = noise(0.2 * ket_p + vec3(0., 0., 0.));
		float ket_noise2 = noise(1.5 * ket_p + vec3(0., 0., 0.));
		float ket = fCylinder(ket_p, 0.6, 1. / 0.);
		ket += ket_noise1 * 0.4 + ket_noise2 * 0.3;
		float ket_w = 1. - smoothstep(eps, eps + 0.1, ket);
		vec3 ket_c = vec3(0.41, 0.1, 0.1) * 0.8;
		c += ket_w * ket_c;
		r = min(r, ket);
	}

	pR45(p.xy);
	pR45(p.xy);
	pR(p.xy, n);

	

	pModPolar(p.xy, floor(n / 8. + 1.));
	p.x -= min(n, 8. + floor(n / 8. + 1.));
	
	if(n > 46.)
	{
		p.z += cos(n * 4. + 0.8) * 5.;
		// pasta
		vec3 pas_p = p;
		// pR45(pas_p.zx);
		pas_p.x += -14.;

		float rows = floor((n - 40.) / 32.);
		float cell = pModInterval1(pas_p.x, 15., 0., rows);
		pas_p.z += sin(cell) * 10.;

		pR(pas_p.xz, n * 4.);
		pR(pas_p.xy, pas_p.z * 0.8);
		float pas = fBox(pas_p, vec3(1.6, 0.4, 6.));
		// pas = p.z;
		float pas_w = 1. - smoothstep(eps, eps + 0.1, pas);
		vec3 pas_c = vec3(0.4, 0.4, 0.15);
		c += pas_w * pas_c;
		r = min(pas, r);
	}
	

	// meatball
	float ball_noise1 = noise(p * 1.3) * 1.1;
	float ball_noise2 = noise(p * 5.) * 0.15;
	float ball = fSphere(p + vec3(0., 0., 0), 5.5) + ball_noise1 - ball_noise2;
	// n *= 4.;
	// ball += 0.7 * (sin(n)+sin(n/0.5)*0.5+sin(n/0.333)*0.333+sin(n/0.25)*0.25+sin(n/0.2)*0.2);
	// ball += fract(n);
	ball += +4. - min(3., n*.4) + sin((fract((n*2)/-1)-1)/0.55) * 1.;
	float ball_w = 1. - smoothstep(eps, eps + 0.1, ball);
	vec3 ball_c = vec3(0.18, 0.11, 0.07);
	c += ball_w * ball_c;
	r = min(r, ball);

	return vec4(c, r);
}

// meatball mining
vec4 scene_b(vec3 p, float n)
{
	float eps = epsilon_b(n);
	vec3 c = vec3(0.);
	float r = 1. / 0.;

	// pMod1(p.x, 20.);
	// pR(p.xy, -0.15);
	// pR(p.xy, 0.005);
	// pR(p.xy, n);

	// fork
	vec3 fork_p = p + vec3(0., -15., -15.);
	fork_p.y += sin(p.z * 0.3 + 1.) * 0.5;
	// fork_p.x *= 1.2 + (sin(p.z * 0.15 + 6.) * 0.15);
	pR(fork_p.xz, 1.6);
	pR(fork_p.yx, 1.6);
	float fork_noise1 = noise(fork_p * 0.7);
	float fork = fCapsule(fork_p, 3.3, 10.);
	fork_p.x = abs(fork_p.x);
	fork_p.z = abs(fork_p.z);
	fork = max(fork, -fBox(fork_p + vec3(-2.55, 0., 0.), vec3(2.35, 15., 5.)));
	fork = max(fork, -fCapsule(fork_p + vec3(0., -5.7, -3.85), 3., 7.9));
	pMod1(fork_p.z, 2.);
	fork = max(fork, -fCapsule(fork_p + vec3(0., 11., 0.), 0.75, 4.));
	float fork_w = 1. - smoothstep(eps, eps + 0.1, fork);
	vec3 fork_c = vec3(0.5) + fork_noise1 * 0.15;
	c += fork_w * fork_c;
	r = min(r, fork);

	// meatball
	float ball_noise1 = noise(p * 1.3) * 1.1;
	float ball_noise2 = noise(p * 5.) * 0.15;
	float ball = fSphere(p + vec3(0., -15., 0), 5.5) + ball_noise1 - ball_noise2;
	float ball_w = 1. - smoothstep(eps, eps + 0.1, ball);
	vec3 ball_c = vec3(0.18, 0.11, 0.07);
	ball_c *= 0.9 - ball_noise2;
	c += ball_w * ball_c;
	r = min(r, ball);

	pR(p.xz, n * 6.);

	// drill
	p += noise(n) * 0.1;
	p += noise(n * 100.) * 0.05;
	p.y += 4. - min(n * 0.3, 15.5);
	float bit_len = 8.;
	float cyl = fCylinder(p, 1., bit_len);
	float tip = fCone(p + vec3(0., -bit_len, 0.), 1., 1.5);
	float bit = min(cyl, tip);
	pR(p.xz, p.y * 2.);
	bit = max(bit, -fCapsule(p + vec3(2.1, -2.5, 0.), 2., 5.));
	float bit_w = 1. - smoothstep(eps, eps + 0.1, bit);
	vec3 bit_c = vec3(0.5);
	c += bit_w * bit_c;

	r = max(r, -bit + 0.3 + noise(p * 1.)); // meatball excavation
	r = min(r, bit);

	return vec4(c, r);
}

vec4 scene_c(vec3 p, float n)
{
	float eps = epsilon_c(n);
	vec3 c = vec3(0.);
	float r = 1. / 0.;

	// p.z += cos(n * 4. + 0.8) * 5.;
	// pR(p.xz, n * 4.);
	pR(p.xy, p.z * 0.8);
	float pas = fBox(p, vec3(1.6, 0.4, 6.));
	float pas_w = 1. - smoothstep(eps, eps + 0.1, pas);
	vec3 pas_c = vec3(0.4, 0.4, 0.15);
	c += pas_w * pas_c;
	r = min(pas, r);


	return vec4(c, r);
}

vec4 scene_d(vec3 p, float n)
{
	float eps = epsilon_d(n);
	vec3 c = vec3(0.);
	float r = 1. / 0.;

	if(n > 158.)
	{
		vec3 pas_p = p;
		// pas_p.z += cos(n * 4. + 0.8) * 5.;
		pR(pas_p.yx, -n * 2.);
		pR(pas_p.yz, n * 8.);
		pR(pas_p.xy, -n * 4.);
		pR(pas_p.xy, pas_p.z * 0.8);
		float pas = fBox(pas_p, vec3(1.6, 0.4, 6.));
		float pas_w = 1. - smoothstep(eps, eps + 0.1, pas);
		vec3 pas_c = vec3(0.4, 0.4, 0.15);
		c += pas_w * pas_c;
		r = min(pas, r);
	}


	p.z -= n * 50;

	// if(n > 31.)
	{
		// ketchup
		vec3 ket_p = p;
		pR45(ket_p.zy);
		pR45(ket_p.zy);
		ket_p.x += sin(ket_p.y * 0.1 + n * PI * 2.) * 3. * (1. + (sin(p.z * 0.2)*8. + 50.) * 0.06);
		ket_p.z += cos(ket_p.y * 0.1 + n * PI * 2.) * 3. * (1. + (cos(p.z * 0.2)*8. + 50.) * 0.03);
		ket_p += noise(ket_p * 0.15) * 5.;
		ket_p.y += n * 120.;
		float ket_noise1 = noise(0.2 * ket_p + vec3(0., 0., 0.));
		float ket_noise2 = noise(1.5 * ket_p + vec3(0., 0., 0.));
		float ket = fCylinder(ket_p, 0.8, 1. / 0.);
		ket += ket_noise1 * 0.4 + ket_noise2 * 0.3;
		float ket_w = 1. - smoothstep(eps, eps + 0.1, ket);
		vec3 ket_c = vec3(0.41, 0.1, 0.1) * 0.8;
		c += ket_w * ket_c;
		r = min(r, ket);
	}

	pR45(p.xy);
	pR45(p.xy);
	pR(p.xy, sin(n * PI * 0.5 - 0.8) * 1.);

	pModPolar(p.xy, 16.);
	pMod1(p.z, 16.);
	// p.x -= min(n, 8. + floor(n / 8. + 1.));
	float startingDist = min(0., n - 128.6) * 40.;
	// float startingDist = -min(0., n - 128.3) * 400.;
	p.x -= sin(n * PI * 0.5 + 1.7) * 6. + 22. +startingDist;
	
	// if(n > 46.)
	// {
	// 	p.z += cos(n * 4. + 0.8) * 5.;
	// 	// pasta
	// 	vec3 pas_p = p;
	// 	// pR45(pas_p.zx);
	// 	pas_p.x += -14.;

	// 	float rows = floor((n - 40.) / 8.);
	// 	// float cell = pModInterval1(pas_p.x, 15., 0., rows);
	// 	// pas_p.z += sin(cell) * 10.;

	// 	pR(pas_p.xz, n * 4.);
	// 	pR(pas_p.xy, pas_p.z * 0.8);
	// 	float pas = fBox(pas_p, vec3(1.6, 0.4, 6.));
	// 	// pas = p.z;
	// 	float pas_w = 1. - smoothstep(eps, eps + 0.1, pas);
	// 	vec3 pas_c = vec3(0.4, 0.4, 0.15);
	// 	c += pas_w * pas_c;
	// 	r = min(pas, r);
	// }
	

	// meatball
	float ball_noise1 = noise(p * 1.3) * 1.1;
	float ball_noise2 = noise(p * 5.) * 0.15;
	float ball = fSphere(p + vec3(0., 0., 0), 5.5) + ball_noise1 - ball_noise2;
	// n *= 4.;
	// ball += 0.7 * (sin(n)+sin(n/0.5)*0.5+sin(n/0.333)*0.333+sin(n/0.25)*0.25+sin(n/0.2)*0.2);
	// ball += fract(n);
	ball += +4. - min(3., n*.4) + sin((fract((n*2)/-1)-1)/0.55) * 1.;
	float ball_w = 1. - smoothstep(eps, eps + 0.1, ball);
	vec3 ball_c = vec3(0.18, 0.11, 0.07);
	c += ball_w * ball_c;
	r = min(r, ball);

	return vec4(c, r);
}

void overlay_a(vec2 uv, inout vec3 c, float n)
{
	if(n < 16.)
	{
		float eo = 1. - step(0.5, fract((n * 0.5) + 0.5)) * 2.; // toggles between -1 and +1
		c += (max(0.8, fract(-n * 1. + 0.5)) - 0.8) * 0.2 * eo;
	}
	else
	{
		float eo = 1. - step(0.5, fract((n * 0.5) + 0.5)) * 2.; // toggles between -1 and +1
		c += (max(0.8, fract(-n * 2.)) - 0.8) * 0.2 * eo;
	}
}

void overlay_b(vec2 uv, inout vec3 c, float n)
{
	if(n < 16.)
	{
		float eo = 1. - step(0.5, fract((n * 0.5) + 0.5)) * 2.; // toggles between -1 and +1
		c += (max(0.8, fract(-n * 1. + 0.5)) - 0.8) * 0.2 * eo;
	}
	else
	{
		float eo = 1. - step(0.5, fract((n * 0.5) + 0.5)) * 2.; // toggles between -1 and +1
		c += (max(0.8, fract(-n * 2.)) - 0.8) * 0.2 * eo;
	}
}

void overlay_c(vec2 uv, inout vec3 c, float n)
{
	// float eo = 1. - step(0.5, fract((n * 0.5) + 0.5)) * 2.; // toggles between -1 and +1

	// c += (max(0.8, fract(-n * 2.)) - 0.8) * 0.2 * eo;
}

void overlay_d(vec2 uv, inout vec3 c, float n)
{
	float eo = 1. - step(0.5, fract((n * 0.5) + 0.5)) * 2.; // toggles between -1 and +1
	c += (max(0.8, fract(-n * 2.)) - 0.8) * 0.2 * eo;
}

float sceneId(float n)
{
	if(n > 179) { 
		return 9.;
	}
	if(n > 46 && n < 48) {
		return 2.;
	}
	else if(n > 128) {
		if(floor(mod(n / 5., 3.)) > 0.) {
			return 3.;
		}
		else {
			return 0.;
		}
	}

	return floor(mod(n / 5., 2.));
}

vec4 scene(vec3 p, float n)
{
	float id = sceneId(n);
	if(id == 0.) {
		return scene_a(p, n);
	}
	else if(id == 1.) {
		return scene_b(p, n);
	}
	else if(id == 2.) {
		return scene_c(p, n);
	}
	else if(id == 3.) {
		return scene_d(p, n);
	}
}

vec3 origin(float n, vec3 off)
{
	float id = sceneId(n);
	if(id == 0.) {
		return origin_a(n, off);
	}
	else if(id == 1.) {
		return origin_b(n, off);
	}
	else if(id == 2.) {
		return origin_c(n, off);
	}
	else if(id == 3.) {
		return origin_d(n, off);
	}
}
vec3 origin(float n) { return origin(n, vec3(0.)); }

vec3 target(float n)
{
	float id = sceneId(n);
	if(id == 0.) {
		return target_a(n);
	}
	else if(id == 1.) {
		return target_b(n);
	}
	else if(id == 2.) {
		return target_c(n);
	}
	else if(id == 3.) {
		return target_d(n);
	}
}

float epsilon(float n)
{
	float id = sceneId(n);
	if(id == 0.) {
		return epsilon_a(n);
	}
	else if(id == 1.) {
		return epsilon_b(n);
	}
	else if(id == 2.) {
		return epsilon_c(n);
	}
	else if(id == 3.) {
		return epsilon_d(n);
	}
}

void overlay(vec2 uv, inout vec3 c, float n)
{
	float id = sceneId(n);
	if(id == 0.) {
		overlay_a(uv, c, n);
	}
	else if(id == 1.) {
		overlay_b(uv, c, n);
	}
	else if(id == 2.) {
		overlay_c(uv, c, n);
	}
	else if(id == 3.) {
		overlay_d(uv, c, n);
	}
}

void main()
{
	float n = (iTime / DUR) - 0.15;

	const float MAX_DIST = 180.0;
	const int MAX_ITERATIONS = 30;
	float EPS = epsilon(n);

	vec2 uv = (gl_FragCoord.xy - (iResolution.xy * 0.5)) / iResolution.yy;
	uv *= 1. - (max(0.8, fract(-n * 2.)) - 0.8) * 0.4;

	if(n > 16.) {
		uv += (vec2(rand(n), rand(n + 1.0)) - 0.5) * 0.02; // shake
	}
	
	if(n > 102. && n < 104)
	{
		uv = floor(uv * 30) / 30;
	}
	
	if(n > 134. && n < 168.)
	{
		float dst = 50. - floor((n - 134) * 2.2);
		uv = floor(uv * dst) / dst;
		
		// uv *= 10.;
	}
	
	if(n > 156.)
	{
		uv = -uv;
		// c = 0.5 -c * 3.;
	}

	vec3 cameraOrigin = origin(n);
	vec3 cameraTarget = target(n);
	vec3 upDir = vec3(.0, 1.0, .0);
	vec3 cameraDir = normalize(cameraTarget - cameraOrigin);
	vec3 cameraRight = normalize(cross(upDir, cameraOrigin));
	vec3 cameraUp = cross(cameraDir, cameraRight);
	vec3 rayDir = normalize(cameraRight * uv.x + cameraUp * uv.y + cameraDir);
	float dist = EPS;
	float totalDist = 0.0;
	vec3 p = cameraOrigin;
	vec3 c = vec3(0.);

	for(int i = 0; i < MAX_ITERATIONS && dist >= EPS && totalDist < MAX_DIST; i++)
	{
		vec4 result = scene(p, n);
		c = result.rgb;
		dist = result.w;

		totalDist += dist;
		p += dist * rayDir;
	}

	vec3 bgc = vec3(0.15, 0.14, 0.16) * 0.57;

	if(dist < EPS)
	{
		vec2 eps = vec2(0.0, EPS);
		vec3 normal = normalize(vec3(
			scene(p + eps.yxx, n).a - scene(p - eps.yxx, n).a,
			scene(p + eps.xyx, n).a - scene(p - eps.xyx, n).a,
			scene(p + eps.xxy, n).a - scene(p - eps.xxy, n).a));

		// vec3 lightOffset = vec3(0., 0.05, 0.4);
		vec3 lightOffset = vec3(0.);
		float diffuse = max(.11, dot(-normalize(rayDir + lightOffset), normal));
		float specular = pow(diffuse, 40.);
		c *= diffuse + specular;
	}
	else
	{
		c = bgc;
	}

	c = mix(c, bgc, pow(totalDist / MAX_DIST, 3.)); // distance fog

	// c = vec3(1.);

	overlay(uv, c, n);
	
	
	if(n > 156. && n < 179)
	{
		c = 0.5 -c * 3.;
	}

	c -= lpsnow(uv, iTime) * vec3(1., 0.5, 0.5) * 0.3;
	c += lpsnow(uv + 1., iTime) * vec3(1., 0.5, 0.5) * 0.3;
	c += grain(uv, n) * 0.2;
	c *= vignette(uv);
	c += ambience(uv, n);
	c *= letterbox(uv);

	c = clamp(c, 0.01, 1.);

	// grading
	c -= 0.02;
	c *= 1.1;
	c = sqrt(c);
	c = c*c*(2.5-1.5*c*c); // contrast
	c = pow(c, vec3(1.0,0.96,1.0)); // soft green
	c *= vec3(1.08,0.99,0.99); // tint red
	c.z = (c.z+0.05)/1.05; // bias blue
	c = mix(c, c.yyy, 0.12); // desaturate

	c = 0.06 + (c * 0.9);
	// > 0.06 && < 0.96
	
	// c *= 2.;
	
	fragColor = vec4(c, 1.);
}
