/*=============================================================================
	ModShadowCommon.usf: modulated shadow helper functions.
	Copyright 1998-2010 Epic Games, Inc. All Rights Reserved.
=============================================================================*/

#ifndef MODSHADOW_LIGHTTYPE_DIRECTIONAL
#define MODSHADOW_LIGHTTYPE_DIRECTIONAL 0
#endif

#ifndef MODSHADOW_LIGHTTYPE_POINT
#define MODSHADOW_LIGHTTYPE_POINT 0
#endif

#ifndef MODSHADOW_LIGHTTYPE_SPOT
#define MODSHADOW_LIGHTTYPE_SPOT 0
#endif

/** color to modulate shadowed areas on screen */
float4	ShadowModulateColor;
/** world position of light casting a shadow. Note: w = 1.0 / Radius */
float4	LightPosition;
/** needed to get world positions from deferred scene depth values */
float4x4 ScreenToWorld;
/** Falloff parameters for light casting a shadow */
half3 FalloffParameters;
static half FalloffExponent = FalloffParameters.x;
static half FalloffDistanceScale = FalloffParameters.y;
static half FalloffDistanceBias = FalloffParameters.z;
/** spot light direction vector in world space */
float3	SpotDirection;
/** spot light cone cut-off angles */
float2	SpotAngles;

float ShadowAttenuation(float4 ScreenPositionVec,float SceneDepth)
{
	// derive world position from scene depth
	float4 WorldPosition = MulMatrix(ScreenToWorld,float4((ScreenPositionVec.xy/ScreenPositionVec.w)*SceneDepth,SceneDepth,1));
	// vector from world position to light
	float4 WorldLightVector = float4((LightPosition.xyz - WorldPosition.xyz),0) * LightPosition.w;	
	// mul world vector by 1/radius to get distance attenuation
	half Attenuation = pow(
		saturate(1.0f - Square(max(0,length(WorldLightVector) * FalloffDistanceScale + FalloffDistanceBias)) ),
		FalloffExponent
		);
	
#if MODSHADOW_LIGHTTYPE_SPOT
	// radial attenuation based on inner/outer cone angles for spot lights
	Attenuation *= Square(clamp((dot(normalize((float3)WorldLightVector.xyz), -SpotDirection) - SpotAngles.x) * SpotAngles.y,0,1));
#endif
	
	// attenuation result as a percentage of world light vector length to light radius 
	return Attenuation;
}

#if XBOX

/* Whether to apply the emissive masking */
bool bApplyEmissiveToShadowCoverage;

/* Scale emissive mask alpha by scene color bias */
float EmissiveAlphaMaskScale;

#endif

/**
 * Applies emissive masking based on a bit in scene color alpha on xbox
 */
half ApplyEmissiveToShadowCoverage(float4 ScreenPosition, half ShadowCoverage)
{
#if XBOX
	// Using a static branch to keep from incurring this overhead with normal modulated shadows, without having to compile out extra shaders.
	if (bApplyEmissiveToShadowCoverage)
	{
		// read the scene alpha value written during the base pass.
		// scale by EmissiveAlphaMaskScale is needed to convert to unit range.
		half SceneAlpha = PreviousLighting(ScreenPosition).a * EmissiveAlphaMaskScale; 

		// if SceneAlpha >= 0.666, then the emissive bit is set.
		// The next lower value possible is 0.333 - so we can round the alpha value
		// to the nearest whole value. Getting 1 when the emissive bit is not set and 0 when it isn't
		half EmissiveBit = round(SceneAlpha);

		// when EmissiveBit is 1.0, return 1.0 otherwise return ShadowCoverage
		ShadowCoverage = max(ShadowCoverage, EmissiveBit);
	}
#endif
	return ShadowCoverage;
}


