#ifdef GL_ES
precision mediump float;
#endif

#extension GL_OES_standard_derivatives : enable

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

float rand(vec2 co){
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

float smin( float a, float b, float k )
{
    float res = exp( -k*a ) + exp( -k*b );
    return -log( res )/k;
}

float mapYellow(vec3 pos)
{
	pos.x = abs(pos.x);
	float a = length(vec3(pos.x, pos.y / 4.0, pos.z)) - 0.4 + sin(pos.y) * .1;
	float b = length(vec3(pos.x / 1.3, pos.y / 1.5 + 3.0, pos.z / 1.3 + pos.y * 0.1)) - 1.1;
	float c = length(vec3(pos.x / 0.6, pos.y / 0.8 - 5.0, pos.z / 0.6 + pos.y * -0.3)) - 1.1;
	float d = length(vec3(pos.x / 0.6 - 2.0, pos.y / 1.6 + 4.5, pos.z / 0.6)) - 1.1 + sin(pos.y * 1.45) * 0.3;
	float e = length(vec3(pos.x / 0.3 - 3.0, pos.y / 1.0 + 2.5, pos.z / 0.6)) - 1.1;
	return smin(smin(smin(smin(a, b, 1.0), c, 1.0), d, 5.0), e, 5.0);
}

float sdTorus( vec3 p, vec2 t )
{
  	vec2 q = vec2(length(p.xz)-t.x,p.y);
  	return length(q)-t.y;
}

float mapRed(vec3 pos)
{
	pos.x = abs(pos.x);
	float a = sdTorus(pos + vec3(0, 0.8, 0.1), vec2(0.8, 0.2));
	float b = sdTorus(vec3(pos.x / 0.8, abs(pos.y - 3.3) * 0.2 + pos.z + 0.4, pos.y - 3.3), vec2(0.7, 0.15));
	float c = length(vec3(pos.x, pos.y, pos.z / 2.0) - vec3(0, 5, 0.4)) - 0.5;
	float d = length(vec3(pos.x, pos.y, pos.z / 1.5) - vec3(0.5, 2.5, 0.0)) - 0.2;
	float e = length(vec3(pos.x, pos.y / 2.0, pos.z) - vec3(1.15, -4.8, 0.0)) - 0.4;
	return min(min(min(min(a, b), c), d), e);
}

float mapWhite(vec3 pos)
{
	pos.x = abs(pos.x);
	float c = length(vec3(pos.x, pos.y, pos.z) - vec3(0.25, 4.3, 0.1)) - 0.5;
	return c;
}

float mapBlack(vec3 pos)
{
	pos.x = abs(pos.x);
	float c = length(vec3(pos.x, pos.y, pos.z) - vec3(0.3, 4.5, -0.3)) - 0.2;
	return c;
}


mat3 rotY(float a)
{
	return mat3(sin(a), 0, -cos(a),
		   0, 1, 0,
		   cos(a), 0, sin(a));
}

mat3 rotX(float a)
{
	return mat3(1, 0, 0,
		   0, sin(a), -cos(a),
		   0, cos(a), sin(a));
}
mat3 rotZ(float a)
{
	return mat3(sin(a), -cos(a), 0,
		   cos(a), sin(a), 0,
		   0, 0, 1);
}
/*
float text(vec2 uv)
{
	if ()
}*/

void main( void ) 
{
	float low = sin(time * 16.0);
	float v0 = 1.0 - pow(fract(time * 2.0), 0.5);
	
	vec2 uv = ( gl_FragCoord.xy - resolution.xy / 2.0 ) / resolution.y;
	
	mat3 rot = rotY(time * 2.6) * rotZ(sin(time * 0.6) * 0.5 + 3.14 / 2.0) * rotX(sin(time * 1.2) * 0.4 + 3.14 / 2.0) ;
	vec3 color1 = (1.0 - pow(length(uv) * (1.0 + sin(time * 20.0) * 0.2), 0.2)) * vec3(1, 1, 0.8) * 1.5;
	vec2 uv2 = uv + vec2(time * 0.05, 0.0);
	float ct = rand(floor(uv2 * 30.0)) * 10.0 + time * 20.0;
	vec3 color2 = vec3(sin(ct) * 0.4 + 0.5,
			  sin(ct * 2.5) * 0.1 + 0.2,
			  sin(ct * 2.4) * 0.3 + 0.4);
	vec3 color = mix(color1, color2, v0);
	
	vec3 origin = rot * vec3(0, 0, -18.0 + sin(time * 2.0) * 3.0) - vec3(sin(time * 0.8) * 0.5, 2.0 + sin(time * 1.5) * 0.5, 0);
	vec3 dir = normalize(vec3(uv, 1.0));
	
	
	dir.x *= 1.0 +low * 0.1;
	dir.y *= 1.0 - low * 0.1;
	dir = rot * dir;
	
	float minLen = 1.0 / 0.0;
	vec3 hitPos;
	float len = 0.0;
	for (int i = 0; i < 64; ++i)
	{
		vec3 pos = origin + dir * len;
		float d = mapYellow(pos);
		if (d < 0.001)
		{
			color = vec3(1.0, 0.8, 0.2);
			minLen = min(minLen, len);
			hitPos = pos;
		}
		len += d;
	}
	
	len = 0.0;
	for (int i = 0; i < 64; ++i)
	{
		vec3 pos = origin + dir * len;
		float d = mapRed(pos);
		if (len > minLen)
		{
			break;
		}
		if (d < 0.001)
		{
			color = vec3(1.0, 0.0, 0.0);
			minLen = min(minLen, len);
			hitPos = pos;
		}
		len += d;
	}

	len = 0.0;
	for (int i = 0; i < 64; ++i)
	{
		vec3 pos = origin + dir * len;
		float d = mapWhite(pos);
		if (len > minLen)
		{
			break;
		}
		if (d < 0.001)
		{
			color = vec3(1.0, 1.0, 1.0);
			minLen = min(minLen, len);
			hitPos = pos;
		}
		len += d;
	}

	len = 0.0;
	for (int i = 0; i < 64; ++i)
	{
		vec3 pos = origin + dir * len;
		float d = mapBlack(pos);
		if (len > minLen)
		{
			break;
		}
		if (d < 0.001)
		{
			color = vec3(0.0, 0.0, 0.0);
			minLen = min(minLen, len);
			hitPos = pos;
		}
		len += d;
	}

	color *= 2.0 - length(hitPos - vec3(0, -2, 0)) * 0.2;
	gl_FragColor = vec4(color, 1.0);

}