uniform float Time, RotationTime;

uniform mat4 View, ViewRotation;

uniform samplerCube SkyboxTex;

uniform float SkyboxMix;

uniform float Color, AoFactor;

uniform float Cutouts, Slashes;

uniform float PlaneDistance;

uniform float RotationMix;

vec3 randomRot(vec3 p, float r)
{
	float c = cos(r);
	float s = sin(r);
	for (int i = 0; i < 2; i++) p = vec3(c * p.x - s * p.y, p.z, c * p.y + s * p.x);
	return p;
}

float cutout(vec3 p)
{
	return min(min(max(abs(p.x), abs(p.y)),
		max(abs(p.x), abs(p.z))),
		max(abs(p.y), abs(p.z))) - Cutouts;
}

float f(vec3 p)
{
	float sphere = length(p) - 1.0;
	float slashes = abs(fract((p.x + p.y + p.z) * 8.0) / 16.0 - 1.0 / 32.0) - Slashes / 32.0;
	float plane = p.y + PlaneDistance;
	float d = min(max(sphere, slashes), plane);
	float s = 1.0;
	for (float i = 0.0; i < 5.0; i += 1.0)
	{
		p = randomRot(p, (1.2 + RotationTime * .4 / pow(2.0, i)) * RotationMix);
		vec3 a = mod(p * s, 2.0) - 1.0;
		s *= 3.0;
		vec3 r = 1.0 - 3.0 * abs(a);
		float c = cutout(r) / s;
		d = max(d, c);
	}
	return d;
}

void main()
{
	vec2 pixelPosition = (gl_FragCoord.xy - vec2(480, 270)) / 540.0;
	
	vec3 eyeDir = (ViewRotation * vec4(normalize(vec3(pixelPosition * 1.4, 1)), 1)).xyz;
	vec3 eyePos = (View * vec4(0, 0, 0, 1)).xyz;

	vec3 color = mix(vec3(.96), textureCube(SkyboxTex, eyeDir).xyz, SkyboxMix);

	float maxDisTravelled = 12.0;
	for (float disTravelled = 0.0; disTravelled < maxDisTravelled; )
	{
		float d = f(eyePos);
		if (d <= 0.0)
		{
			vec3 normal = normalize(vec3(f(eyePos + vec3(.001, 0, 0)) - d,
										f(eyePos + vec3(0, .001, 0)) - d,
										f(eyePos + vec3(0, 0, .001)) - d));
			float occlusionTerm = 0.0;
			for (float i = 1.0; i < 4.0; i += 1.0) occlusionTerm += (i * .2 - f(eyePos + normal * i * .08)) / pow(2.0, i);
			color = mix(color, vec3(Color - occlusionTerm * 3.8 * AoFactor), 1.0 - disTravelled / maxDisTravelled);
			break;
		}
		d = max(d, .002);
		eyePos += eyeDir * d;
		disTravelled += d;
	}
	
	gl_FragColor = vec4(color, 1);
}
