//========== Copyright (c) Valve Corporation, All rights reserved. ==========//

// STATIC: "DEFERRED_SHADOWS"	"0..1"	[CONSOLE]
// STATIC: "DEFERRED_SHADOWS"	"0..0"	[PC]
// STATIC: "BLOBBY_SHADOWS"		"0..1"
#include "common_fog_ps_fxc.h"

#define HDRTYPE HDR_TYPE_NONE
#include "common_ps_fxc.h"

const float4 g_ShadowColor						: register( c1 );
const float3 g_EyePos							: register( c2 );
const float4 g_FogParams							: register( c3 );
const float4 g_DeferredParams					: register( c4 );
#define g_MaxFalloffAmount	g_DeferredParams.x
#define g_vInvScreenSize	g_DeferredParams.yz

const float4x4 g_mInvViewProj					: register( c5 );

sampler ShadowSampler	: register( s0 );
sampler sDepth			: register( s1 );

#if DEFERRED_SHADOWS == 0

//////////////////////////////////
// NORMAL SHADOW SHADER
//////////////////////////////////

struct PS_INPUT
{
	float4 worldPos_projPosZ		: TEXCOORD0;
	float4 vFalloffParams			: TEXCOORD1_centroid;
	float3 texCoord0_shadowAlpha	: TEXCOORD2_centroid;
#if !defined( _X360 )
	float4 texCoord1_2				: TEXCOORD3_centroid;
	float4 texCoord3_4				: TEXCOORD4;
#endif
};

float4_color_return_type main( PS_INPUT i ) : COLOR
{
	float shadowCoverage;
	
	#if BLOBBY_SHADOWS == 1
	{
		shadowCoverage = tex2D( ShadowSampler, i.texCoord0_shadowAlpha.xy ).a;
	}
	#elif !defined( _X360 )
	{
		float samples0;
		float4  samples1_4;
		samples0 = tex2D( ShadowSampler, i.texCoord0_shadowAlpha.xy ).a;
		samples1_4.x = tex2D( ShadowSampler, i.texCoord1_2.xy ).a;
		samples1_4.y = tex2D( ShadowSampler, i.texCoord1_2.wz ).a;
		samples1_4.z = tex2D( ShadowSampler, i.texCoord3_4.xy ).a;
		samples1_4.w = tex2D( ShadowSampler, i.texCoord3_4.wz ).a;

		// Interpolate between a bunch of jittered shadow samples.
		shadowCoverage = samples0 * 0.2 + dot( samples1_4, float4( 0.2, 0.2, 0.2, 0.2 ) );
	}
	#else
	{
		float samples0 = tex2D( ShadowSampler, i.texCoord0_shadowAlpha.xy ).a;
		float2 texCoord = i.texCoord0_shadowAlpha.xy;
		float4 samples1_4;
		asm {
			tfetch2D samples1_4.w___, texCoord.xy, ShadowSampler, OffsetX = -1.0, OffsetY = -1.0
			tfetch2D samples1_4._w__, texCoord.xy, ShadowSampler, OffsetX =  1.0, OffsetY = -1.0
			tfetch2D samples1_4.__w_, texCoord.xy, ShadowSampler, OffsetX = -1.0, OffsetY =  1.0
			tfetch2D samples1_4.___w, texCoord.xy, ShadowSampler, OffsetX =  1.0, OffsetY =  1.0
		};

		// Interpolate between a bunch of jittered shadow samples.
		shadowCoverage = samples0 * 0.2 + dot( samples1_4, float4( 0.2,0.2,0.2,0.2 ) );
	}
	#endif

	// compute "vertex" alpha
	// NOTE: 0 means black, non-zero adds towards white...
	float fVertAlpha = saturate( i.vFalloffParams.w * i.vFalloffParams.y + i.vFalloffParams.x );	// could pull the mad into the VS
	fVertAlpha = saturate( i.vFalloffParams.z + fVertAlpha * g_MaxFalloffAmount );
	//fVertAlpha = i.texCoord0_shadowAlpha.z;

	// To accomplish shadow fading, subtract vertex alpha from texture alpha
	shadowCoverage = saturate( shadowCoverage - fVertAlpha );
		
	// Blend between white and the constant color...
	// return lerp( 1.0-shadowCoverage, 1.0, g_ShadowColor );  
	
	// this is equivalent, and saves an instruction
	float4 result = shadowCoverage*g_ShadowColor - shadowCoverage;
	result = 1.0 + result;

	float alpha = 1.0f;

	float fogFactor = CalcPixelFogFactor( PIXELFOGTYPE, g_FogParams, g_EyePos.xyz, i.worldPos_projPosZ.xyz, i.worldPos_projPosZ.w );
	
	// Apply fog here to compensate for our srcColor*dstColor alpha blend into already fogged pixels
	result.rgb = 1.0f - ( ( 1.0f - result.rgb ) * pow( ( 1.0f - fogFactor ), 4.0f ) );

	// Call FinalOutput without fog!
	return FinalOutput( float4( result.rgb, alpha ), fogFactor, PIXEL_FOG_TYPE_NONE, TONEMAP_SCALE_NONE );
}

#else // DEFERRED_SHADOWS == 1

//////////////////////////////////
// X360 DEFERRED SHADOW SHADER
//////////////////////////////////

struct PS_INPUT
{
	float4 vTexCoordBiasScale	: TEXCOORD0;

	float4 vProjToTex0			: TEXCOORD1_centroid;
	float4 vProjToTex1			: TEXCOORD2_centroid;
	float4 vProjToTex2			: TEXCOORD3_centroid;
	float4 vProjToTex3			: TEXCOORD4;
	float3 vFalloffParams		: TEXCOORD5;

#ifdef _PS3
	float4 vPos					: TEXCOORD6;
#else
	float2 vPos					: VPOS;
#endif
};

float4_color_return_type main( PS_INPUT i ) : COLOR
{
	float4 vPosCS;
	vPosCS.xy = ( i.vPos.xy+float2(0.5, 0.5) ) * g_vInvScreenSize;
	vPosCS.z = 1.0 - tex2D( sDepth, vPosCS.xy );
	vPosCS.w = 1.0;
	vPosCS.xy = 2.0 * vPosCS.xy - 1.0;
	vPosCS.y = -vPosCS.y;

	//return float4((1-vPosCS.z).xxx, 1);

	float4 vPosTS;// = mul( vPosCS, g_mScreenToTexture );
	
	// Clip space to shadow texture space transform
	vPosTS.x = dot( vPosCS, i.vProjToTex0 );
	vPosTS.y = dot( vPosCS, i.vProjToTex1 );
	vPosTS.z = dot( vPosCS, i.vProjToTex2 );
	vPosTS.w = dot( vPosCS, i.vProjToTex3 );
	vPosTS /= vPosTS.w;

	// check if pixel is within shadow frustum, and early-out if it's not
	float2 vClamped = saturate( vPosTS.xy );
	vClamped -= vPosTS.xy;
	clip( 0.0001 - dot( vClamped, vClamped ) );

	// extract normal in texture space
	float3 vNormalTS = cross( ddx(vPosTS.xyz), ddy(vPosTS.xyz) );

	#if BLOBBY_SHADOWS == 0
		float2 vTexCoord = i.vTexCoordBiasScale.xy + i.vTexCoordBiasScale.zw * vPosTS.xy;
	#else
		float2 vTexCoord = vPosTS.xy;
	#endif

	float shadowCoverage = 0.0f;
	#if !defined( _X360 ) || ( BLOBBY_SHADOWS == 1 )
	{
		shadowCoverage = tex2D( ShadowSampler, vTexCoord ).a;
	}
	#else
	{
		float samples0 = tex2D( ShadowSampler, vTexCoord ).a;
		float4 samples1_4;
		asm {
			tfetch2D samples1_4.w___, vTexCoord.xy, ShadowSampler, OffsetX = -1.0, OffsetY = -1.0
			tfetch2D samples1_4._w__, vTexCoord.xy, ShadowSampler, OffsetX =  1.0, OffsetY = -1.0
			tfetch2D samples1_4.__w_, vTexCoord.xy, ShadowSampler, OffsetX = -1.0, OffsetY =  1.0
			tfetch2D samples1_4.___w, vTexCoord.xy, ShadowSampler, OffsetX =  1.0, OffsetY =  1.0
		};

		// Interpolate between a bunch of jittered shadow samples.
		shadowCoverage = samples0 * 0.2 + dot( samples1_4, float4( 0.2,0.2,0.2,0.2 ) );
	}
	#endif

	// compute "vertex" alpha
	// NOTE: 0 means black, non-zero adds towards white...
	float fVertAlpha = saturate( vPosTS.z * i.vFalloffParams.y + i.vFalloffParams.x );	// could pull the mad into the VS
	fVertAlpha = saturate( i.vFalloffParams.z + fVertAlpha * g_MaxFalloffAmount );

	// To accomplish shadow fading, subtract vertex alpha from texture alpha
	shadowCoverage = saturate( shadowCoverage - fVertAlpha );

	// mask out shadows on geometry facing away from the shadow direction
	shadowCoverage *= saturate(sign(vNormalTS.z));

	// TODO: Add fog

	// Blend between white and the constant color...
	// return lerp( 1.0-shadowCoverage, 1.0, g_ShadowColor );  
	
	// this is equivalent, and saves an instruction
	float4 result = shadowCoverage*g_ShadowColor - shadowCoverage;
	result = 1.0 + result;

	float alpha = 1.0f;

	// TODO: Add support for fog
	float fogFactor = 0;	
	/*
	// Apply fog here to compensate for our srcColor*dstColor alpha blend into already fogged pixels
	result.rgb = 1.0f - ( ( 1.0f - result.rgb ) * pow( ( 1.0f - fogFactor ), 4.0f ) );
	*/

	//return float4( g_shadowColor.rgb, shadowCoverage );

	// Call FinalOutput without fog!
	return FinalOutput( float4( result.rgb, alpha ), fogFactor, PIXEL_FOG_TYPE_NONE, TONEMAP_SCALE_NONE );
}

#endif