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

float ray_to_sphere(in vec3 ray_o, in vec3 ray_d, in vec4 spr_o, in vec4 spr_col, out vec4 col)
{
	vec3 d1 = ray_o - spr_o.xyz;
	float b = 2.0 * dot(ray_d, d1);
	float c = dot(d1,d1) - spr_o.w*spr_o.w;

	float delta = b*b - 4.0*c;

	if (delta >= 0.0)
	{
		float t = (-b-sqrt(delta))/ (2.0);
		
		if (t > 0.0)
		{
//            col = vec4(normal * 0.5 + vec3(0.5), 0.0);
//            col = vec4(hp * vec3(1.0, 0.0, 0.0), 0.0);
			return t;
		}
	}

	return 1000000.0;
}

float ray_to_plane(in vec3 ray_o, in vec3 ray_d, in vec4 planevec)
{
/*
	n * p - d = 0
	p = ro + rd*t

	n * (ro + rd*t) - d = 0
	n * (ro + rd*t) = d

	v1 = ro + rd*t
	n . v1 = d

	(n.x*v1.x)+(n.y*v1.y)+(n.z*v1.z) = d

	-> (n.x*ro.x + n.x*rd.x*t)+

	!!!!

		n*rd*t = d - n*ro
		t = (d - n*ro) / n*rd;
*/

    
	float d = (planevec.w - dot(planevec.xyz,ray_o)) / dot(planevec.xyz,ray_d);
    if (d > 0.0)
      return d;

       return 1000000.0;
}

vec4 obj_pos[4];

void update_positions()
{
	obj_pos[0] = vec4(-2, 0.0, 0.0, 1.2);
	obj_pos[1] = vec4(0, sin(iGlobalTime*3.0), 0.0, 1.2);
	obj_pos[2] = vec4(2, sin(iGlobalTime*2.3), 0.0, 1.2);
	obj_pos[3] = vec4(0.0, -1.0, 0.0, 1.0);
}


void trace(float level, in vec3 ray_o, in vec3 ray_d, out vec4 outcol)
{
	vec4 lt;
	float d1, d2, d3, d4;
	
	d1 = ray_to_sphere(ray_o, ray_d, obj_pos[0], vec4(0.0), lt);
	d2 = ray_to_sphere(ray_o, ray_d, obj_pos[1], vec4(0.0), lt);
	d3 = ray_to_sphere(ray_o, ray_d, obj_pos[2], vec4(0.0), lt);
	d4 = ray_to_plane(ray_o, ray_d, obj_pos[3]);

	float d;
	float mat = 0.0;

	d = 1000000.0;

	if (d1 < 100000.0 && d1 < d)
	{
		d = d1;
		mat = 1.0;
	}
	if (d2 < 100000.0 && d2 < d)
	{
		d = d2;
		mat = 2.0;
	}
	if (d3 < 100000.0 && d3 < d)
	{
		d = d3;
		mat = 3.0;
	}
	if (d4 < 100000.0 && d4 < d)
	{
		d = d4;
		mat = 4.0;
	}

	outcol = textureCube(iChannel0, ray_d);
	
	if (mat > 0.5)
	{
		vec3 hp = ray_o + ray_d * d;
		vec3 lp = vec3(0.0+sin(iGlobalTime * 3.0) * 2.0,2.0, 0.0);
		vec3 ld = normalize(lp-hp);

		vec3 normal;
		vec4 spr_col;
		if (mat < 1.5)
		{
			normal = normalize(hp-obj_pos[0].xyz);
			spr_col = vec4(1.0, 0.4, 0.0, 0.0);
		}
		else if (mat < 2.5)
		{
			normal = normalize(hp-obj_pos[1].xyz);
			spr_col = vec4(0.4, 1.0, 0.2, 0.0);
		}
		else if (mat < 3.5)
		{
			normal = normalize(hp-obj_pos[2].xyz);
			spr_col = vec4(0.2, 0.3, 1.0, 0.0);
		}
		else if (mat < 4.5)
		{
			normal = -obj_pos[3].xyz;
			spr_col = vec4(0.6, 0.6, 1.0, 0.0);
		}
		float diffuse = clamp(dot(normal, ld), 0.0, 1.0);
		
		//outcol = vec4(normal * 0.5 + vec3(0.5), 1.0);
		
		vec3 ref_ray_o = hp;
		vec3 ref_ray_d = ray_d - 2.0*dot(ray_d, normal) * normal;
		vec4 ref_col;
		
//        ref_ray_d = -ref_ray_d;
		
		//trace2(level + 1.0, ref_ray_o, ref_ray_d, ref_col);
		float ref_fac = clamp(-dot(normal, ray_d), 0.0, 1.0) * 1.0;
		ref_col = textureCube(iChannel0, ref_ray_d) * 1.0 * ref_fac;

		
		float ref_fac2 = ref_fac * 2.0;
		float spec_light = pow(clamp(dot(ld, ref_ray_d), 0.0, 1.0), 15.0);
        outcol = vec4(pow(1.0 - ref_fac, 3.0) * 0.5);
		outcol = spr_col * diffuse + spec_light * ref_fac2;
		outcol = ref_col * spr_col;
//        outcol = vec4(1.0) * ref_fac;

	}
}
/*
{
	teetrace();
}
*/
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 ang = iGlobalTime * 1.0432;
	float ang2 = sin(iGlobalTime * 1.21231) - 0.6;
	float ang3 = sin(iGlobalTime * 1.63223) - 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) * rotinv;
	
	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();

	
	vec3 ro = vec3(0.0 + sin(iGlobalTime*1.9) * 0.0, -0.0, -4.5 + sin(iGlobalTime) * 1.0);
	vec3 rd = vec3((uv.x - 0.5), uv.y - 0.5, 1.0);
	rd = normalize(rd);

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

    gl_FragColor = 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);
    clamp(outcol * vec4(1.0, 0.9, 0.8, 1.0) * 2.0, vec4(0.0), vec4(1.0)) - vignet;
    //gl_FragColor = vec4(1.0) - vignet;
*/
}