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

texture		g_sourceTexture;
texture		g_depthTexture;
texture		g_focusTexture;

float4x4	g_mWorld;                  // World matrix for object
float4x4	g_mWorldViewProjection;    // World * View * Projection matrix

float3		g_CamPos;
float3		g_time;						// x = time, y = prevTime, z = dt

float3		g_focalPoint;

#define BLUR_AMOUNT		0.02

//-----------------------------------------------------------------------------
// Texture samplers
//-----------------------------------------------------------------------------
sampler SourceSampler = 
sampler_state
{
    Texture = <g_sourceTexture>;
    MinFilter = POINT;  
    MagFilter = POINT;

    AddressU = Clamp;
    AddressV = Clamp;
};

sampler DepthSampler = 
sampler_state
{
    Texture = <g_depthTexture>;
    MinFilter = POINT;  
    MagFilter = POINT;

    AddressU = Clamp;
    AddressV = Clamp;
};

sampler FocusSampler = 
sampler_state
{
    Texture = <g_focusTexture>;
    MinFilter = POINT;  
    MagFilter = POINT;

    AddressU = Clamp;
    AddressV = Clamp;
};


struct VS_OUTPUT
{
    float4 Position		: POSITION;		// vertex position 
    float3 CamToFrag	: TEXCOORD0;
};


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

    Output.Position = mul(vPos, g_mWorldViewProjection);
    
    Output.CamToFrag = mul(vPos, g_mWorld) - g_CamPos;
        
    return Output;    
}

struct PS_OUTPUT
{
    float4 RGBColor : COLOR0;  // Pixel color    
};

PS_OUTPUT WriteDepthPS( VS_OUTPUT In ) 
{ 
    PS_OUTPUT Output;

	Output.RGBColor = length( In.CamToFrag );

    return Output;
}


float4 AdjustFocusPS( float2 OriginalUV : TEXCOORD0 ) : COLOR
{	
	float fFocusDepth = tex2D(DepthSampler, g_focalPoint ).r;
	
	float fCurrentFocusDepth = tex2D(FocusSampler, float2(0.5,0.5)).r;	
	
	fCurrentFocusDepth = fCurrentFocusDepth + (fFocusDepth - fCurrentFocusDepth) * ( 1 - pow( 0.98f, g_time.z * 0.1) );
	
	fCurrentFocusDepth = clamp( fCurrentFocusDepth, -100.0, 100 );

	return float4( fCurrentFocusDepth, fCurrentFocusDepth, fCurrentFocusDepth, fCurrentFocusDepth );
}

//-----------------------------------------------------------------------------
// Name:  
// Type: Pixel shader                                      
// Desc: 
//-----------------------------------------------------------------------------
float4 Blur( float2 OriginalUV : TEXCOORD0, uniform float fSamples, uniform float fdx, uniform float fdy ) : COLOR
{	
	float fFocusDepth = tex2D(FocusSampler, float2(0.5,0.5)).r;
		
    float fBlur = min( (tex2D(DepthSampler, OriginalUV).r - fFocusDepth) * BLUR_AMOUNT, 1 );
    
	float2 StartUV = OriginalUV - float2( fBlur*fdx*(fSamples*0.5-0.5), fBlur*fdy*(fSamples*0.5-0.5) );
    
    float3 vBlurred = float3(0,0,0);    
    
    float fTotalWeight = 0.0;
   
    for(float i = 0; i < fSamples; i++)
    {   
        // Sample texture in a new spot based on pixelVelocity vector 
        // and average it with the other samples        
        float2 lookup = StartUV + float2(fBlur*fdx*i,fBlur*fdy*i);
        
        // Lookup the color at this new spot
        float3 vSample = tex2D(SourceSampler, lookup);
        
        float fWeight = 1.0 - abs( (2.0*i/fSamples)-1.0 );
        
        fTotalWeight += fWeight;
          
        // Add it with the other samples
        vBlurred += (vSample * fWeight);
    }
    
    // Return the average color of all the samples
    return float4(vBlurred / fTotalWeight, 1);
}


technique WriteDepth
{
    pass P0
    {   
		VertexShader = compile vs_1_1 WriteDepthVS();     
		PixelShader = compile ps_2_0 WriteDepthPS();
    }
}

//-----------------------------------------------------------------------------
// Name: 
// Type: Technique                                     
// Desc: 
//-----------------------------------------------------------------------------
technique DepthOfField
{
	pass P0
	{
		PixelShader = compile ps_2_0 AdjustFocusPS();
	}
    pass P1
    {        
		PixelShader = compile ps_2_0 Blur( 8, 0.0035, 0 );
    }
    pass P2
    {        
		PixelShader = compile ps_2_0 Blur( 8, 0, 0.0035 );
    }
}


