//--------------------------------------------------------------------------------------
// Global variables
//--------------------------------------------------------------------------------------
float3 g_LightPos;			        // Light's position in world space
float3 g_LightDir;
float4 g_LightDiffuse;				// Light's diffuse color
float3 g_LightAttenuation;

float3 g_Diffuse;

float3 g_CamPos;					// Camera position
float3 g_CamDir;					// Camera direction

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

float3 g_RainSettings;			// x = Time multiplier, y = Height

texture g_DiffuseMap;              // Diffuse texture

texture g_ShadowMap;				// Shadow map
texture g_ProjectionMap;			// Projection map

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

float4x4 g_mWorldToLightProj;		// Matrix to transform from world space to lights projection space

#define SMAP_SIZE		1024
#define SHADOW_EPSILON	0.00020f


//--------------------------------------------------------------------------------------
// Texture samplers
//--------------------------------------------------------------------------------------
sampler DiffuseMapSampler = 
sampler_state
{
    Texture = <g_DiffuseMap>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
};

sampler ShadowMapSampler = 
sampler_state
{
    Texture = <g_ShadowMap>;
	MinFilter = Point;
    MagFilter = Point;
    MipFilter = Point;
    AddressU = Clamp;
    AddressV = Clamp;
};

sampler ProjectionMapSampler = 
sampler_state
{
    Texture = <g_ProjectionMap>;
	MinFilter = Linear;
    MagFilter = Linear;
    MipFilter = Point;
    AddressU = Clamp;
    AddressV = Clamp;
};

//--------------------------------------------------------------------------------------
// Vertex shader output structure
//--------------------------------------------------------------------------------------
struct VS_OUTPUT
{
    float4 Position		: POSITION;		// vertex position 
    float2 TextureUV	: TEXCOORD0;	// vertex texture coords 
    float3 LightWorld	: TEXCOORD3;	// Un-normalised light vector in world space
    float4 PosLight		: TEXCOORD4;	// Fragment position in light's projection space
};



//--------------------------------------------------------------------------------------
// 
//--------------------------------------------------------------------------------------
VS_OUTPUT RenderSceneVS( float4 vPos : POSITION, 
                         float3 vTexCoord0 : TEXCOORD0, 
                         float3 vTexCoord1 : TEXCOORD1 )
{
    VS_OUTPUT Output;


	
	float3 vUp = float3(0,1,0);
	float3 vSide = cross( vUp, g_CamDir );
	float3 vIn = cross( vUp, vSide );
	
	float4 vNewPos = float4( dot(vPos,vSide), dot(vPos,vUp), dot(vPos,vIn), 1 );
	
	float fLoop;
	float fTime = modf( (g_time.x*g_RainSettings.x)+vTexCoord0.z, fLoop );

	vNewPos = float4( vNewPos.x + vTexCoord0.x, vNewPos.y - (fTime.x*g_RainSettings.y), vNewPos.z + vTexCoord0.y, vNewPos.w );

	
    // Transform the position from object space to homogeneous projection space
	Output.Position = mul(vNewPos, g_mWorldViewProjection);      
   
    // Calculate world position
    float3 vWorldPos = mul(vNewPos, g_mWorld); // position (world space)   
        
	// Copy texture coordinate through
	Output.TextureUV = vTexCoord1; 

	// Calculate light vector
	Output.LightWorld = g_LightPos - vWorldPos;
				
	// Transform fragment position to lights projection space
	Output.PosLight = mul( vPos, g_mWorldToLightProj );
		
    return Output;    
}

VS_OUTPUT RenderSceneInfinityVS( float4 vPos : POSITION, 
                         float3 vTexCoord0 : TEXCOORD0, 
                         float3 vTexCoord1 : TEXCOORD1 )
{
    VS_OUTPUT Output;
	
	Output.Position = float( 10000,10000,10000 );     
	Output.TextureUV = vTexCoord1; 
	Output.LightWorld = float3(0,0,0);
	Output.PosLight = float3(0,0,0)
		
    return Output;    
}


struct WriteVelocityVS_OUTPUT
{
    float4 Position		: POSITION;		// vertex position 
    float2 Velocity		: TEXCOORD0;
};


WriteVelocityVS_OUTPUT WriteVelocityVS(	float4 vPos : POSITION, 
										float3 vTexCoord0 : TEXCOORD0, 
										float3 vTexCoord1 : TEXCOORD1 )
{

    WriteVelocityVS_OUTPUT Output;
    
    Output.Position = float4(0,0,0,0); 
    Output.Velocity = float2( 0,0 ); 
       
/*
	float3 vUp = float3(0,1,0);
	float3 vSide = cross( vUp, g_CamDir );
	float3 vIn = cross( vUp, vSide );
	
	float4 vNewPos = float4( dot(vPos,vSide), dot(vPos,vUp), dot(vPos,vIn), 1 );
	
	float fLoop;
	float fTime = modf( (g_time.x*g_RainSettings.x)+vTexCoord0.z, fLoop );
	float4 vWorldPos = float4( vNewPos.x + vTexCoord0.x, vNewPos.y - (fTime.x*g_RainSettings.y), vNewPos.z + vTexCoord0.y, vNewPos.w );
	
	Output.Position = mul(vWorldPos, g_mWorldViewProjection);      
   
    fTime = modf( (g_time.y*g_RainSettings.x)+vTexCoord0.z, fLoop );
	float4 vWorldPosPrev = float4( vNewPos.x + vTexCoord0.x, vNewPos.y - (fTime.x*g_RainSettings.y), vNewPos.z + vTexCoord0.y, vNewPos.w );
	vWorldPosPrev = mul(vWorldPosPrev, g_mWorldViewProjectionPrev); 

	float4 vPosProjSpaceCurrent = Output.Position / Output.Position.w;
	float4 vPosProjSpaceLast = vWorldPosPrev / vWorldPosPrev.w;
 
	Output.Velocity = vPosProjSpaceCurrent - vPosProjSpaceLast;
	
	Output.Velocity = float2(0,0);
*/

    return Output;    
}


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


//--------------------------------------------------------------------------------------
// 
//--------------------------------------------------------------------------------------
PS_OUTPUT RenderScenePS( VS_OUTPUT In ) 
{ 
    PS_OUTPUT Output;
	
    //transform from RT space to texture space.
    float2 ShadowTexC = 0.5 * In.PosLight.xy / In.PosLight.w + float2( 0.5, 0.5 );
    ShadowTexC.y = 1.0f - ShadowTexC.y;

    // transform to texel space
    float2 texelpos = SMAP_SIZE * ShadowTexC;
    
    // Determine the lerp amounts           
    float2 lerps = frac( texelpos );

  	// Calculate distance to light
  	float1 fLightDist = length(In.LightWorld);
  	
    //float fShadowMul = (tex2D( ShadowMapSampler, ShadowTexC ).r + SHADOW_EPSILON < fLightDist)? 0.0f: 1.0f;  
    float fShadowMul = 1;
                        
                           
    // Get projected texture colour
	float3 vProjColour = tex2D( ProjectionMapSampler, ShadowTexC );
                     	
	// Attenuation
	//float fLightIntensity = clamp(g_LightAttenuation.x - g_LightAttenuation.y*sqrt(fLightDist), 0.0, 1.0);
	
	//fLightIntensity *= fShadowMul;
		
	// Sum
	float3 vDiffuse = float3(fShadowMul,fShadowMul,fShadowMul) * g_Diffuse;
			
    // Lookup mesh texture and modulate it with diffuse

	Output.RGBColor.rgb = tex2D(DiffuseMapSampler, In.TextureUV) * g_LightDiffuse * vDiffuse;
	
	Output.RGBColor.a = 0; 
	
    return Output;
}

PS_OUTPUT WriteDepthPS( VS_OUTPUT In ) 
{ 
    PS_OUTPUT Output;
	
  	// Calculate distance to light
  	float1 fLightDist = length(In.LightWorld);
  	
  	Output.RGBColor = float4( fLightDist, 0, 0, 0 );
  	
    return Output;
}


PS_OUTPUT WriteVelocityPS( WriteVelocityVS_OUTPUT In ) 
{ 
    PS_OUTPUT Output;
    
    Output.RGBColor = float4(In.Velocity,1.0f,1.0f);
    
    return Output;
}
   
    
//--------------------------------------------------------------------------------------
// Renders scene to render target
//--------------------------------------------------------------------------------------
technique RenderScene_High
{
    pass P0
    {          
        VertexShader = compile vs_1_1 RenderSceneVS();
        PixelShader  = compile ps_2_0 RenderScenePS();
    }
}

technique DepthPass
{
    pass P0
    {      
		ZWriteEnable = false;     
        VertexShader = compile vs_1_1 RenderSceneInfinityVS();
    }
}

technique WriteDepth // Moves rain to infinity
{
    pass P0
    {         
        VertexShader = compile vs_1_1 RenderSceneInfinityVS();
        PixelShader  = compile ps_2_0 WriteDepthPS();
    }
}

technique WriteScreenVelocity
{
    pass P0
    {        
        VertexShader = compile vs_1_1 WriteVelocityVS();
        PixelShader  = compile ps_2_0 WriteVelocityPS();
    }
}
