struct VS_INPUT_BlendGodRays
{
	float3 Position : POSITION;
	float2 UV : TEXCOORD0;
};

struct VS_OUTPUT_BlendGodRays
{
	float4 Position : POSITION;
	float2 UV : TEXCOORD0;
	float4 ScreenPos : TEXCOORD1;
};


uniform float4 g_screenLightPos;
uniform int g_godRaysNumSamples;
uniform float g_godRaysDensity;
uniform float g_godRaysWeight;
uniform float g_godRaysDecay;
uniform float g_godRaysExposure;

texture GodRaysTexture : register(t2);

sampler2D g_godRaysTexSampler = 
sampler_state{
	texture = <GodRaysTexture>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;   
	AddressU  = Clamp;
	AddressV  = Clamp;
};


VS_OUTPUT_BlendGodRays VS_BlendGodRays(VS_INPUT_BlendGodRays In)
{
	VS_OUTPUT_BlendGodRays Out;
	Out.Position = float4(In.Position, 1.0f);
	Out.UV = In.UV;
	
	float4 screenPos = (Out.Position / Out.Position.w);
	screenPos.x *= 0.5f;
	screenPos.y *= -0.5f;
	screenPos.xy += 0.5f;
	Out.ScreenPos = screenPos;
	
	Out.ScreenPos = FixDx9HalfPixelOffset(Out.ScreenPos);
	
	return Out;
}

float4 CalcGodRays(float2 texCoord)
{
	// Copy from GPU GEM3 Chapter 13.
	
	// Calculate vector from pixel to light source in screen space.
	half2 deltaTexCoord = (texCoord - g_screenLightPos.xy);
	// Divide by number of samples and scale by control factor.
	deltaTexCoord *= 1.0f / g_godRaysNumSamples * g_godRaysDensity;
	// Store initial sample.
	float4 texColor = tex2D(g_godRaysTexSampler, texCoord);
	half3 color = texColor.rgb;
	// Set up illumination decay factor.
	half illuminationDecay = 1.0f;
	// Evaluate summation from Equation 3 g_godRaysNumSamples iterations.
	for (int i = 0; i < g_godRaysNumSamples; i++)
	{
		// Step sample location along ray.
		texCoord -= deltaTexCoord;
		// Retrieve sample at new location.
		half3 sample = tex2D(g_godRaysTexSampler, texCoord);
		// Apply sample attenuation scale/decay factors.
		sample *= illuminationDecay * g_godRaysWeight;
		// Accumulate combined color.
		color += sample;
		// Update exponential decay factor.
		illuminationDecay *= g_godRaysDecay;
	}
	// Output final color with a further scale control factor.
	return float4(color * g_godRaysExposure, 1);
}


float4 PS_BlendGodRays(VS_OUTPUT_BlendGodRays In) : COLOR
{
	return CalcGodRays(In.ScreenPos);
}


technique BlendGodRays
{
	pass p0 
	{
		AlphaBlendEnable = true;
		BlendOp = Add;	
		SrcBlend = One;
		DestBlend = One;
		ZEnable = false;
		ZWriteEnable = false;
		
		VertexShader = compile vs_3_0 VS_BlendGodRays();
		PixelShader = compile ps_3_0 PS_BlendGodRays();
	}
}
