
//--------------------------------------------------------------------------------------
// Global variables
//--------------------------------------------------------------------------------------

#include "GlobalDefines.txt"
#include "Shadows.txt"


float3 g_LightAttenuatgion;

float4x4 g_mWorld;                  // World matrix for object
float4x4 g_mWorldViewProjection;    // World * View * Projection matrix
float4x4 g_mWorldToLightTex;		// Matrix to transform from world space to lights texture space

float3 g_LightPos;


//--------------------------------------------------------------------------------------
// Vertex shader output structure
//--------------------------------------------------------------------------------------
struct VS_OUTPUT
{
    float4 Position			: POSITION;		// vertex position 
    float2 Depth			: TEXCOORD0;	// xy = zw depth 
    float4 LightSpacePos	: TEXCOORD1;
};


//--------------------------------------------------------------------------------------
// This shader computes standard transform and lighting
//--------------------------------------------------------------------------------------
VS_OUTPUT RenderSceneLightVS( float4 vPos : POSITION )
{
    VS_OUTPUT Output;

    // Transform the position from object space to homogeneous projection space
    Output.Position = mul(vPos, g_mWorldViewProjection);
         
    Output.Depth = (Output.Position.z + SHADOW_NEAR_PLANE) / (SHADOW_FAR_PLANE - SHADOW_NEAR_PLANE);
    
    Output.Position.z = Output.Depth.x * Output.Position.w;
  
	Output.LightSpacePos = 0;
  
    return Output;    
}

VS_OUTPUT RenderSceneWorldVS( float4 vPos : POSITION )
{
    VS_OUTPUT Output;

    // Transform the position from object space to homogeneous projection space
    Output.Position = mul(vPos, g_mWorldViewProjection);
         
    Output.LightSpacePos = mul( vPos, g_mWorldToLightTex );	// Fragment position in light-texture space
		
	Output.Depth = (Output.LightSpacePos.z + SHADOW_NEAR_PLANE) / (SHADOW_FAR_PLANE - SHADOW_NEAR_PLANE);
  
    return Output;    
}


//--------------------------------------------------------------------------------------
// Pixel shader output structure
//--------------------------------------------------------------------------------------
struct PS_OUTPUT
{
    float4 RGBColor : COLOR0;  // Pixel color    
};


PS_OUTPUT RenderSceneLightPS( VS_OUTPUT In ) 
{ 
    PS_OUTPUT Output;

	Output.RGBColor.r = In.Depth.x;
	Output.RGBColor.g = In.Depth.x * In.Depth.x;
	Output.RGBColor.ba = 0;

    return Output;
}

PS_OUTPUT RenderSceneWorldPS( VS_OUTPUT In, uniform bool bShadow, uniform bool bVariance, uniform bool bPCF ) 
{ 
    PS_OUTPUT Output;
	
	if (bVariance)
	{
		Output.RGBColor.rgb = CalculateVarianceShadows( In.LightSpacePos, In.Depth.x );
	}
	else
	{	
		Output.RGBColor.rgb = CalculateShadowColour( In.LightSpacePos, In.Depth.x, bShadow, bPCF );
	}
	
	Output.RGBColor.a = 1;
	
    return Output;
}

static const float NumberOfPostProcessSamples = 8.0;
static const float BlurScale = 0.002; //0.003

float4 PostProcessBlurH( float2 OriginalUV : TEXCOORD0 ) : COLOR
{
	//return float4(0.0,1.0,0.0,0.0);
	
    float2 Blurred = 0;    
    
    float2 StartUV = OriginalUV - float2(NumberOfPostProcessSamples*0.5*BlurScale,0);
    
    float fTotalWeight = 0.0;
    
    for(float i = 0; i < NumberOfPostProcessSamples; i++)
    {        
        float2 lookup = StartUV + float2(BlurScale*i,0);
        
        float4 Current = tex2D(ShadowMapSampler, lookup);
        
        float fWeight = 1.0 - abs( (2.0*i/NumberOfPostProcessSamples)-1.0 );
        
        fTotalWeight += fWeight;
        
        Blurred += (Current.rg * fWeight);
    }
    
    // Return the average color of all the samples
    return float4(Blurred.x,Blurred.y,0,0) / fTotalWeight;
}

float4 PostProcessBlurV( float2 OriginalUV : TEXCOORD0 ) : COLOR
{
	//return float4(1.0,0.0,0.0,0.0);
	
    float2 Blurred = 0;    
    
    float2 StartUV = OriginalUV - float2(0,NumberOfPostProcessSamples*0.5*BlurScale);
    
    float fTotalWeight = 0.0;
  
    for(float i = 0; i < NumberOfPostProcessSamples; i++)
    {   
        float2 lookup = StartUV + float2(0,BlurScale*i);
        
        float4 Current = tex2D(ShadowMapSampler, lookup);
        
        float fWeight = 1.0 - abs( (2.0*i/NumberOfPostProcessSamples)-1.0 );
        
        fTotalWeight += fWeight;
        
        Blurred += (Current.rg * fWeight);
    }
    
    // Return the average color of all the samples
    return float4(Blurred.x,Blurred.y,0,0) / fTotalWeight;
}

//--------------------------------------------------------------------------------------
// Renders scene to render target
//--------------------------------------------------------------------------------------
technique WriteDepth
{
    pass P0
    {          
		CullMode = None;
        VertexShader = compile vs_1_1 RenderSceneLightVS();
        PixelShader  = compile ps_1_4 RenderSceneLightPS();
    }
}

technique WriteShadowMask
{
    pass P0
    {          
        VertexShader = compile vs_1_1 RenderSceneWorldVS();
        PixelShader  = compile ps_2_0 RenderSceneWorldPS( true, true, false );
    }
}

technique WriteShadowMaskLow
{
    pass P0
    {          
        VertexShader = compile vs_1_1 RenderSceneWorldVS();
        PixelShader  = compile ps_1_4 RenderSceneWorldPS( true, false, false );
    }
}

technique BlurShadowMap
{
    pass P0
    {          
        PixelShader  = compile ps_2_0 PostProcessBlurH();
    }
    pass P1
    {          
        PixelShader  = compile ps_2_0 PostProcessBlurV();
    }
}

