//-----------------------------------------------------------------------------
// File: PixelMotionBlur.fx
//
// Desc: Effect file for image based motion blur. The HLSL shaders are used to
//       calculate the velocity of each pixel based on the last frame's matrix 
//       transforms.  This per-pixel velocity is then used in a blur filter to 
//       create the motion blur effect.
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------


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

texture RenderTargetTexture;
texture CurFrameVelocityTexture;
texture	LastFrameVelocityTexture;

float4x4 g_mWorldViewProjection;
float4x4 g_mWorldViewProjectionPrev;

float4x4 g_mViewProjectionIT;

float4x4 g_mWorld;                  
float4x4 g_mWorldPrev;                  

float4x4 g_mWorldView;                  
float4x4 g_mWorldViewPrev;  

float PixelBlurConst = 1.1f;
static const float NumberOfPostProcessSamples = 10.0f;

float VectorBlurScale = 0.2f;

float	g_Samples[12];


//-----------------------------------------------------------------------------
// Texture samplers
//-----------------------------------------------------------------------------
sampler RenderTargetSampler = 
sampler_state
{
    Texture = <RenderTargetTexture>;
    MinFilter = POINT;  
    MagFilter = POINT;

    AddressU = Clamp;
    AddressV = Clamp;
};

sampler CurFramePixelVelSampler = 
sampler_state
{
    Texture = <CurFrameVelocityTexture>;
    MinFilter = POINT;
    MagFilter = POINT;

    AddressU = Clamp;
    AddressV = Clamp;
};

sampler LastFramePixelVelSampler = 
sampler_state
{
    Texture = <LastFrameVelocityTexture>;
    MinFilter = POINT;
    MagFilter = POINT;

    AddressU = Clamp;
    AddressV = Clamp;
};


//-----------------------------------------------------------------------------
// Vertex shader output structure
//-----------------------------------------------------------------------------
struct VS_OUTPUT
{
    float4 Position : POSITION;   // position of the vertex
    float2 VelocityUV : TEXCOORD0;  // per-vertex velocity stored here
};


//-----------------------------------------------------------------------------
// Name: WorldVertexShader     
// Type: Vertex shader                                      
// Desc: In addition to standard transform and lighting, it calculates the velocity 
//       of the vertex and outputs this as a texture coord.
//-----------------------------------------------------------------------------
VS_OUTPUT WorldVertexShader( float4 vPos : POSITION )
{
    VS_OUTPUT Output;

    float4 vPosProjSpaceCurrent; 
    float4 vPosProjSpaceLast; 
     
    // Transform from object space to homogeneous projection space
    vPosProjSpaceCurrent = mul(vPos, g_mWorldViewProjection);
    vPosProjSpaceLast = mul(vPos, g_mWorldViewProjectionPrev);
    
    // Output the vertex position in projection space
    Output.Position = vPosProjSpaceCurrent;
      
    // Convert to non-homogeneous points [-1,1] by dividing by w 
    vPosProjSpaceCurrent /= vPosProjSpaceCurrent.w;
    vPosProjSpaceLast /= vPosProjSpaceLast.w;
 
    // Vertex's velocity (in non-homogeneous projection space) is the position this frame minus 
    // its position last frame.  This information is stored in a texture coord.  The pixel shader 
    // will read the texture coordinate with a sampler and use it to output each pixel's velocity.
    float2 velocity = vPosProjSpaceCurrent - vPosProjSpaceLast;    
    
	if (Output.Position.w < 30)
	{
		velocity = float2(0,0);
	}
			
	// The velocity is now between (-2,2) so divide by 2 to get it to (-1,1)
    velocity /= 2.0f;   
    
    // Store the velocity in a texture coord
    Output.VelocityUV = velocity;
    
    //Output.VelocityUV = float2(0,0);            
            
    return Output;    
}


struct VS_WS_OUTPUT
{
    float4 Position : POSITION;   // position of the vertex
    float4 Velocity : TEXCOORD0;  // per-vertex velocity stored here
};

VS_WS_OUTPUT WorldSpaceVertexShader( float4 vPos : POSITION )
{
    VS_WS_OUTPUT Output;

    float4 vPosProjSpaceCurrent; 
    float4 vPosProjSpaceLast; 
     
    // Transform from object space to homogeneous projection space
    Output.Position = mul(vPos, g_mWorldViewProjection);
    
    vPosProjSpaceCurrent = mul(vPos, g_mWorldView);
    vPosProjSpaceLast = mul(vPos, g_mWorldViewPrev);
    
    Output.Velocity = vPos;
    
    //Output.Velocity = vPosProjSpaceCurrent - vPosProjSpaceLast;    
    				     
    //Output.Velocity /= float3(100,100,100);   
    
    return Output;    
}

//-----------------------------------------------------------------------------
// Pixel shader output structure for no MRT
//-----------------------------------------------------------------------------
struct PS_OUTPUT_NO_MRT
{
    // The pixel shader can output 2+ values simulatanously if 
    // d3dcaps.NumSimultaneousRTs > 1
    
    float4 RGBColor      : COLOR0;  // Pixel color    
};

//-----------------------------------------------------------------------------
// Name: WorldPixelShaderPhase1 & WorldPixelShaderPhase2
// Desc: Uses multiple render passes to output 2 values one in each
//       pixel shader.  The two values are color and velocity.
//-----------------------------------------------------------------------------
PS_OUTPUT_NO_MRT WorldPixelShaderPass2(VS_OUTPUT In)
{
    PS_OUTPUT_NO_MRT Output;
    Output.RGBColor = float4(In.VelocityUV,1.0f,1.0f);
    return Output;
}

PS_OUTPUT_NO_MRT WorldSpacePixelShaderPass2(VS_WS_OUTPUT In)
{
    PS_OUTPUT_NO_MRT Output;
        
	float4 SSPosCurr = mul(In.Velocity, g_mWorldViewProjection);
	float4 SSPosPrev = mul(In.Velocity, g_mWorldViewProjectionPrev);
	
	SSPosCurr /= SSPosCurr.z;
	SSPosPrev /= SSPosPrev.z;
	
	Output.RGBColor.rg = clamp( (SSPosCurr - SSPosPrev) * float4(0.5,0.5,0,0), -0.02, 0.02 );
        
    Output.RGBColor.ba = 0;
        
    return Output;
}




//-----------------------------------------------------------------------------
// Name: PostProcessMotionBlurPS 
// Type: Pixel shader                                      
// Desc: Uses the pixel's velocity to sum up and average pixel in that direction
//       to create a blur effect based on the velocity in a fullscreen
//       post process pass.
//-----------------------------------------------------------------------------
float4 PostProcessMotionBlurPS( float2 OriginalUV : TEXCOORD0 ) : COLOR
{
	//return tex2D(RenderTargetSampler, OriginalUV);
	
    float2 pixelVelocity;
    
    // Get this pixel's current velocity and this pixel's last frame velocity
    // The velocity is stored in .r & .g channels
    float4 curFramePixelVelocity = tex2D(CurFramePixelVelSampler, OriginalUV);
    float4 lastFramePixelVelocity = tex2D(LastFramePixelVelSampler, OriginalUV);

    // If this pixel's current velocity is zero, then use its last frame velocity
    // otherwise use its current velocity.  We don't want to add them because then 
    // you would get double the current velocity in the center.  
    // If you just use the current velocity, then it won't blur where the object 
    // was last frame because the current velocity at that point would be 0.  Instead 
    // you could do a filter to find if any neighbors are non-zero, but that requires a lot 
    // of texture lookups which are limited and also may not work if the object moved too 
    // far, but could be done multi-pass.
    float curVelocitySqMag = curFramePixelVelocity.r * curFramePixelVelocity.r +
                             curFramePixelVelocity.g * curFramePixelVelocity.g;
   // float lastVelocitySqMag = lastFramePixelVelocity.r * lastFramePixelVelocity.r +
    //                          lastFramePixelVelocity.g * lastFramePixelVelocity.g;
                          
                             
    //if( lastVelocitySqMag > curVelocitySqMag )
    {
		//pixelVelocity.x =  lastFramePixelVelocity.r * PixelBlurConst;   
		//pixelVelocity.y = -lastFramePixelVelocity.g * PixelBlurConst;
    }
    //else
    {
        pixelVelocity.x =  curFramePixelVelocity.r * PixelBlurConst;   
        pixelVelocity.y = -curFramePixelVelocity.g * PixelBlurConst;    
    }
    
    // For each sample, sum up each sample's color in "Blurred" and then divide
    // to average the color after all the samples are added.
    float3 Blurred = 0;    
    
    float2 StartUV = OriginalUV + pixelVelocity*0.5;
    
    float fSampleNoLeft = NumberOfPostProcessSamples;
    
    for(float i = 0; i < NumberOfPostProcessSamples; i++)
    {   
    
        // Sample texture in a new spot based on pixelVelocity vector 
        // and average it with the other samples        
        float2 lookup = StartUV - pixelVelocity * i / NumberOfPostProcessSamples;
        
        // Lookup the color at this new spot
        float4 Current = tex2D(RenderTargetSampler, lookup);
        
        // Add it with the other samples
        Blurred += Current.rgb;
        
          
          /*
        float2 lookup = StartUV - pixelVelocity * (g_Samples[i] / NumberOfPostProcessSamples);
         
        float4 Current = tex2D(RenderTargetSampler, lookup);
           
        float fSampleStr = 1;
        
        if (abs(Current.w - fDepth) > 1)
        {
			fSampleStr = fSampleNoLeft;
		}
		
		Blurred += Current.rgb * fSampleStr;
		
		fSampleNoLeft -= fSampleStr;  
		*/   
        
    }
    
    // Return the average color of all the samples
    return float4(Blurred / NumberOfPostProcessSamples, 1.0f);
}



float4 PostProcessMotionBlurH( float2 OriginalUV : TEXCOORD0 ) : COLOR
{
    float2 Blurred = 0;    
    
    
    float2 StartUV = OriginalUV - float2(0.07*VectorBlurScale,0);
    
    for(float i = 0; i < NumberOfPostProcessSamples; i++)
    {   
        // Sample texture in a new spot based on pixelVelocity vector 
        // and average it with the other samples        
        float2 lookup = StartUV + float2(0.01*VectorBlurScale*i,0);
        
        // Lookup the color at this new spot
        float4 Current = tex2D(CurFramePixelVelSampler, lookup);
        
        // Add it with the other samples
        Blurred += Current.rg;
    }
    
    // Return the average color of all the samples
    return float4(Blurred.x,Blurred.y,0,0) / NumberOfPostProcessSamples;
}

float4 PostProcessMotionBlurV( float2 OriginalUV : TEXCOORD0 ) : COLOR
{
    float2 Blurred = 0;    
    
    float2 StartUV = OriginalUV - float2(0,0.07*VectorBlurScale);
    
    for(float i = 0; i < NumberOfPostProcessSamples; i++)
    {   
        // Sample texture in a new spot based on pixelVelocity vector 
        // and average it with the other samples        
        float2 lookup = StartUV + float2(0,0.01*VectorBlurScale*i);
        
        // Lookup the color at this new spot
        float4 Current = tex2D(CurFramePixelVelSampler, lookup);
        
        // Add it with the other samples
        Blurred += Current.rg;
    }
    
    // Return the average color of all the samples
    return float4(Blurred.x,Blurred.y,0,0) / NumberOfPostProcessSamples;
}

//-----------------------------------------------------------------------------
// Name: RenderScene
// Type: Technique                                     
// Desc: Renders the scene's color in pass 0 and writes 
//       pixel velocity in pass 1.
//-----------------------------------------------------------------------------
technique WriteScreenVelocity2
{
    pass P0
    {          
        VertexShader = compile vs_2_0 WorldVertexShader();
        PixelShader  = compile ps_2_0 WorldPixelShaderPass2();
    }
}

technique WriteScreenVelocity
{
    pass P0
    {          
        VertexShader = compile vs_2_0 WorldSpaceVertexShader();
        PixelShader  = compile ps_2_0 WorldSpacePixelShaderPass2();
    }
}



//-----------------------------------------------------------------------------
// Name: PostProcessMotionBlur
// Type: Technique                                     
// Desc: Renders a full screen quad and uses velocity information stored in 
//       the textures to blur image.
//-----------------------------------------------------------------------------
technique PostProcessMotionBlur
{
    pass P0
    {        
        PixelShader = compile ps_2_0 PostProcessMotionBlurPS();
    }
}

technique PostProcessMotionBlur2
{
	pass P0
    {        
        PixelShader = compile ps_2_0 PostProcessMotionBlurH();
    }
    pass P1
    {        
        PixelShader = compile ps_2_0 PostProcessMotionBlurV();
    }
    pass P2
    {        
        PixelShader = compile ps_2_0 PostProcessMotionBlurPS();
    }
}
