uniform float iGlobalTime;
uniform vec3 iResolution;
uniform samplerCube iChannel0;
uniform sampler2D iChannel2;

struct ray_t 
{
	vec3 o;
	vec3 d;
};

vec3 lp;
vec3 campos_fudge;
vec3 camdir_fudge;

void update_positions()
{
	lp = vec3(300.0);
	campos_fudge = vec3(0.0);
	camdir_fudge = vec3(0.0);
}

void doplane(in ray_t ray, inout vec3 normal, inout float minimum, inout float maximum, in vec4 planedef)
{
	float deter = dot(planedef.xyz,ray.d);

	// is ray parallel to plane
	if (abs(deter) < 0.00001)
		return;

	float numer = planedef.w - dot(planedef.xyz,ray.o);
	float d = numer / deter;

	// is the plane in front of us?
	if (deter > 0.0 && d > minimum)
	{
		minimum = d;
		normal = -planedef.xyz;
	}
	else if (deter <= 0.0 && d < maximum)
	{
		maximum = d;
	}
}

void brush666(in ray_t ray, inout float d, inout vec3 normal, inout vec4 color, inout float mat)
{
	float minimum = -100000.0;
	float maximum = 100000.0;
	vec3 new_normal;
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(-vec3(0.0,1.0, 0.9)), -30.0 + sin(iGlobalTime * 3.5) * 30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(-vec3(0.9,1.0, -0.9)), -30.0 + sin(iGlobalTime * 3.1) * 30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(0.0,1.0, 0.9)), -30.0 + sin(iGlobalTime * 2.0) * 30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(0.9,1.0, -0.9)), -30.0 + sin(iGlobalTime * 2.3) * 30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(1.0, 0.2, -0.3)), -30.0+ sin(iGlobalTime * 4.3) * 30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(-1.0, -0.3, 0.1)), -30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(0.1, 0.1,1.0)), -30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(0.3, -0.2,-1.0)), -30.0));

	if (minimum < maximum && minimum > 0.0 && minimum < d)
	{
		d = minimum;
		normal = new_normal;
		color = vec4(0.0, 1.0, 0.4, 0.0);
        mat = 1.0;
	}
}

void brush667(in ray_t ray, inout float d, inout vec3 normal, inout vec4 color, inout float mat)
{
	float minimum = -100000.0;
	float maximum = 100000.0;
	vec3 new_normal;
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(-vec3(0.1,1.0, 0.9)), -30.0 + sin(iGlobalTime * 2.5) * 30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(-vec3(0.8,1.0, -0.9)), -30.0 + sin(iGlobalTime * 2.1) * 30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(0.2,1.0, 0.9)), -30.0 + sin(iGlobalTime * 3.0) * 30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(0.3,1.0, -0.9)), -30.0 + sin(iGlobalTime * 3.3) * 30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(1.0, -0.24, -0.3)), -0.0+ sin(iGlobalTime * 1.3) * 30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(-1.0, 0.32, 0.1)), -60.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(0.1, -0.1,1.0)), -30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(0.3, 0.2,-1.0)), -30.0));

	if (minimum < maximum && minimum > 0.0 && minimum < d)
	{
		d = minimum;
		normal = new_normal;
		color = vec4(1.0, 0.4, 0.0, 0.0);
        mat = 1.0;
	}
}

void brush668(in ray_t ray, inout float d, inout vec3 normal, inout vec4 color, inout float mat)
{
	float minimum = -100000.0;
	float maximum = 100000.0;
	vec3 new_normal;
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(-vec3(0.1,1.0, 0.9)), -00.0 + sin(iGlobalTime * 2.5) * 30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(-vec3(-0.8,1.2, 0.9)), -00.0 + sin(iGlobalTime * 2.1) * 30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(0.2,1.0, -0.9)), -60.0 + sin(iGlobalTime * 3.0) * 30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(-0.3,1.4, -0.9)), -60.0 + sin(iGlobalTime * 3.3) * 30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(1.0, 0.24, -0.3)), -30.0+ sin(iGlobalTime * 1.3) * 30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(-1.0, -0.32, 0.1)), -30.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(0.1, 0.1,1.3)), -40.0));
	doplane(ray, new_normal, minimum, maximum, vec4( normalize(vec3(0.3, 0.2,-0.3)), -30.0));

	if (minimum < maximum && minimum > 0.0 && minimum < d)
	{
		d = minimum;
		normal = new_normal;
		color = vec4(0.0, 0.3, 1.0, 0.0);
        mat = 1.0;
	}
}

float trage(inout ray_t ray, out vec3 normal, out vec4 color)
{
	vec4 lt;
	float dc;

	float d = 100000.0;
	float mat = 0.0;

//	color = vec4(mod(vec3(iGlobalTime) + ray.d * 10.0, 1.0), 0.0);
    color = textureCube(iChannel0, ray.d);

	brush666(ray, d, normal, color, mat);
	brush667(ray, d, normal, color, mat);
	brush668(ray, d, normal, color, mat);
 
    if (d > 0.0)
    {
		vec3 hp = ray.o + ray.d * d;
		ray.o = hp;
    }
        
	return mat;
}

float shade(in float mat, inout ray_t ray, in vec3 normal, in vec4 color, inout vec4 outcol, inout vec4 refblendfac)
{

	if (mat < 0.5)
	{
		outcol += color * refblendfac;
		return 0.0;
	}

	vec3 ld = normalize(lp-ray.o);

	float diffuse = clamp(dot(normal, ld), 0.2, 1.0);
	
	//outcol = vec4(normal * 0.5 + vec3(0.5), 1.0);
	
	vec3 ref_ray_d = ray.d - 2.0*dot(ray.d, normal) * normal;
	float ref_fac = pow(clamp(-dot(normal, ray.d), 0.0, 1.0), 2.0);
	vec4 new_refblendfac = ref_fac * refblendfac * 0.3;
		
//        ref_ray_d = -ref_ray_d;
		
//		ref_col = textureCube(iChannel0, ref_ray_d) * 1.0 * ref_fac;

		
	float ref_fac2 = ref_fac * 0.5;
	float spec_light = pow(clamp(dot(ld, ref_ray_d), 0.0, 1.0), 3.0);
	vec4 thiscol = vec4(0.0);
	
	
	// diffuse lighting
//    	diffuse = 0.2;
	thiscol += color * diffuse;
	// specular hilight
	thiscol += spec_light * ref_fac2;
	// SMG lighting
	thiscol += vec4(pow(1.0 - ref_fac, 10.0) * 0.3);
	
	// mix with previous stage and set up next
	outcol += thiscol * refblendfac;
	ray.d = ref_ray_d;
	refblendfac = new_refblendfac;

	return 1.0;
}

void trace(in ray_t ray, out vec4 outcol)
{
	vec3 hp;
	vec3 normal;
	vec4 color;
	float mat;

	float cont;

	ray_t refray;
	vec4 refblendfac;

	outcol = vec4(0.0);
	refray = ray;
	refblendfac = vec4(1.0);
	mat = trage(refray, normal, color);
	cont = shade(mat, refray, normal, color, outcol, refblendfac);


	if (cont > 0.5)
	{
		mat = trage(refray, normal, color);
		cont = shade(mat, refray, normal, color, outcol, refblendfac);
	}

	if (cont > 0.5)
	{
		mat = trage(refray, normal, color);
		cont = shade(mat, refray, normal, color, outcol, refblendfac);
	}

	if (cont > 0.5)
	{
		mat = trage(refray, normal, color);
		cont = shade(mat, refray, normal, color, outcol, refblendfac);
	}

	if (cont > 0.5)
	{
		mat = trage(refray, normal, color);
		cont = shade(mat, refray, normal, color, outcol, refblendfac);
	}

	if (cont > 0.5)
	{
		mat = trage(refray, normal, color);
		cont = shade(mat, refray, normal, color, outcol, refblendfac);
	}

}


void main(void)
{
	vec2 uv = gl_FragCoord.xy / iResolution.xy;
	
	uv.xy -= vec2(0.5);
    uv.x *= iResolution.z;
	uv.xy += vec2(0.5);

	float speed = 1.1;
	float ang = iGlobalTime * 1.0432 * speed;
	float ang2 = iGlobalTime * 1.21231 * speed - 0.6;
	float ang3 = sin(iGlobalTime * 0.73223 * speed) - 0.6;

//    ang = 1.0;
	
	mat3 rotinv = mat3(
		cos(ang), 0.0, -sin(ang),
		0.0,      1.0, 0.0,
		sin(ang), 0.0, cos(ang));

	mat3 rotinv2 = mat3(
		  1.0, 0.0, 0.0,
		  0.0, cos(ang2), -sin(ang2),
		  0.0, sin(ang2), cos(ang2));

		mat3 rotinv3 = mat3(
		  cos(ang3), -sin(ang3), 0.0,
		  sin(ang3), cos(ang3), 0.0,
		  0.0, 0.0, 1.0);


	mat3 scale = mat3(
	1.0, 0.0, 0.0,
	0.0, 0.3, 0.0,
	0.0, 0.0, 1.0);
 
	rotinv = mat3(1.0) * rotinv3 * rotinv * rotinv2;
	
	mat3 rot = mat3(
		rotinv[0][0],rotinv[1][0],rotinv[2][0],
		rotinv[0][1],rotinv[1][1],rotinv[2][1],
		rotinv[0][2],rotinv[1][2],rotinv[2][2]);

	
	update_positions();

	ray_t ray;
	ray.o = vec3(0.0 + sin(iGlobalTime*1.9) * 0.0, -194.5 + sin(iGlobalTime) * 100.0, 0.0 + sin(iGlobalTime) * 0.0);
	ray.d = vec3((uv.x - 0.5), 1.0, uv.y - 0.5);

	ray.o += campos_fudge;
	ray.d += camdir_fudge;
	ray.d = normalize(ray.d);

  //  ro += rd * ((0.5)/rd.z);
	
	ray.o = rotinv * ray.o;
	ray.d = rotinv * ray.d;
	
	
	vec4 outcol;
	trace(ray, outcol);

//	gl_FragColor = 1.0-vec4(d * 0.2);
	vec4 vignet = vec4(pow(length(uv - vec2(0.5)), 5.0)) * vec4(1.0);
	
	vignet = vignet + texture2D(iChannel2, uv * 2.0) * 18.4 * (0.02 + vignet);
	vignet *= vec4(0.3, 0.6, 1.0, 1.0);
	gl_FragColor = clamp(outcol * vec4(1.0) * 2.0, vec4(0.0), vec4(1.0)) - vignet;
	//gl_FragColor = vec4(1.0) - vignet;
}