#version 120

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;

struct plane_t
{
	vec3 n;
	float d;
};

struct sphere_t
{
	vec3 p;
	float r;
};

uniform plane_t brush666_pr[6];
uniform plane_t brush667_pr[6];
uniform plane_t brush668_pr[6];

//sphere_t obj_pallomulkku = sphere_t(vec3(0.0, 0.0, 0.0), 34.0 + sin(iGlobalTime * 2.0) * 10.0);
sphere_t obj_pallomulkku = sphere_t(vec3(0.0, 0.0, 0.0), 34.0);
sphere_t obj_pallomulkku2 = sphere_t(vec3(-50.0, 0.0, 0.0), 50.0);

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

	//dosphere(ray, new_normal, mininum, vec4(0.0, 0.0, 0.0, 45.0));
float dosphere(in ray_t ray, inout vec3 normal,inout float minimum, inout float maximum, in sphere_t spr_o)
{
	vec3 d1 = ray.o - spr_o.p.xyz;
	float b = 2.0 * dot(ray.d, d1);
	float c = dot(d1,d1) - spr_o.r*spr_o.r;

	float delta = b*b - 4.0*c;

	if (delta >= 0.0)
	{
		minimum = (-b-sqrt(delta))/ (2.0);
		maximum = (-b+sqrt(delta))/ (2.0);

		vec3 hp = ray.o + ray.d * minimum;
		normal = normalize(hp-spr_o.p.xyz);
		return 1.0;
	}
	else
		return 0.0;
}

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

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

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

	// is the plane in front of us?
	if (deter > 0.0 && d > minimum)
	{

		minimum = d;
		normal = -planedef.n.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;

	for (int i = 0; i < 6; i++)
	{
		doplane(ray, new_normal, minimum, maximum, brush666_pr[i]);
	}

	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;

	for (int i = 0; i < 6; i++)
	{
		doplane(ray, new_normal, minimum, maximum, brush667_pr[i]);
	}

	if (minimum < maximum && minimum > 0.0 && minimum < d)
	{
		d = minimum;
		normal = new_normal;
		color = vec4(1.0, 0.4, 0.0, 0.0);
        mat = 2.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;

	for (int i = 0; i < 6; i++)
	{
		doplane(ray, new_normal, minimum, maximum, brush668_pr[i]);
	}

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

void pallomulkku(in ray_t ray, inout float d, inout vec3 normal, inout vec4 color, inout float mat)
{
	vec3 new_normal;
	float minimum = -100000.0;
	float maximum = 100000.0;

//	dosphere(ray, new_normal, minimum, maximum, vec4(0.0, 0.0 + sin(iGlobalTime * 1.2123)*50.0, 0.0, 34.0 + sin(iGlobalTime * 2.0) * 10.0));
	float hit = dosphere(ray, new_normal, minimum, maximum, obj_pallomulkku);
    
    if (hit > 0.5 && minimum > 0.0 && minimum < d)
    {
        d = minimum;
        normal = new_normal;
        color = vec4(0.0, 0.0, 1.0, 0.0);
        mat = 4.0;
    }
}

void pallomulkku2(in ray_t ray, inout float d, inout vec3 normal, inout vec4 color, inout float mat)
{
	vec3 new_normal;
	float minimum = 100000.0;
	float maximum = -100000.0;
//	dosphere(ray, new_normal, minimum, maximum, vec4(20.0, 0.0, 0.0 + sin(iGlobalTime * 2.2123)*50.0, 34.0 + sin(iGlobalTime * 3.5) * 10.0));
	float hit = dosphere(ray, new_normal, minimum, maximum, obj_pallomulkku2);
    
    if (hit > 0.5 && minimum > 0.0 && minimum < d)
//    if (minimum < maximum && maximum > 0.0 && minimum < d && maximum >= d)
    {
        d = minimum;
        normal = new_normal;
        color = vec4(0.5, 0.5, 0.9, 0.0);
        mat = 4.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.xzy);

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

float trage_shadow(in ray_t ray)
{
	float d = 100000.0;

	vec3 normal;
	vec4 color;
	float mat;

	brush666(ray, d, normal, color, mat);
	brush667(ray, d, normal, color, mat);
	brush668(ray, d, normal, color, mat);
    pallomulkku(ray, d, normal, color, mat);
    pallomulkku2(ray, d, normal, color, mat);
 
    if (d > 0.0)
    {
    	return d;
    }
        
	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 lightvec = lp-ray.o;
	float lightdist = length(lightvec);
	vec3 ld = lightvec / lightdist;

	float diffuse = clamp(dot(normal, ld), 0.2, 1.0);

	ray_t shadowray;
	shadowray.o = ray.o + ld * 0.1;
	shadowray.d = ld;

	if (trage_shadow(shadowray) < lightdist)
	{
		diffuse = 0.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);
	//float ref_fac = 1.0;
    vec4 new_refblendfac = ref_fac * refblendfac * 2.3;
		
//        ref_ray_d = -ref_ray_d;
		
//		ref_col = textureCube(iChannel0, ref_ray_d) * 1.0 * ref_fac;

		
	float ref_fac2 = ref_fac * 9.0;
	float spec_light = pow(clamp(dot(ld, ref_ray_d), 0.0, 1.0), 50.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 rX(inout vec3 p, float a)
	{
        float c,s;
		vec3 q=p;
        c = cos(a); s = sin(a);
        p.y = c * q.y - s * q.z;
        p.z = s * q.y + c * q.z;
	}

void rY(inout vec3 p, float a)
	{
        float c,s;
		vec3 q=p;
        c = cos(a); s = sin(a);
        p.x = c * q.x + s * q.z;
        p.z = -s * q.x + c * q.z;
	}

void rZ(inout vec3 p, float a)
	{
        float c,s;
		vec3 q=p;
        c = cos(a); s = sin(a);
        p.x = c * q.x - s * q.y;
        p.y = s * q.x + c * q.y;
	}

void rotate(inout vec3 o, inout vec3 d)
{
    float t=iGlobalTime;
    float pi = 3.14159265;
    o.z-= 0.1;
  rX(o,t*.04);
    rY(o,t*.324);
    rZ(o,t*.24);

  rX(d,t*.04);
    rY(d,t*.324);
    rZ(d,t*.24);

}



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

	ray_t ray;
	ray.o = vec3(0.0, 0.0, -94.5);
//	ray.d = vec3(uv.x - 0.5, 1.0, uv.y - 0.5);

	ray.d = 1. * vec3(p.x, p.y, .6) / (3. * 512.);

	rotate(ray.o, ray.d);

	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 = outcol;
	gl_FragColor.a = 1.0;

//	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;
}