
texture g_ShadowMap;				
texture g_ProjectionMap;	

sampler ShadowMapSampler = 
sampler_state
{
    Texture = <g_ShadowMap>;
	MinFilter = Point;
    MagFilter = Point;
    MipFilter = Point;
    AddressU = Clamp;
    AddressV = Clamp;
};

sampler ProjectionMapSampler = 
sampler_state
{
    Texture = <g_ProjectionMap>;
	MinFilter = Linear;
    MagFilter = Linear;
    MipFilter = Point;
    AddressU = Clamp;
    AddressV = Clamp;
};

#define SHADOW_NEAR_PLANE	0.1
#define SHADOW_FAR_PLANE	100

float2 TransformScreenToTextureSpace( float4 vScreenSpace )
{
	//float2 ShadowTexC = 0.5 * vScreenSpace.xy / vScreenSpace.w + float2( 0.5, 0.5 );
	//ShadowTexC.y = 1.0f - ShadowTexC.y;
	
	float2 ShadowTexC = vScreenSpace.xy / vScreenSpace.w;
	
	return ShadowTexC;
}

float CalculateShadows( float4 vLightSpacePos, float fLightDist, bool bPCF )
{
	float fShadowMul = 1;
		
	if (bPCF)
	{
		// Homogenous divide
		float2 ShadowTexC = vLightSpacePos.xy / vLightSpacePos.w;

		// transform to texel space
		float2 texelpos = SHADOWS_MAP_SIZE * ShadowTexC;
	
		// Determine the lerp amounts           
		float2 lerps = frac( texelpos );
	
		// Read shadow map and calculate percentage closest filtering
		float4 sourcevals;
		
		float fInvShadowSize = 1.0/SHADOWS_MAP_SIZE;
			
	    sourcevals.x = tex2D( ShadowMapSampler, ShadowTexC ).r - fLightDist;
	    sourcevals.y = tex2D( ShadowMapSampler, ShadowTexC + float2(fInvShadowSize, 0) ).r - fLightDist;
		sourcevals.z = tex2D( ShadowMapSampler, ShadowTexC + float2(0, fInvShadowSize) ).r - fLightDist;
		sourcevals.w = tex2D( ShadowMapSampler, ShadowTexC + float2(fInvShadowSize, fInvShadowSize) ).r - fLightDist;
			    
	    float4 testResults = (sourcevals.xyzw < 0) ? 0.0 : 1.0;
	   
	    fShadowMul = lerp( lerp( testResults.x, testResults.y, lerps.x ),
					       lerp( testResults.z, testResults.w, lerps.x ), lerps.y ); 
	      

	}
	else
	{
		fShadowMul = (tex2Dproj( ShadowMapSampler, vLightSpacePos ).r < fLightDist)? 0.0f: 1.0f;  
	}
	
	return fShadowMul;      
}

float CalculateVarianceShadows( float4 vLightSpacePos, float fLightDist )
{
	float fShadowMul = 1;
	
	float2 fDepths = tex2Dproj( ShadowMapSampler, vLightSpacePos ).xy;

	//fDepths.x = fDepths.x * 20.0;	
	//fDepths.y = fDepths.y * 20.0;
	  	
	float E_x2 = fDepths.y;
    	
    float Ex_2 = fDepths.x * fDepths.x;
    	
    float variance = min( max(E_x2 - Ex_2, 0.0) + 0.000001, 1.0);
    	
	variance *= 0.1;
    	
    float m_d = (fDepths.x - fLightDist);
    
    float p = variance / (variance + m_d * m_d);
	
	//p=1-p;
		
	//fShadowMul = max( p, fShadowMul );
	//fShadowMul = p;	
	
	if (fDepths.x < fLightDist) 
	{
		fShadowMul = p;
	}
	else
	{
		fShadowMul = 1.0;
	}
	
	return fShadowMul;      
}

float3 CalculateShadowColour( float4 vLightSpacePos, float fLightDist, bool bShadow, bool bPCF )
{		
	float3 vDiffuse = tex2Dproj( ProjectionMapSampler, vLightSpacePos );
	
	if (bShadow)
	{
		vDiffuse *= CalculateShadows( vLightSpacePos, fLightDist, bPCF );
	}
	
	return vDiffuse;
}

float3 CalculateVarianceShadowColour( float4 vLightSpacePos, float fLightDist, bool bShadow, bool bPCF )
{		
	float3 vDiffuse = tex2Dproj( ProjectionMapSampler, vLightSpacePos );
	
	if (bShadow)
	{
		vDiffuse *= CalculateVarianceShadows( vLightSpacePos, fLightDist );
	}
	
	return vDiffuse;
}
