// All content © 2010-2011 DigiPen (USA) Corporation, all rights reserved.

//shader to render a spot light's properties into the light buffer.

#version 150

// ---------------------------------------------------------------------------
//uniforms

//light variables
uniform vec3			uLightPos; //viewspace light position
uniform vec3			uTarget; //viewspace light target

uniform float			uSpecular; //specular component 
uniform vec4			uDiffuse; //diffuse component
uniform vec3			uAtten; //attenuation
uniform float			uIntensity; //light intensity

uniform float			uCosInnerAngle; //cosine of spotlight inner angle
uniform float			uCosOuterAngle; //cosine of spotlight outer angle
uniform float			uFalloff; //spotlight falloff

//uniform sampler1D		uToon; //toon texture for toon shading
uniform sampler2D		uGBuffer; //geometry buffer storing depth + normals

uniform bool			uCastShadow; 

uniform float			uCamFarPlane; //scene camera far plane


// ---------------------------------------------------------------------------
// from vertex shader

in vec3					vViewPos; //view space position		

// ---------------------------------------------------------------------------
// function declarations

float calcShadow( in vec3 viewSpacePos );

// ---------------------------------------------------------------------------

out vec4				out_Color;

void main()
{	
	vec4 color = vec4( 0.0, 0.0, 0.0, 0.0 ); //stores the acculumated color
	vec4 nrmDepth = texelFetch( uGBuffer, ivec2( gl_FragCoord.xy ), 0 );
	vec3 nrm = nrmDepth.rgb;

	//reconstruct pixel position from depth: frustum ray * depth
	//frustum ray = viewPos * ( camFarPlane/viewPos.z )
	vec3 eyeScreenRay = vViewPos * (uCamFarPlane/-vViewPos.z);
	vec3 nRay = normalize( eyeScreenRay );
	vec3 pixelPos = eyeScreenRay * nrmDepth.a;
	
	//get the surface-to-light ray
	vec3 lightVec = uLightPos - pixelPos;
		
	//---------------------------------------------------------------
	//calculate distance attenuation factor
		
	float d = length( lightVec ); //distance from light to this pixel
	lightVec = normalize( lightVec );
	d = min( 1.0/( uAtten.x + uAtten.y * d + uAtten.z * d * d ), 1.0 ); 
	
	float nl = clamp( dot( nrm, lightVec ), 0.0, 1.0 );

	//---------------------------------------------------------------
	//calculate spotlight effect
	
	float e = 1.0;
	vec3 dirVec = normalize( uTarget - uLightPos ); //direction vector of spotlight
	float ld = max( dot( dirVec, -lightVec ), 0.0 );
			
	if ( ld < uCosOuterAngle )
	{
		//outside outer cone, no spotlight effect
		e = 0.0;
	}
	else
	{
		if ( ld <= uCosInnerAngle )
		{
			//interpolate
			e = pow( (ld - uCosOuterAngle)/(uCosInnerAngle - uCosOuterAngle), uFalloff );
		}
		//else inside inner cone, receive max light
	}

	d *= e;

	//----------------------------------------------------------------
	//add shadow occlusion

	if ( uCastShadow )
		d *= calcShadow( pixelPos );

	//----------------------------------------------------------------
	//add diffuse

	color = uDiffuse * nl;

	//----------------------------------------------------------------
	//add specular
		
	//phong
	float specular = pow( clamp( dot( normalize(reflect(lightVec, nrm)), nRay ), 0.0, 1.0 ), uSpecular ); // (R.V)^s, where R =  2 * N * N.L - L
	out_Color += vec4( color.rgb, specular ) * d  * uIntensity; 
}
