uniform sampler2D Texture0;
uniform sampler2D ShadowMap;
uniform int enable_shadow;
uniform int object_type;
uniform int light_type;
uniform vec4 uColor;

varying vec3 lightDir;
varying vec3 normal;
varying vec3 halfVector;
varying float dist;
varying vec4 ShadowCoord;
varying vec4 position;
varying vec4 worldpos;
varying vec4 id;

vec4 ShadowCoordPostW;

// TODO ARTR: implement proper VSM using second moment
float chebyshevUpperBound(float distance)
{
	vec2 moments = texture2D(ShadowMap,ShadowCoordPostW.xy).rg;
		
	if (distance <= moments.x)
	{
		return 1.0;
	}
	
	float variance = moments.y - pow(moments.x,2.0);
	variance = max(variance,0.00002);
	
	float p_max = variance / (variance + pow(distance - moments.x,2.0));
	return p_max;
}

void main(void)
{
	vec3 n = normalize(normal);
	vec3 lightdir = normalize(lightDir);

	ShadowCoordPostW = ShadowCoord / ShadowCoord.w;
	float shadow = chebyshevUpperBound(ShadowCoordPostW.z);

	vec4 actColor = uColor;
	if(object_type == 1) actColor = gl_Color;
	if(object_type == 2 || object_type == 3 || object_type == 4) actColor = texture2D(Texture0,gl_TexCoord[0].st);

	vec4 color = gl_LightSource[0].ambient * actColor;
	vec4 color2 = color;

	float spot = 1.0;		
	switch(light_type)
	{
	case 0:	//Point Light
		spot = clamp((length(gl_LightSource[0].position.xyz-worldpos.xyz)/2.0f - gl_LightSource[0].constantAttenuation) / (gl_LightSource[0].spotCutoff - gl_LightSource[0].constantAttenuation), 0.0, 1.0);
		break;	
	case 1:	//Cone Light
		spot = clamp((length(gl_LightSource[0].position.xz-worldpos.xz)/2.0f - gl_LightSource[0].constantAttenuation) / (gl_LightSource[0].spotCutoff - gl_LightSource[0].constantAttenuation), 0.0, 1.0);
		break;
	case 2:	//Spot Light	
		float cos_outer_cone_angle = cos(gl_LightSource[0].constantAttenuation);
		float cos_inner_cone_angle = gl_LightSource[0].spotCosCutoff;
		float cos_inner_minus_outer_angle = cos_inner_cone_angle - cos_outer_cone_angle;
		float cos_cur_angle = dot(-lightdir, normalize(gl_LightSource[0].spotDirection));
		spot = clamp((cos_cur_angle - cos_outer_cone_angle) / cos_inner_minus_outer_angle, 0.0, 1.0);
		break;
	}

	float NdotL = max(dot(n,normalize(lightdir)),0.0);
	if(NdotL > 0.0)
	{
		color += spot *  (actColor * gl_LightSource[0].diffuse * NdotL);
	
		vec3 E = normalize(position.xyz);
		vec3 R = reflect(-lightdir, n);

		float specular = pow( max(dot(R, E), 0.0), 4.0);

		color += vec4(1.0) * gl_LightSource[0].specular * specular * spot;// * specular;	
	}

	color2 += actColor*spot;	

	//Light Disable
	if(light_type == 4)
	{
		color = actColor;
		color2 = actColor;
	}

	if(enable_shadow == 1)	color *=  shadow;


	switch(object_type)
	{
	case 0:
	case 3:	gl_FragData[0] = vec4(color.xyz,1.0);
		gl_FragData[1] = gl_Color;		
		break;
	case 1:
	case 2:
		gl_FragData[0] = color2;
		gl_FragData[1] = id;
		break;
	case 4: gl_FragData[0] = vec4(0.0);
		gl_FragData[1] = id;
		break;
	}
}