//*******************************************************************
//
// File: Asura_Platform_FSFX_SM30.cpp        
//
// Created: 19 Mar 2007
//
// Description: 
//
//*******************************************************************

// system libraries
#include "Core/Asura.h"

#if defined( ASURA_USE_FSFX)

#if defined(ASURA_TARGET_SM3)

// main header
#include "FSFX/Asura_FSFX_Component.h"
#include "FSFX/Asura_FSFX_System.h"
#include "FSFX/Asura_FSFX_Template.h"

#include "Rendering/Asura_Direct3D_BackBufferCapture.h"
#include "Rendering/Asura_Direct3D_Effects_System.h"
#include "Rendering/Asura_Direct3D_RenderTargetManager.h"
#include "Rendering/Asura_Direct3D_UserOptions.h"
#include "Rendering/Asura_Direct3D_Caps.h"
#include "Rendering/Asura_ViewPort.h"
#include "Rendering/Asura_Render.h"
#include "Rendering/Asura_Overlay_Quad.h"

#if defined(ASURA_TARGET_SM3)
#include "FSFX/Asura_Platform_FSFX_SM30.h"
#endif

//*******************************************************************
// Constants
//*******************************************************************

const Direct3D_VertexElement axBLOOM_VERTEX_DECLARATION[] =
{
	{ 0,  0, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },	// Position 
	{ 0,  8, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },	// UVs
	D3DDECL_END()
};

const Direct3D_VertexElement axCOLOUR_MAP_VERTEX_DECLARATION[] =
{
	{ 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },	// Position
	{ 0, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },	// UVs
	D3DDECL_END()
};

//*******************************************************************
// Globals
//*******************************************************************

Asura_Direct3D_Effect*			Asura_Platform_FSFX_SM30::g_pxBloomEffect				= NULL;
Direct3D_VertexDeclaration*		Asura_Platform_FSFX_SM30::g_pxBloomVertexDecl			= NULL;

Asura_Direct3D_Effect*			Asura_Platform_FSFX_SM30::g_pxColourMapEffect			= NULL;
Direct3D_VertexDeclaration*		Asura_Platform_FSFX_SM30::g_pxColourMapVertexDecl		= NULL;

Asura_Direct3D_Effect*			Asura_Platform_FSFX_SM30::g_pxDepthOfFieldEffect		= NULL;

D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xBloomEffectSourceTextureHandle			= 0;
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xBloomEffectUVOffsetHandle				= 0;
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xBloomEffectExtractBrightBitsHandle		= 0;
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xBloomEffectSaturationHandle			= 0;		
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xBloomEffectOutputColourHandle			= 0;
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xBloomEffectInputThresholdHandle		= 0;
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xBloomEffectBlurHandle					= 0;
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xBloomEffectInputScaleHandle			= 0;
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xBloomEffectAccumulateHandle			= 0;
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xBloomEffectAccumFadeHandle				= 0;
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xBloomEffectAccumTextureHandle			= 0;
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xBloomEffectSecondaryUVOfsHandle		= 0;

D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xBloomEffectDepthTextureHandle			= 0;			// Bloom effect shader is reused with a static branch for 
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xBloomEffectExtractNearDepthOfFieldHandle=0;			// extracting the near depth-of-field - using these params
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xBloomEffectOneOverScreenDimensionsHandle=0;
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xBloomEffectFocalDistancesHandle		 =0;

float							Asura_Platform_FSFX_SM30::g_fBloomEffectBlurBufferScale				= 0.5f;			// Set to 0.5 for a half-sized buffer

D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xColourMapInitialImageHandle			= 0;
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xColourMapHandle						= 0;
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xColourMapIntensityHandle				= 0;

D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xDepthOfFieldEffectSourceTextureHandle		= 0;
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xDepthOfFieldEffectDepthTextureHandle		= 0;
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xDepthOfFieldEffectFocalDistances			= 0;
D3DXHANDLE						Asura_Platform_FSFX_SM30::g_xDepthOfFieldEffectOneOverScreenDimensions	= 0;

void Asura_Platform_FSFX_SM30_Bloom_OnEffectLoaded(Asura_Direct3D_Effect* pxEffect);
void Asura_Platform_FSFX_SM30_Bloom_OnEffectUnloaded(Asura_Direct3D_Effect* pxEffect);

void Asura_Platform_FSFX_SM30_Bloom_CaptureEffect(void)
{
#define LOADPARAMETER(codeName, shaderName) { Asura_Platform_FSFX_SM30::codeName = Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->GetParameterByName(NULL, shaderName); Asura_Assert(Asura_Platform_FSFX_SM30::codeName, "Could not get shader parameter '" shaderName "'."); }

	Asura_Platform_FSFX_SM30::g_pxBloomEffect = Asura_Direct3D_Effects_System::GetEffect("FSFX_SM30_Bloom");	

	if (!Asura_Platform_FSFX_SM30::g_pxBloomEffect)
	{
		return;
	}

#if ASURA_LOAD_EFFECT_FILES == 1
	Asura_Platform_FSFX_SM30::g_pxBloomEffect->SetOnLoadCallback(Asura_Platform_FSFX_SM30_Bloom_OnEffectLoaded);
	Asura_Platform_FSFX_SM30::g_pxBloomEffect->SetOnUnloadCallback(Asura_Platform_FSFX_SM30_Bloom_OnEffectUnloaded);
#endif	

	// Get the params
	LOADPARAMETER(g_xBloomEffectSourceTextureHandle				 , "g_xTexture" );
	LOADPARAMETER(g_xBloomEffectUVOffsetHandle					 , "g_xUVOffset" );
	LOADPARAMETER(g_xBloomEffectBlurHandle						 , "g_bBlur" );
	LOADPARAMETER(g_xBloomEffectExtractBrightBitsHandle			 , "g_bExtractBrightBits" );
	LOADPARAMETER(g_xBloomEffectSaturationHandle 			     , "g_fSaturation");
	LOADPARAMETER(g_xBloomEffectOutputColourHandle 			     , "g_xOutputColour");
	LOADPARAMETER(g_xBloomEffectInputThresholdHandle 		     , "g_xInputThreshold");
	LOADPARAMETER(g_xBloomEffectInputScaleHandle			     , "g_fInputScale");
	LOADPARAMETER(g_xBloomEffectAccumulateHandle 			     , "g_bAccumulate");
	LOADPARAMETER(g_xBloomEffectAccumFadeHandle					 , "g_fAccumFade");
	LOADPARAMETER(g_xBloomEffectAccumTextureHandle			     , "g_xAccumTexture");
	LOADPARAMETER(g_xBloomEffectSecondaryUVOfsHandle		     , "g_xSecondaryUVOffset");	

	LOADPARAMETER(g_xBloomEffectDepthTextureHandle				 , "g_xDepthTexture");
	LOADPARAMETER(g_xBloomEffectExtractNearDepthOfFieldHandle    , "g_bExtractNearDepthOfField");
	LOADPARAMETER(g_xBloomEffectOneOverScreenDimensionsHandle	 , "g_xOneOverScreenDimensions");
	LOADPARAMETER(g_xBloomEffectFocalDistancesHandle			 , "g_xFocalDistances");

#undef LOADPARAMETER
}

void Asura_Platform_FSFX_SM30_Bloom_OnEffectLoaded(Asura_Direct3D_Effect* pxEffect)
{
	Asura_Platform_FSFX_SM30_Bloom_CaptureEffect();
}

void Asura_Platform_FSFX_SM30_Bloom_OnEffectUnloaded(Asura_Direct3D_Effect* pxEffect)
{
	Asura_Platform_FSFX_SM30::g_pxBloomEffect = NULL;
}

void Asura_Platform_FSFX_ColourMap_OnEffectLoaded(Asura_Direct3D_Effect* pxEffect);
void Asura_Platform_FSFX_ColourMap_OnEffectUnloaded(Asura_Direct3D_Effect* pxEffect);

void Asura_Platform_FSFX_ColourMap_CaptureEffect(void)
{
#define LOADPARAMETER(codeName, shaderName) { Asura_Platform_FSFX_SM30::codeName = Asura_Platform_FSFX_SM30::g_pxColourMapEffect->GetD3DEffect()->GetParameterByName(NULL, shaderName); Asura_Assert(Asura_Platform_FSFX_SM30::codeName, "Could not get shader parameter '" shaderName "'."); }

	Asura_Platform_FSFX_SM30::g_pxColourMapEffect = Asura_Direct3D_Effects_System::GetEffect("FSFX_ColourMap");

	if (!Asura_Platform_FSFX_SM30::g_pxColourMapEffect)
	{
		return;
	}

#if ASURA_LOAD_EFFECT_FILES == 1
	Asura_Platform_FSFX_SM30::g_pxColourMapEffect->SetOnLoadCallback(Asura_Platform_FSFX_ColourMap_OnEffectLoaded);
	Asura_Platform_FSFX_SM30::g_pxColourMapEffect->SetOnUnloadCallback(Asura_Platform_FSFX_ColourMap_OnEffectUnloaded);
#endif

	// Get the params
	LOADPARAMETER(g_xColourMapInitialImageHandle, "g_xInitialImageTexture" );
	LOADPARAMETER(g_xColourMapHandle, "g_xColourMapTexture" );
	LOADPARAMETER(g_xColourMapIntensityHandle, "g_fIntensity" );	

#undef LOADPARAMETER
}

void Asura_Platform_FSFX_ColourMap_OnEffectLoaded(Asura_Direct3D_Effect* pxEffect)
{
	Asura_Platform_FSFX_ColourMap_CaptureEffect();
}

void Asura_Platform_FSFX_ColourMap_OnEffectUnloaded(Asura_Direct3D_Effect* pxEffect)
{
	Asura_Platform_FSFX_SM30::g_pxColourMapEffect = NULL;
}




void Asura_Platform_FSFX_SM30_DepthOfField_OnEffectLoaded(Asura_Direct3D_Effect* pxEffect);
void Asura_Platform_FSFX_SM30_DepthOfField_OnEffectUnloaded(Asura_Direct3D_Effect* pxEffect);

void Asura_Platform_FSFX_SM30_DepthOfField_CaptureEffect(void)
{
#define LOADPARAMETER(codeName, shaderName) { Asura_Platform_FSFX_SM30::codeName = Asura_Platform_FSFX_SM30::g_pxDepthOfFieldEffect->GetD3DEffect()->GetParameterByName(NULL, shaderName); Asura_Assert(Asura_Platform_FSFX_SM30::codeName, "Could not get shader parameter '" shaderName "'."); }

	Asura_Platform_FSFX_SM30::g_pxDepthOfFieldEffect = Asura_Direct3D_Effects_System::GetEffect("FSFX_SM30_DepthOfField");	

	if (!Asura_Platform_FSFX_SM30::g_pxDepthOfFieldEffect)
	{
		return;
	}

#if ASURA_LOAD_EFFECT_FILES == 1
	Asura_Platform_FSFX_SM30::g_pxDepthOfFieldEffect->SetOnLoadCallback(Asura_Platform_FSFX_SM30_DepthOfField_OnEffectLoaded);
	Asura_Platform_FSFX_SM30::g_pxDepthOfFieldEffect->SetOnUnloadCallback(Asura_Platform_FSFX_SM30_DepthOfField_OnEffectUnloaded);
#endif	

	// Get the params
	LOADPARAMETER(g_xDepthOfFieldEffectSourceTextureHandle				 , "g_xBlurredTexture" );
	LOADPARAMETER(g_xDepthOfFieldEffectDepthTextureHandle				 , "g_xDepthTexture" );
	LOADPARAMETER(g_xDepthOfFieldEffectFocalDistances					 , "g_xFocalDistances" );
	LOADPARAMETER(g_xDepthOfFieldEffectOneOverScreenDimensions			 , "g_xOneOverScreenDimensions" );
	
#undef LOADPARAMETER
}

void Asura_Platform_FSFX_SM30_DepthOfField_OnEffectLoaded(Asura_Direct3D_Effect* pxEffect)
{
	Asura_Platform_FSFX_SM30_DepthOfField_CaptureEffect();
}

void Asura_Platform_FSFX_SM30_DepthOfField_OnEffectUnloaded(Asura_Direct3D_Effect* pxEffect)
{
	Asura_Platform_FSFX_SM30::g_pxDepthOfFieldEffect = NULL;
}

void Asura_Platform_FSFX_SM30_MotionBlur_CaptureEffect(void);

void Asura_Platform_FSFX_SM30::Platform_Initialise()
{
	if( NULL == Asura_Direct3D::D3DDevice)	
	{
		return;
	}
	
	HRESULT xResult = Asura_Direct3D::D3DDevice->CreateVertexDeclaration( axBLOOM_VERTEX_DECLARATION, &g_pxBloomVertexDecl );
	(void) xResult;
	Asura_Assert( SUCCEEDED( xResult ) && g_pxBloomVertexDecl, "Failed to create SM3.0 bloom vertex declaration." );	

	xResult = Asura_Direct3D::D3DDevice->CreateVertexDeclaration( axCOLOUR_MAP_VERTEX_DECLARATION, &g_pxColourMapVertexDecl );
	(void) xResult;
	Asura_Assert( SUCCEEDED( xResult ) && g_pxColourMapVertexDecl, "Failed to create colour map vertex declaration." );

	// Create the shader and vertex declaration
	Asura_Platform_FSFX_SM30_Bloom_CaptureEffect();
	Asura_Platform_FSFX_ColourMap_CaptureEffect();
	Asura_Platform_FSFX_SM30_DepthOfField_CaptureEffect();
	Asura_Platform_FSFX_SM30_MotionBlur_CaptureEffect();
}

void Asura_Platform_FSFX_SM30::Platform_Reset()
{
	Platform_Shutdown();
	Platform_Initialise();
}

void Asura_Platform_FSFX_SM30::Platform_Shutdown()
{
	// Release the shader and vertex declaration
	if (g_pxBloomVertexDecl)
	{
		g_pxBloomVertexDecl->Release();
		g_pxBloomVertexDecl = NULL;
	}

	if (g_pxColourMapVertexDecl)
	{
		g_pxColourMapVertexDecl->Release();
		g_pxColourMapVertexDecl = NULL;
	}
}

// Function used to create a blurred copy of the back buffer, which can be used by HUD effects
// --------------------------------------------------------------------------------------------------
static Asura_Direct3D_RenderTarget* g_apxBlurBuffers[2] = { NULL, NULL };
static Asura_Direct3D_RenderTarget* g_pxBlurredBufferToUse = NULL;

void Asura_Platform_FSFX_SM30::UpdateBlurredBuffer( const int iBlurPasses, const float fBlurRadius, const float fSaturation, bool bNearDepthOfField, float fDist0, float fDist1, float fBleedScale)
{
	SCOPEDPIXEVENT(( 0xFFFFFFFF, L"FSFX SM30 Update Blur Buffer" ));

	// create offscreen buffers to use when applying the blur
	//

	if ( NULL == g_apxBlurBuffers[0] )
	{
		g_apxBlurBuffers[0] = Asura_Direct3D_RenderTargetManager::FindUnusedRenderTarget( Asura_Platform_FSFX_SM30::g_fBloomEffectBlurBufferScale, Asura_Platform_FSFX_SM30::g_fBloomEffectBlurBufferScale, D3DFMT_A8R8G8B8, D3DFMT_UNKNOWN, true, 1, false );
	}
	if ( NULL == g_apxBlurBuffers[1] )
	{
		g_apxBlurBuffers[1] = Asura_Direct3D_RenderTargetManager::FindUnusedRenderTarget( Asura_Platform_FSFX_SM30::g_fBloomEffectBlurBufferScale, Asura_Platform_FSFX_SM30::g_fBloomEffectBlurBufferScale, D3DFMT_A8R8G8B8, D3DFMT_UNKNOWN, true, 1, false );
	}
	

	if ( (NULL == g_apxBlurBuffers[0]) || (NULL == g_apxBlurBuffers[1]) )
	{
		Asura_Assert(( (NULL != g_apxBlurBuffers[0]) && (NULL != g_apxBlurBuffers[1]) ), "Failed to allocate blur buffers for pain effect" );
		return;
	}

	if ( !Asura_Direct3D_BackBufferCapture::HasCapturedThisFrame() )
	{
		Asura_Direct3D_BackBufferCapture::CaptureCurrentBackBuffer();
	}
	Asura_Render::AllowFullScreenRendering();

	// get the current render target
	Direct3D_Surface* pxOldRenderTargetBuffer = NULL;
	Direct3D_Surface* pxOldRenderTargetDepth = NULL;
	HRESULT xResult = Asura_Direct3D::D3DDevice->GetRenderTarget(0, &pxOldRenderTargetBuffer);

	ASURA_D3D_OK(xResult);
	xResult = Asura_Direct3D::D3DDevice->GetDepthStencilSurface(&pxOldRenderTargetDepth);

	int g_iAccumBuffer=0;

	// parameters used for setting up the target rendering
	const float fViewWidth		= static_cast< float> ( Asura_Direct3D::GetPresentParameters().BackBufferWidth);
	const float fViewHeight		= static_cast< float> ( Asura_Direct3D::GetPresentParameters().BackBufferHeight);
	const float fBufferWidth	= static_cast< float> ( g_apxBlurBuffers[g_iAccumBuffer]->GetWidth());
	const float fBufferHeight	= static_cast< float> ( g_apxBlurBuffers[g_iAccumBuffer]->GetHeight());

	float fHalfTexelU = 0.5f/fViewWidth;
	float fHalfTexelV = 0.5f/fViewHeight;

	BloomVertex axVerts[4];

	axVerts[0].fX = -1.0f;     axVerts[0].fY =  1.0f;
	axVerts[1].fX = -1.0f;     axVerts[1].fY = -1.0f;
	axVerts[2].fX =  1.0f;     axVerts[2].fY =  1.0f; 
	axVerts[3].fX =  1.0f;     axVerts[3].fY = -1.0f; 

	axVerts[0].fU = 0.0f+fHalfTexelU;	   axVerts[0].fV = 0.0f+fHalfTexelV;
	axVerts[1].fU = 0.0f+fHalfTexelU;	   axVerts[1].fV = 1.0f+fHalfTexelV;
	axVerts[2].fU = 1.0f+fHalfTexelU;	   axVerts[2].fV = 0.0f+fHalfTexelV;
	axVerts[3].fU = 1.0f+fHalfTexelU;	   axVerts[3].fV = 1.0f+fHalfTexelV;

	float afSecondaryUVOffset[2] = {-fHalfTexelU + (0.5f/fBufferWidth), -fHalfTexelV + (0.5f/fBufferWidth)};

	// Clear any unused render targets (in case deferred shading targets are still active)
	unsigned int u;
	for (u = 1; u < Asura_Direct3D_Caps::GetMaxNumberOfRenderTargets(); ++u)
	{
		Asura_Direct3D::D3DDevice->SetRenderTarget(u, NULL);
	}

	// Set the render target
	Asura_Direct3D::D3DDevice->SetRenderTarget(0, g_apxBlurBuffers[g_iAccumBuffer]->GetSurface());

	const bool bSRGB = Asura_Direct3D::UseGammaCorrection();
	Asura_Direct3D::D3DDevice->SetSamplerState( 0, D3DSAMP_SRGBTEXTURE, bSRGB );
	Asura_Direct3D::D3DDevice->SetSamplerState( 1, D3DSAMP_SRGBTEXTURE, bSRGB );

	// If the accumulation buffer has just been allocated, it's a non-additive first pass	
	Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_OFF);
	Asura_Render::CurrentStates.RequestAlphaTest(false);
	
	Asura_Direct3D::D3DDevice->SetVertexDeclaration(Asura_Platform_FSFX_SM30::g_pxBloomVertexDecl);
	Asura_Direct3D_Effects_System::BeginEffect(*Asura_Platform_FSFX_SM30::g_pxBloomEffect);
	Asura_Assert(Asura_Platform_FSFX_SM30::g_pxBloomEffect->IsD3DEffectValid(), "bloom effect invalid");

	if (Asura_Platform_FSFX_SM30::g_pxBloomEffect->IsD3DEffectValid())
	{
		float afUVOffsets[2] = {0.0f,0.0f};
		Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetFloatArray(Asura_Platform_FSFX_SM30::g_xBloomEffectUVOffsetHandle, afUVOffsets, 2);

		float afOutputColour[4] = {1.0f,1.0f,1.0f,1.0f};
		Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetFloatArray(Asura_Platform_FSFX_SM30::g_xBloomEffectOutputColourHandle, afOutputColour, 4);				

		float afInputThreshold[4] = {0,0,0,0};
		Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetFloatArray(Asura_Platform_FSFX_SM30::g_xBloomEffectInputThresholdHandle,afInputThreshold, 4);		
		Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetFloat(Asura_Platform_FSFX_SM30::g_xBloomEffectInputScaleHandle, 1.0f);

		Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetBool(Asura_Platform_FSFX_SM30::g_xBloomEffectAccumulateHandle, false);

		Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetFloat(Asura_Platform_FSFX_SM30::g_xBloomEffectAccumFadeHandle, 0.0f);

		Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetTexture(Asura_Platform_FSFX_SM30::g_xBloomEffectAccumTextureHandle, Asura_Direct3D_BackBufferCapture::GetCaptureTexture());
		Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetFloatArray(Asura_Platform_FSFX_SM30::g_xBloomEffectSecondaryUVOfsHandle, afSecondaryUVOffset, 2);
		
		// No blurring on this pass, but we want do subtract the input threshold and desaturate it
		Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetBool(Asura_Platform_FSFX_SM30::g_xBloomEffectBlurHandle, false);
		if (fSaturation<1.0f)
		{		
			Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetBool(Asura_Platform_FSFX_SM30::g_xBloomEffectExtractBrightBitsHandle, true);
			Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetFloat(Asura_Platform_FSFX_SM30::g_xBloomEffectSaturationHandle, fSaturation);
		}
		else
		{
			Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetBool(Asura_Platform_FSFX_SM30::g_xBloomEffectExtractBrightBitsHandle, false);
		}

		Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetBool(Asura_Platform_FSFX_SM30::g_xBloomEffectExtractNearDepthOfFieldHandle, bNearDepthOfField);

		if (bNearDepthOfField)
		{
			float afOneOverScreenDimensions[4] = {2.0f / Asura_Viewport::GetWidth(), 2.0f / Asura_Viewport::GetHeight(),  fBleedScale, 1};
			Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetFloatArray(Asura_Platform_FSFX_SM30::g_xBloomEffectOneOverScreenDimensionsHandle, afOneOverScreenDimensions, 4);

			float afFocalDistances[4] = {fDist0, fDist1, fBleedScale, 1};
			Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetFloatArray(Asura_Platform_FSFX_SM30::g_xBloomEffectFocalDistancesHandle, afFocalDistances, 4);

			Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetTexture(Asura_Platform_FSFX_SM30::g_xBloomEffectDepthTextureHandle, Asura_Direct3D::GetDeferredRenderingTarget()->GetTexture( ASURA_DIRECT3D_DEFFEDRENDERTARGET_NORMAL_INDEX));
		}

		Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetTexture(Asura_Platform_FSFX_SM30::g_xBloomEffectSourceTextureHandle, Asura_Direct3D_BackBufferCapture::GetCaptureTexture());

		Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->BeginPass(0);
		Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->CommitChanges();
		Asura_Direct3D::D3DDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, axVerts, sizeof(BloomVertex) );
		Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->EndPass();

		// Flush any effects we may still be using
		Asura_Direct3D_Effects_System::FlushEffects();

		if (bNearDepthOfField)
		{
			Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetTexture(Asura_Platform_FSFX_SM30::g_xBloomEffectDepthTextureHandle, NULL);
			Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetBool(Asura_Platform_FSFX_SM30::g_xBloomEffectExtractNearDepthOfFieldHandle, false);
		}
	}

	// Blur passes - From the accum buffer to the temp buffer, and back
	// ---------------------------------------------------------------------------------------------------------------
	
	// Update the UVs
	fHalfTexelU = 0.5f/fBufferWidth;
	fHalfTexelV = 0.5f/fBufferHeight;

	// DMR 02/10/07 - Not quite sure what this was doing, but it seemed very wrong...
	float fUMax =  1; //(fViewWidth  * Asura_Platform_FSFX_SM30::g_fBloomEffectBlurBufferScale)  / fBufferWidth;
	float fVMax =  1; //(fViewHeight * Asura_Platform_FSFX_SM30::g_fBloomEffectBlurBufferScale)  / fBufferHeight;

	axVerts[0].fU = 0.0f+fHalfTexelU;	   axVerts[0].fV = 0.0f+fHalfTexelV;
	axVerts[1].fU = 0.0f+fHalfTexelU;	   axVerts[1].fV = fVMax+fHalfTexelV;
	axVerts[2].fU = fUMax+fHalfTexelU;	   axVerts[2].fV = 0.0f+fHalfTexelV;
	axVerts[3].fU = fUMax+fHalfTexelU;	   axVerts[3].fV = fVMax+fHalfTexelV;

	Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_OFF);

	// this blur could be made better I reckon.
	for (int iPass = 0; iPass<iBlurPasses; iPass++)
	{
		for (int iDir = 0; iDir<2; iDir++)
		{					

			// Set up the UVs and viewport
			if (iDir==0)
			{				
				// Accum buffer -> Temp buffer, Horiz blur
				float afUVOffsets[2] = {0.0025f*fBlurRadius,0.0f};
				Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetFloatArray(Asura_Platform_FSFX_SM30::g_xBloomEffectUVOffsetHandle, afUVOffsets, 2);				
				Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetTexture(Asura_Platform_FSFX_SM30::g_xBloomEffectSourceTextureHandle, g_apxBlurBuffers[g_iAccumBuffer]->GetTexture());										
				Asura_Direct3D::D3DDevice->SetRenderTarget(0, g_apxBlurBuffers[1-g_iAccumBuffer]->GetSurface());

				g_pxBlurredBufferToUse = g_apxBlurBuffers[1-g_iAccumBuffer];
			}
			else
			{
				// Temp buffer -> Accum buffer, Vert blur
				float afUVOffsets[2] = {0.0f,0.0025f*fBlurRadius};					
				Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetFloatArray(Asura_Platform_FSFX_SM30::g_xBloomEffectUVOffsetHandle, afUVOffsets, 2);
				Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetTexture(Asura_Platform_FSFX_SM30::g_xBloomEffectSourceTextureHandle, g_apxBlurBuffers[1-g_iAccumBuffer]->GetTexture());					
				Asura_Direct3D::D3DDevice->SetRenderTarget(0, g_apxBlurBuffers[g_iAccumBuffer]->GetSurface());

				g_pxBlurredBufferToUse = g_apxBlurBuffers[g_iAccumBuffer];
			}

			
			Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetTexture(Asura_Platform_FSFX_SM30::g_xBloomEffectAccumTextureHandle, NULL);


			Asura_Direct3D_Effects_System::BeginEffect(*Asura_Platform_FSFX_SM30::g_pxBloomEffect);
			Asura_Assert(Asura_Platform_FSFX_SM30::g_pxBloomEffect->IsD3DEffectValid(), "bloom effect invalid");

			if (Asura_Platform_FSFX_SM30::g_pxBloomEffect->IsD3DEffectValid())
			{									
				// Blurring enabled
				float afOutputColour[4] = {1.0f,1.0f,1.0f,1.0f};
				Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetFloatArray(Asura_Platform_FSFX_SM30::g_xBloomEffectOutputColourHandle, afOutputColour, 4);				
				Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetBool(Asura_Platform_FSFX_SM30::g_xBloomEffectBlurHandle, true);
				Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetBool(Asura_Platform_FSFX_SM30::g_xBloomEffectExtractBrightBitsHandle, false);				

				Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->BeginPass(0);
				Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->CommitChanges();
				Asura_Direct3D::D3DDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, axVerts, sizeof(BloomVertex) );
				Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->EndPass();

				// Flush any effects we may still be using
				Asura_Direct3D_Effects_System::FlushEffects();
			}
		}
	}

	// This is very important. If we leave any render target bound in any shader, it'll cause
	// device resets to fail - shader has a reference to the RT, so it won't be released
	Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetTexture(Asura_Platform_FSFX_SM30::g_xBloomEffectAccumTextureHandle, NULL);
	Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->SetTexture(Asura_Platform_FSFX_SM30::g_xBloomEffectSourceTextureHandle, NULL);
	Asura_Platform_FSFX_SM30::g_pxBloomEffect->GetD3DEffect()->CommitChanges();

	// restore the old render target and depth buffer
	Asura_Direct3D::D3DDevice->SetRenderTarget(0, pxOldRenderTargetBuffer);
	Asura_Direct3D::D3DDevice->SetDepthStencilSurface(pxOldRenderTargetDepth);

	// the Get* functions up above will have called AddRef on these objects?
	if ( pxOldRenderTargetBuffer )
		pxOldRenderTargetBuffer->Release();
	if ( pxOldRenderTargetDepth )
		pxOldRenderTargetDepth->Release();

	Asura_Direct3D::D3DDevice->SetSamplerState( 0, D3DSAMP_SRGBTEXTURE, FALSE );
	Asura_Direct3D::D3DDevice->SetSamplerState( 1, D3DSAMP_SRGBTEXTURE, FALSE );

	Asura_Direct3D_BackBufferCapture::AdviseNextFrame();
	Asura_Render::ApplyCameraSettings();
}

Direct3D_Texture const* Asura_Platform_FSFX_SM30::GetBlurredBuffer(void)
{
	if ( g_pxBlurredBufferToUse )
		return g_pxBlurredBufferToUse->GetTexture();
	else
		return NULL;
}

#endif // defined(ASURA_TARGET_SM3)

#endif // defined(ASURA_USE_FSFX)
