//////////////////////////////////////////////////////////////////////////////
//
// Asura_Platform_FSFX.cpp
//
// Copyright (c) 2006 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

/******************************************************************************/
/* Included Files                                                             */
/******************************************************************************/

#include "Core/Asura.h"

#if defined ASURA_USE_FSFX

// Asura Platform-independent
#include "Core/Asura_Timers.h"	// Needed for double vision
#include "FSFX/Asura_FSFX_Component.h"
#include "FSFX/Asura_FSFX_System.h"
#include "FSFX/Asura_FSFX_Template.h"
#include "Rendering/Asura_Render.h"
#include "Rendering/Asura_Viewport.h"
#include "Camera/Asura_Camera.h"

// Asura Xbox 360
#include "Rendering/Asura_Xbox360_Effect_System.h"
#include "Rendering/Asura_Xbox360_Graphics.h"
#include "Rendering/Asura_Xbox360_TextureManagement.h"
#include "Rendering/Asura_Xbox360_VertexBuffer.h"

#include "FSFX/Asura_Platform_FSFX.h"

#include "Debugging/Asura_Platform_GPUProfile.h"

// Misc
#include <xgraphics.h>
#include <xtl.h>

// Asura Xbox 360 Shaders
#include "FSFX_Bloom.h"
#include "FSFX_BrightnessContrast.h"
#include "FSFX_DesatTint.h"
#include "FSFX_Gamma.h"
#include "FSFX_Noise.h"
#include "FSFX_RadialBlur.h"
#include "FSFX_SM30_Bloom.h"
#include "FSFX_ColourMap.h"
#include "FSFX_SM30_DepthOfField.h"
#include "FSFX_SM30_FishEye.h"
#include "FSFX_SM30_DoubleVision.h"

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

const Direct3D_VertexElement axFSFX_VERTEX_DECLARATION[] =
{
	{ 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
	{ 0, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
	D3DDECL_END()
};

struct FSFXVertex
{
	float fX,fY;
	float fU,fV;
};


const u_int uFSFX_VERTEX_SIZE = 16;

/******************************************************************************/
/* Global Variables                                                           */
/******************************************************************************/

// Shared data
static Direct3D_VertexDeclaration* g_pxFSFX_VD = NULL;

// Bloom
static Asura_Xbox360_Effect* g_pxBloomEffect = NULL;
static Asura_Xbox360_Effect_System::Handle g_xBloomTintHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xBloomScaleHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xBloomBiasHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xBloomLevelHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xBloomRcpSizesHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xBloomBlurImageHandle = 0;
static Direct3D_Texture* g_pxBloomTexture = NULL;
static Direct3D_Surface* g_pxBloomRT = NULL;
static u_int g_uBloomRTWidth = 0;
static u_int g_uBloomRTHeight = 0;

// Advanced Bloom (DaveR 24/01/07)
static Asura_Xbox360_Effect* g_pxAdvBloomEffect = NULL;
static Direct3D_Texture*	 g_pxAdvBloomAccumTexture = NULL;
static Direct3D_Texture*	 g_pxAdvBloomTempTexture  = NULL;
static Direct3D_Surface*	 g_pxAdvBloomAccumRT = NULL;

static Asura_Xbox360_Effect_System::Handle g_xAdvBloomSourceTextureHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xAdvBloomAccumTextureHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xAdvBloomDepthTextureHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xAdvBloomUVOffsetHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xAdvBloomBlurHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xAdvBloomExtractBrightBitsHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xAdvBloomSaturationHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xAdvBloomOutputColourHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xAdvBloomInputThresholdHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xAdvBloomInputScaleHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xAdvBloomAccumulateHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xAdvBloomAccumFadeHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xAdvBloomExtractNearDepthOfFieldHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xAdvBloomFocalDistancesHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xAdvBloomUVCorrectionHandle = 0;

//static Asura_Xbox360_Effect_System::Handle g_xAdvBloomSecondaryUVOfsHandle = 0;

// Brightness and contrast
static Asura_Xbox360_Effect* g_pxBrightContrastEffect = NULL;
static Asura_Xbox360_Effect_System::Handle g_xBrightContrastCoeffsHandle = 0;

// Desaturate and tint
static Asura_Xbox360_Effect* g_pxDesatTintEffect = NULL;
static Asura_Xbox360_Effect_System::Handle g_xDesatTintColourHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xDesatTintStrengthHandle = 0;

// Gamma
static Asura_Xbox360_Effect* g_pxGammaEffect = NULL;
static Asura_Xbox360_Effect_System::Handle g_xGammaCoeffsHandle = 0;

// Noise
static Asura_Xbox360_Effect* g_pxNoiseEffect = NULL;
static Asura_Xbox360_Effect_System::Handle g_xNoiseColourHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xNoiseTextureHandle = 0;

// Radial blur
static Asura_Xbox360_Effect* g_pxRadialBlurEffect = NULL;
static Asura_Xbox360_Effect_System::Handle g_xRadialBlurTextureHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xRadialBlurVertexTransformsHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xRadialBlurSampleWeightsHandle = 0;
static Direct3D_Texture* g_pxRadialBlurTexture = NULL;

// Colour map
static Asura_Xbox360_Effect* g_pxColourMapEffect = NULL;
static Asura_Xbox360_Effect_System::Handle g_xColourMapHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xColourMapIntensityHandle = 0;

// Depth of Field
static Asura_Xbox360_Effect* g_pxDepthOfFieldEffect = NULL;
static Asura_Xbox360_Effect_System::Handle g_xDepthOfFieldBlurredTextureHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xDepthOfFieldDepthTextureHandle   = 0;
static Asura_Xbox360_Effect_System::Handle g_xDepthOfFieldEffectStrengthHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xDepthOfFieldFocalDistancesHandle = 0;

// FishEye
static Asura_Xbox360_Effect* g_pxFishEyeEffect = NULL;
static Asura_Xbox360_Effect_System::Handle g_xFishEyeTextureHandle = 0;
//static Asura_Xbox360_Effect_System::Handle g_xFishEyeIntensityHandle   = 0;
static Asura_Xbox360_Effect_System::Handle g_xFishEyeFOVHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xFishEyeMultiplierHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xFishEyeScaleHandle = 0;
static Asura_Xbox360_Effect_System::Handle g_xOneOverTanFOV		= 0;
static Asura_Xbox360_Effect_System::Handle g_xSinHalfFOV		= 0;
static Asura_Xbox360_Effect_System::Handle g_xTanHalfFOV		= 0;
static Direct3D_VertexDeclaration* g_pxFishEye_VD = NULL;

struct FishEyeVertex
{
	float m_fX, m_fY, m_fZ, m_fW;
	float m_fU, m_fV;
};


const Direct3D_VertexElement axFISHEYE_VERTEX_DECLARATION[] =
{
	{ 0,  0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
	{ 0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
	D3DDECL_END()
};

// Double vision - SteveB (01/02/08)
static Asura_Xbox360_Effect* g_pxDoubleVisionEffect;
static Asura_Xbox360_Effect_System::Handle g_xDoubleVisionInitialImageHandle;
static Asura_Xbox360_Effect_System::Handle g_xDoubleVisionXOffsetHandle1;
static Asura_Xbox360_Effect_System::Handle g_xDoubleVisionYOffsetHandle1;
static Asura_Xbox360_Effect_System::Handle g_xDoubleVisionScaleHandle1;
static Asura_Xbox360_Effect_System::Handle g_xDoubleVisionXOffsetHandle2;
static Asura_Xbox360_Effect_System::Handle g_xDoubleVisionYOffsetHandle2;
static Asura_Xbox360_Effect_System::Handle g_xDoubleVisionScaleHandle2;
static Direct3D_VertexDeclaration* g_pxDoubleVision_VD = NULL;

struct DoubleVisionVertex
{
	float m_fX, m_fY, m_fZ, m_fW;
	float m_fU, m_fV;
};

const Direct3D_VertexElement axDOUBLEVISION_VERTEX_DECLARATION[] =
{
	{ 0,  0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
	{ 0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
	D3DDECL_END()
};

/******************************************************************************/
/* Functions                                                                  */
/******************************************************************************/

////////////////////////////////////////////////////////////////////////////////
//
// RenderFSFX()
//
// Renders a one-pass simple FSFX. Ensure effect-specific constants are set up
// prior to calling this function
//
// Parameters:		pxEffect - Effect to use
// Return value:	None
//
////////////////////////////////////////////////////////////////////////////////

static void RenderFSFX( Asura_Xbox360_Effect* const pxEffect, bool bDisableTranslucency = true, bool bSRGB = true )
{
	// Resolve the current RT back out so we can read the initial colours


	if (!bSRGB)
	{
		Asura_Xbox360_Graphics::GetDevice()->SetRenderTarget( 0, Asura_Xbox360_Graphics::GetPostToneMapLinearRT() );
		Asura_Xbox360_Graphics::Resolve( Asura_Xbox360_Graphics::GetPostToneMapLinearTexture() );
	} else {
		Asura_Xbox360_Graphics::GetDevice()->SetRenderTarget( 0, Asura_Xbox360_Graphics::GetPostToneMapRT() );
		Asura_Xbox360_Graphics::Resolve( Asura_Xbox360_Graphics::GetPostToneMapTexture() );
	}

	ASURA_GPU_PROFILE_START( ASURA_GPUPROFILE_FSFX );

	// Render the FSFX	
	if (bDisableTranslucency)
	{	
		Asura_Render::CurrentStates.RequestTranslucencyMode( ASURA_TRANSLUCENCY_OFF );
	}
	else
	{
		Asura_Xbox360_Graphics::GetDevice()->SetRenderState_Inline( D3DRS_HIGHPRECISIONBLENDENABLE,
																	TRUE );
	}

	Asura_Xbox360_Graphics::GetFullScreenVB().Bind();
	Asura_Xbox360_Graphics::GetDevice()->SetVertexDeclaration( Asura_Xbox360_Graphics::GetFullScreenVD() );

	pxEffect->Begin();
	pxEffect->Commit();
	Asura_Xbox360_Graphics::GetDevice()->DrawVertices( D3DPT_RECTLIST, 0, 3 );
	pxEffect->End();

	if (!bDisableTranslucency)
	{
		Asura_Xbox360_Graphics::GetDevice()->SetRenderState_Inline( D3DRS_HIGHPRECISIONBLENDENABLE,
																	TRUE );
	}
	if (!bSRGB)
	{
		Asura_Xbox360_Graphics::GetDevice()->SetRenderTarget( 0, Asura_Xbox360_Graphics::GetPostToneMapRT() );
	}
	ASURA_GPU_PROFILE_END( ASURA_GPUPROFILE_FSFX );
}

////////////////////////////////////////////////////////////////////////////////
//
// RenderGamma()
//
// Renders a gamma or gamma RGB FSFX
//
// Parameters:		fR, fG, fB - Gamma tints for each colour channel
// Return value:	None
//
////////////////////////////////////////////////////////////////////////////////

static void RenderGamma( const float fR, const float fG, const float fB )
{
	PIXBeginNamedEvent( D3DCOLOR_XRGB( 0xE0, 0xD0, 0xC0 ), "FSFX: Gamma / Gamma RGB" );

	const float fTangentDelta = 0.1f;

	const Asura_Vector_3 xy0( 0.0f, 0.0f, 0.0f);
	const Asura_Vector_3 xy1( pow( fTangentDelta, 1.0f / fR ),		pow( fTangentDelta, 1.0f / fG ),		pow( fTangentDelta, 1.0f / fB ));
	const Asura_Vector_3 xy2( pow( 1.0f-fTangentDelta, 1.0f / fR ),	pow( 1.0f-fTangentDelta, 1.0f / fG ),	pow( 1.0f-fTangentDelta, 1.0f / fB ));
	const Asura_Vector_3 xy3( 1.0f, 1.0f, 1.0f);

	// DLH - 23 February 2006 12:38:16 - Cubic Hermit Spline
	const Asura_Vector_3 xp0 = xy0;
	const Asura_Vector_3 xp1 = xy3;
	const Asura_Vector_3 xm0 = (xy1 - xy0) / fTangentDelta;
	const Asura_Vector_3 xm1 = (xy3 - xy2) / fTangentDelta;
	const Asura_Vector_3 xt3 = (xp0 * 2.0f) + (xm0 * 1.0f) + (xp1 * -2.0f) + (xm1 * 1.0f);
	const Asura_Vector_3 xt2 = (xp0 * -3.0f) + (xm0 * -2.0f) + (xp1 * +3.0f) + (xm1 * -1.0f);
	const Asura_Vector_3 xt1 = (xm0);
	const Asura_Vector_3 xt0 = (xp0);

	const float afPSConsts[4][3] =
	{
		{ xt0.x, xt0.y, xt0.z },
		{ xt1.x, xt1.y, xt1.z },
		{ xt2.x, xt2.y, xt2.z },
		{ xt3.x, xt3.y, xt3.z },
	};

	g_pxGammaEffect->GetInterface()->SetVectorArrayF( g_xGammaCoeffsHandle, &afPSConsts[0][0], 4 );
	FXLEffectPool* const pxPool = Asura_Xbox360_Effect_System::GetPool();
	const Asura_Xbox360_Effect_System::Handle xFSFXInitialImageHandle = pxPool->GetParameterHandle( "g_xInitialImage" );
	pxPool->SetSampler( xFSFXInitialImageHandle, Asura_Xbox360_Graphics::GetPostToneMapLinearTexture() );


	RenderFSFX( g_pxGammaEffect, true, false );

	pxPool->SetSampler( xFSFXInitialImageHandle, Asura_Xbox360_Graphics::GetPostToneMapTexture() );


	PIXEndNamedEvent(); // FSFX
}

/******************************************************************************/
/* Asura_FSFX_System Static Class Functions                                   */
/******************************************************************************/

static void ClearTexture(Direct3D_Texture *pxTexture, u_int uHeight)
{
	D3DLOCKED_RECT rect;
	pxTexture->LockRect(0, &rect, NULL, 0);
	for (u_int i =0; i < uHeight; ++i)
	{
		memset(((char*)rect.pBits) + rect.Pitch * i, 0, rect.Pitch);
	}
	pxTexture->UnlockRect(0);
}


////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_System::Platform_Initialise()
//
// Initialises the FSFX system on Xbox 360
//
// Parameters:		None
// Return value:	None
//
////////////////////////////////////////////////////////////////////////////////


void Asura_FSFX_System::Platform_Initialise()
{
	const u_int uScreenWidth = Asura_Xbox360_Graphics::GetScreenWidth();
	const u_int uScreenHeight = Asura_Xbox360_Graphics::GetScreenHeight();

	// Bloom

	g_pxBloomEffect = Asura_Xbox360_Effect_System::CreateEffectFromMemory( g_auFSFX_Bloom );
	g_xBloomTintHandle = g_pxBloomEffect->GetParameterHandle( "g_xExtractTint" );
	g_xBloomScaleHandle = g_pxBloomEffect->GetParameterHandle( "g_fExtractScale" );
	g_xBloomBiasHandle = g_pxBloomEffect->GetParameterHandle( "g_fExtractBias" );
	g_xBloomLevelHandle = g_pxBloomEffect->GetParameterHandle( "g_fApplyLevel" );
	g_xBloomRcpSizesHandle = g_pxBloomEffect->GetParameterHandle( "g_xRcpScreenSizes" );
	g_xBloomBlurImageHandle = g_pxBloomEffect->GetParameterHandle( "g_xBlurImage" );

	g_uBloomRTWidth = 320;
	g_uBloomRTHeight = 180;

	Asura_Xbox360_Graphics::GetDevice()->CreateTexture( g_uBloomRTWidth, g_uBloomRTHeight, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_pxBloomTexture, NULL );
	Asura_Assert( g_pxBloomTexture, "Unable to create bloom texture." );
	ClearTexture(g_pxBloomTexture, g_uBloomRTHeight);
	g_pxBloomEffect->GetInterface()->SetSampler( g_xBloomBlurImageHandle, g_pxBloomTexture );

	const D3DSURFACE_PARAMETERS& xBloomRTParams = Asura_Xbox360_Graphics::GetSurfaceParams( Asura_Xbox360_Graphics::SP_BLOOM );
	Asura_Xbox360_Graphics::GetDevice()->CreateRenderTarget( g_uBloomRTWidth, g_uBloomRTHeight, D3DFMT_LIN_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, FALSE, &g_pxBloomRT, &xBloomRTParams );
	Asura_Assert( g_pxBloomRT, "Unable to create bloom render target." );

	// Brightness and contrast
	g_pxBrightContrastEffect = Asura_Xbox360_Effect_System::CreateEffectFromMemory( g_auFSFX_BrightnessContrast );
	g_xBrightContrastCoeffsHandle = g_pxBrightContrastEffect->GetParameterHandle( "g_xCoefficients" );

	// Desaturate and tint
	g_pxDesatTintEffect = Asura_Xbox360_Effect_System::CreateEffectFromMemory( g_auFSFX_DesatTint);
	g_xDesatTintColourHandle = g_pxDesatTintEffect->GetParameterHandle( "g_xTintColour" );
	g_xDesatTintStrengthHandle = g_pxDesatTintEffect->GetParameterHandle( "g_fStrength" );

	// Gamma
	g_pxGammaEffect = Asura_Xbox360_Effect_System::CreateEffectFromMemory( g_auFSFX_Gamma);
	g_xGammaCoeffsHandle = g_pxGammaEffect->GetParameterHandle( "g_axCoefficients" );

	// Noise

	g_pxNoiseEffect = Asura_Xbox360_Effect_System::CreateEffectFromMemory( g_auFSFX_Noise);
	g_xNoiseColourHandle = g_pxNoiseEffect->GetParameterHandle( "g_fColour" );
	g_xNoiseTextureHandle = g_pxNoiseEffect->GetParameterHandle( "g_xNoiseTexture" );

	// Radial blur

	g_pxRadialBlurEffect = Asura_Xbox360_Effect_System::CreateEffectFromMemory( g_auFSFX_RadialBlur);
	g_xRadialBlurTextureHandle = g_pxRadialBlurEffect->GetParameterHandle( "g_xTexture" );
	g_xRadialBlurVertexTransformsHandle = g_pxRadialBlurEffect->GetParameterHandle( "g_axVertexTransforms" );
	g_xRadialBlurSampleWeightsHandle = g_pxRadialBlurEffect->GetParameterHandle( "g_afSampleWeights" );

	// NB if the size changes, update the dummy allocation for non-widescreen modes in
	// Asura_Xbox360_Graphics::Initialise()
	Asura_Xbox360_Graphics::GetDevice()->CreateTexture( uScreenWidth, uScreenHeight, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_pxRadialBlurTexture, NULL );
	Asura_Assert( g_pxRadialBlurTexture, "Unable to create radial blur texture." );
	ClearTexture(g_pxRadialBlurTexture, uScreenHeight);

	// Advanced Bloom
	g_pxAdvBloomEffect = Asura_Xbox360_Effect_System::CreateEffectFromMemory( g_auFSFX_SM30_Bloom);

	// NB if the size changes, update the dummy allocation for non-widescreen modes in
	// Asura_Xbox360_Graphics::Initialise()
	Asura_Xbox360_Graphics::GetDevice()->CreateTexture( uScreenWidth / 2, uScreenHeight / 2, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_pxAdvBloomAccumTexture, NULL );
	Asura_Xbox360_Graphics::GetDevice()->CreateTexture( uScreenWidth / 2, uScreenHeight / 2, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_pxAdvBloomTempTexture, NULL );

	const D3DSURFACE_PARAMETERS& xAdvBloomRTParams = Asura_Xbox360_Graphics::GetSurfaceParams( Asura_Xbox360_Graphics::SP_ADV_BLOOM );
	Asura_Xbox360_Graphics::GetDevice()->CreateRenderTarget( uScreenWidth / 2, uScreenHeight / 2, D3DFMT_LIN_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, FALSE, &g_pxAdvBloomAccumRT, &xAdvBloomRTParams );

	Asura_Assert( g_pxAdvBloomAccumTexture && g_pxAdvBloomTempTexture, "Unable to create adv. bloom textures" );
	Asura_Assert( g_pxAdvBloomAccumRT, "Unable to create adv. bloom render target." );
	ClearTexture(g_pxAdvBloomAccumTexture, uScreenHeight / 2);
	ClearTexture(g_pxAdvBloomTempTexture, uScreenHeight / 2);

	g_xAdvBloomSourceTextureHandle				= g_pxAdvBloomEffect->GetParameterHandle( "g_xTexture" );
	g_xAdvBloomAccumTextureHandle				= g_pxAdvBloomEffect->GetParameterHandle( "g_xAccumTexture" );
	g_xAdvBloomDepthTextureHandle				= g_pxAdvBloomEffect->GetParameterHandle( "g_xDepthTexture" );
	g_xAdvBloomUVOffsetHandle					= g_pxAdvBloomEffect->GetParameterHandle( "g_xUVOffset" );
	g_xAdvBloomBlurHandle						= g_pxAdvBloomEffect->GetParameterHandle( "g_bBlur" );
	g_xAdvBloomExtractBrightBitsHandle			= g_pxAdvBloomEffect->GetParameterHandle( "g_bExtractBrightBits" );
	g_xAdvBloomSaturationHandle					= g_pxAdvBloomEffect->GetParameterHandle( "g_fSaturation" );
	g_xAdvBloomOutputColourHandle				= g_pxAdvBloomEffect->GetParameterHandle( "g_xOutputColour" );
	g_xAdvBloomInputThresholdHandle				= g_pxAdvBloomEffect->GetParameterHandle( "g_xInputThreshold" );
	g_xAdvBloomInputScaleHandle					= g_pxAdvBloomEffect->GetParameterHandle( "g_fInputScale" );
	g_xAdvBloomAccumulateHandle					= g_pxAdvBloomEffect->GetParameterHandle( "g_bAccumulate" );
	g_xAdvBloomAccumFadeHandle					= g_pxAdvBloomEffect->GetParameterHandle( "g_fAccumFade" );
	g_xAdvBloomExtractNearDepthOfFieldHandle	= g_pxAdvBloomEffect->GetParameterHandle( "g_bExtractNearDepthOfField" );
	g_xAdvBloomFocalDistancesHandle				= g_pxAdvBloomEffect->GetParameterHandle( "g_xFocalDistances" );
	g_xAdvBloomUVCorrectionHandle				= g_pxAdvBloomEffect->GetParameterHandle( "g_xUVCorrection" );

	//g_xAdvBloomSecondaryUVOfsHandle		= g_pxAdvBloomEffect->GetParameterHandle( "g_fSecondaryUVOffset" );

	// Colour map
	g_pxColourMapEffect = Asura_Xbox360_Effect_System::CreateEffectFromMemory( g_auFSFX_ColourMap);
	if( g_pxColourMapEffect )
	{
		g_xColourMapHandle = g_pxColourMapEffect->GetParameterHandle( "g_xColourMap" );
		g_xColourMapIntensityHandle = g_pxColourMapEffect->GetParameterHandle( "g_fIntensity" );
	}



	// Depth of Field
	g_pxDepthOfFieldEffect = Asura_Xbox360_Effect_System::CreateEffectFromMemory( g_auFSFX_SM30_DepthOfField);
	if (g_pxDepthOfFieldEffect)
	{																						   
		g_xDepthOfFieldBlurredTextureHandle = g_pxDepthOfFieldEffect->GetParameterHandle( "g_xBlurredTextureSampler" );
		g_xDepthOfFieldDepthTextureHandle   = g_pxDepthOfFieldEffect->GetParameterHandle( "g_xDepthTextureSampler" );
		g_xDepthOfFieldEffectStrengthHandle = g_pxDepthOfFieldEffect->GetParameterHandle( "g_fEffectStrength" );
		g_xDepthOfFieldFocalDistancesHandle = g_pxDepthOfFieldEffect->GetParameterHandle( "g_xFocalDistances" );
	}
	
	// FishEye
	g_pxFishEyeEffect = Asura_Xbox360_Effect_System::CreateEffectFromMemory( g_auFSFX_SM30_FishEye);
	if (g_pxFishEyeEffect)
	{		

		g_xFishEyeTextureHandle = g_pxFishEyeEffect->GetParameterHandle( "g_xTextureSampler" );
		//g_xFishEyeIntensityHandle   = g_pxFishEyeEffect->GetParameterHandle( "g_fIntensity" );
		g_xFishEyeFOVHandle = g_pxFishEyeEffect->GetParameterHandle( "g_fFOV" );
		g_xFishEyeMultiplierHandle = g_pxFishEyeEffect->GetParameterHandle( "g_fMult" );
		g_xFishEyeScaleHandle	= g_pxFishEyeEffect->GetParameterHandle( "g_xScale" );
		g_xOneOverTanFOV		= g_pxFishEyeEffect->GetParameterHandle( "g_fOneOverTanFOV" );
		g_xSinHalfFOV			= g_pxFishEyeEffect->GetParameterHandle( "g_fSinHalfFOV" );
		g_xTanHalfFOV			= g_pxFishEyeEffect->GetParameterHandle( "g_fTanHalfFOV" );
	}

	Asura_Xbox360_Graphics::GetDevice()->CreateVertexDeclaration( axFISHEYE_VERTEX_DECLARATION, &g_pxFishEye_VD);

	// Double Vision
	g_pxDoubleVisionEffect = Asura_Xbox360_Effect_System::CreateEffectFromMemory( g_auFSFX_SM30_DoubleVision );
	if (g_pxDoubleVisionEffect)
	{		
		g_xDoubleVisionInitialImageHandle = g_pxDoubleVisionEffect->GetParameterHandle( "g_xTextureSampler" );
		g_xDoubleVisionXOffsetHandle1 = g_pxDoubleVisionEffect->GetParameterHandle( "g_fXOffset1" );
		g_xDoubleVisionYOffsetHandle1 = g_pxDoubleVisionEffect->GetParameterHandle( "g_fYOffset1" );
		g_xDoubleVisionXOffsetHandle2 = g_pxDoubleVisionEffect->GetParameterHandle( "g_fXOffset2" );
		g_xDoubleVisionYOffsetHandle2 = g_pxDoubleVisionEffect->GetParameterHandle( "g_fYOffset2" );
	}

	Asura_Xbox360_Graphics::GetDevice()->CreateVertexDeclaration( axDOUBLEVISION_VERTEX_DECLARATION, &g_pxDoubleVision_VD);

	// Shared parameters

	FXLEffectPool* const pxPool = Asura_Xbox360_Effect_System::GetPool();
	if( pxPool )
	{
		const Asura_Xbox360_Effect_System::Handle xFSFXInitialImageHandle = pxPool->GetParameterHandle( "g_xInitialImage" );
		pxPool->SetSampler( xFSFXInitialImageHandle, Asura_Xbox360_Graphics::GetPostToneMapTexture() );
	}

	Asura_Xbox360_Graphics::GetDevice()->CreateVertexDeclaration( axFSFX_VERTEX_DECLARATION, &g_pxFSFX_VD );
	Asura_Assert( g_pxFSFX_VD, "Failed to create FSFX vertex declaration." );
}

////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_System::Platform_Reset()
//
// Resets the FSFX system on Xbox 360
//
// Parameters:		None
// Return value:	None
//
////////////////////////////////////////////////////////////////////////////////

void Asura_FSFX_System::Platform_Reset()
{
}

////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_System::Platform_Shutdown()
//
// Shuts down the FSFX system on Xbox 360
//
// Parameters:		None
// Return value:	None
//
////////////////////////////////////////////////////////////////////////////////

void Asura_FSFX_System::Platform_Shutdown()
{
	g_pxBloomRT->Release();
	g_pxBloomRT = NULL;

	g_pxBloomTexture->Release();
	g_pxBloomTexture = NULL;

	g_pxFSFX_VD->Release();
	g_pxFSFX_VD = NULL;
	g_pxFishEye_VD->Release();
	g_pxFishEye_VD = NULL;
	g_pxDoubleVision_VD->Release();
	g_pxDoubleVision_VD = NULL;

	g_pxRadialBlurTexture->Release();
	g_pxRadialBlurTexture = NULL;

	Asura_Xbox360_Effect_System::Destroy( g_pxFishEyeEffect );
	Asura_Xbox360_Effect_System::Destroy( g_pxRadialBlurEffect );
	Asura_Xbox360_Effect_System::Destroy( g_pxNoiseEffect );
	Asura_Xbox360_Effect_System::Destroy( g_pxGammaEffect );
	Asura_Xbox360_Effect_System::Destroy( g_pxDesatTintEffect );
	Asura_Xbox360_Effect_System::Destroy( g_pxBrightContrastEffect );
	Asura_Xbox360_Effect_System::Destroy( g_pxBloomEffect );

	g_pxFishEyeEffect = NULL;
	g_pxDoubleVisionEffect = NULL;
	g_pxRadialBlurEffect = NULL;
	g_pxNoiseEffect = NULL;
	g_pxGammaEffect = NULL;
	g_pxDesatTintEffect = NULL;
	g_pxBrightContrastEffect = NULL;
	g_pxBloomEffect = NULL;

	g_pxAdvBloomAccumRT->Release();
	g_pxAdvBloomAccumRT = NULL;

	g_pxAdvBloomAccumTexture->Release();
	g_pxAdvBloomAccumTexture = NULL;

	g_pxAdvBloomTempTexture->Release();
	g_pxAdvBloomTempTexture = NULL;

	Asura_Xbox360_Effect_System::Destroy( g_pxAdvBloomEffect );
	g_pxAdvBloomEffect = NULL;
}

void Asura_FSFX_System::Platform_BeginRender(void)
{
#if defined(ASURA_XBOX360_ENABLE_PIX)
	PIXBeginNamedEvent(D3DCOLOR_XRGB(0xFF, 0xFF, 0xFF), "FSFX");
#endif	//defined(ASURA_XBOX360_ENABLE_PIX)
}

void Asura_FSFX_System::Platform_EndRender(void)
{
#if defined(ASURA_XBOX360_ENABLE_PIX)
	PIXEndNamedEvent();
#endif	//defined(ASURA_XBOX360_ENABLE_PIX)
}


/******************************************************************************/
/* Asura_FSFX_Template Class Functions                                        */
/******************************************************************************/

////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_Template::Platform_GetPlatformFlag()
//
// Identifies the platform to the FSFX system
//
// Parameters:		None
// Return value:	One of the values in Asura_FSFX_Component::Platform
//
////////////////////////////////////////////////////////////////////////////////

int Asura_FSFX_Template::Platform_GetPlatformFlag()
{
	return Asura_FSFX_Component::FSFX_PLATFORM_XB360;
}

/******************************************************************************/
/* Asura_FSFX_Component_* Class Functions                                     */
/******************************************************************************/

////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_Component_BrightnessAndContrast::Platform_Render()
//
// Renders a brightness & contrast FSFX
//
// Parameters:		fIntensity - Intensity level
// Return value:	None
//
////////////////////////////////////////////////////////////////////////////////

void Asura_FSFX_Component_BrightnessAndContrast::Platform_Render( const float fIntensity )
{
	PIXBeginNamedEvent( D3DCOLOR_XRGB( 0xE0, 0xD0, 0xC0 ), "FSFX: Brightness and Contrast" );

	const float fBrightness = fIntensity * m_fBrightness / 100.0f;
	const float fContrast = fIntensity * m_fContrast / 100.0f;
	const float afCoeffs[] = { fBrightness - 0.5f * fContrast, fContrast + 1.0f };
	g_pxBrightContrastEffect->GetInterface()->SetVectorF( g_xBrightContrastCoeffsHandle, afCoeffs );

	FXLEffectPool* const pxPool = Asura_Xbox360_Effect_System::GetPool();
	const Asura_Xbox360_Effect_System::Handle xFSFXInitialImageHandle = pxPool->GetParameterHandle( "g_xInitialImage" );
	pxPool->SetSampler( xFSFXInitialImageHandle, Asura_Xbox360_Graphics::GetPostToneMapLinearTexture() );


	RenderFSFX( g_pxBrightContrastEffect, true, false );

	pxPool->SetSampler( xFSFXInitialImageHandle, Asura_Xbox360_Graphics::GetPostToneMapTexture() );


	PIXEndNamedEvent(); // FSFX
}

////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_Component_DesaturateAndTint::Platform_Render()
//
// Renders a desaturate & tint FSFX
//
// Parameters:		fIntensity - Intensity level
// Return value:	None
//
////////////////////////////////////////////////////////////////////////////////

void Asura_FSFX_Component_DesaturateAndTint::Platform_Render( const float fIntensity )
{
	PIXBeginNamedEvent( D3DCOLOR_XRGB( 0xE0, 0xD0, 0xC0 ), "FSFX: Desaturate and Tint" );

	const float afTint[] = { m_fIntensityR / 100.0f, m_fIntensityG / 100.0f, m_fIntensityB / 100.0f };
	g_pxDesatTintEffect->GetInterface()->SetVectorF( g_xDesatTintColourHandle, afTint );

	const float fStrength = m_fStrength * fIntensity / 100.0f;
	g_pxDesatTintEffect->GetInterface()->SetFloat( g_xDesatTintStrengthHandle, fStrength );

	FXLEffectPool* const pxPool = Asura_Xbox360_Effect_System::GetPool();
	const Asura_Xbox360_Effect_System::Handle xFSFXInitialImageHandle = pxPool->GetParameterHandle( "g_xInitialImage" );
	pxPool->SetSampler( xFSFXInitialImageHandle, Asura_Xbox360_Graphics::GetPostToneMapLinearTexture() );


	RenderFSFX( g_pxDesatTintEffect, true, false );

	pxPool->SetSampler( xFSFXInitialImageHandle, Asura_Xbox360_Graphics::GetPostToneMapTexture() );



	PIXEndNamedEvent(); // FSFX
}

////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_Component_Noise::Platform_Render()
//
// Renders a noise FSFX
//
// Parameters:		fIntensity - Intensity level
// Return value:	None
//
////////////////////////////////////////////////////////////////////////////////

void Asura_FSFX_Component_Noise::Platform_Render( const float fIntensity )
{
	PIXBeginNamedEvent( D3DCOLOR_XRGB( 0xE0, 0xD0, 0xC0 ), "FSFX: Noise" );
	ASURA_GPU_PROFILE_START(ASURA_GPUPROFILE_FSFX);

	const float fU = Asura_Random::GetFloat( 0.0f, 1.0f );
	const float fV = Asura_Random::GetFloat( 0.0f, 1.0f );

	const float fDeltaU = (Asura_Random::GetFloat( 0.0f, 1.0f ) <= 0.5f ? 1.0f : -1.0f) * static_cast< float >( m_uTextureTileX );
	const float fDeltaV = (Asura_Random::GetFloat( 0.0f, 1.0f ) <= 0.5f ? 1.0f : -1.0f) * static_cast< float >( m_uTextureTileY );

	g_pxNoiseEffect->SetTexture( g_xNoiseTextureHandle, m_iTextureID );

	// (AAM - 22.10.2007) For some reason, the effect is halved in strength on PC
	const float fEffectStrength = 0.5f * fIntensity * m_fAmount / 100.0f;
	g_pxNoiseEffect->GetInterface()->SetFloat( g_xNoiseColourHandle, fEffectStrength );

	Asura_Render::CurrentStates.RequestTranslucencyMode( ASURA_TRANSLUCENCY_UGH );

	g_pxNoiseEffect->Begin();
	g_pxNoiseEffect->Commit();

	Asura_Xbox360_Graphics::GetDevice()->SetVertexDeclaration( g_pxFSFX_VD );

	Asura_Xbox360_Graphics::GetDevice()->SetRenderState_Inline( D3DRS_HIGHPRECISIONBLENDENABLE,
																TRUE );

	float* pfVertices = NULL;
	if( SUCCEEDED( Asura_Xbox360_Graphics::GetDevice()->BeginVertices( D3DPT_RECTLIST, 3, uFSFX_VERTEX_SIZE, reinterpret_cast< void** >( &pfVertices ) ) ) )
	{
		// Top left XY
		*pfVertices++ = -1.0f;
		*pfVertices++ = 1.0f;

		// UV
		*pfVertices++ = fU;
		*pfVertices++ = fV;

		// Top right XY
		*pfVertices++ = 1.0f;
		*pfVertices++ = 1.0f;

		// UV
		*pfVertices++ = fU + fDeltaU;
		*pfVertices++ = fV;

		// Bottom left XY
		*pfVertices++ = -1.0f;
		*pfVertices++ = -1.0f;

		// UV
		*pfVertices++ = fU;
		*pfVertices++ = fV + fDeltaV;

		Asura_Xbox360_Graphics::GetDevice()->EndVertices();
	}

	Asura_Xbox360_Graphics::GetDevice()->SetRenderState_Inline( D3DRS_HIGHPRECISIONBLENDENABLE,
																FALSE );

	g_pxNoiseEffect->End();
	Asura_Xbox360_Graphics::GetDevice()->SetRenderState_Inline( D3DRS_ZENABLE,	TRUE );
	Asura_Render::CurrentStates.RequestZBufferWriteEnabled( true );


	ASURA_GPU_PROFILE_END(ASURA_GPUPROFILE_FSFX);
	PIXEndNamedEvent(); // FSFX
}

void Asura_FSFX_Component_GaussianBlur::Platform_Render( const float fIntensity )
{
}

////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_Component_RadialBlur::Platform_Render()
//
// Renders a radial blur FSFX
//
// Parameters:		fIntensity - Intensity level
// Return value:	None
//
////////////////////////////////////////////////////////////////////////////////

void Asura_FSFX_Component_RadialBlur::Platform_Render( const float fIntensity )
{
	SCOPEDPIXEVENT(( D3DCOLOR_XRGB( 0xE0, 0xD0, 0xC0 ), "FSFX: Radial Blur" ));

	// Resolve the current RT back out so we can read the initial colours
	Asura_Xbox360_Graphics::Resolve( Asura_Xbox360_Graphics::GetPostToneMapTexture() );

	ASURA_GPU_PROFILE_START(ASURA_GPUPROFILE_FSFX);

	Asura_Xbox360_Graphics::GetFullScreenVB().Bind();
	Asura_Xbox360_Graphics::GetDevice()->SetVertexDeclaration( Asura_Xbox360_Graphics::GetFullScreenVD() );

	Asura_Render::CurrentStates.RequestTranslucencyMode( ASURA_TRANSLUCENCY_OFF );

	g_pxRadialBlurEffect->Begin();

	// Set the sample weights for the pixel shader
	{
		float afSampleWeights[4];

		afSampleWeights[0] = 1.0f - 0.75f * fIntensity * m_fStrength / 100.0f;
		afSampleWeights[3] = 0.25f * (1.0f - afSampleWeights[0]);
		afSampleWeights[1] = 0.5f * (1.0f - afSampleWeights[0] - afSampleWeights[3]);
		afSampleWeights[2] = afSampleWeights[1];

		g_pxRadialBlurEffect->GetInterface()->SetScalarArrayF( g_xRadialBlurSampleWeightsHandle, afSampleWeights, 4 );
	}

	const float fBlurBufferHeight = 720.0f;

	// Horizontal pass
	{
		SCOPEDPIXEVENT(( D3DCOLOR_XRGB( 0xA8, 0x9C, 0x90 ), "Horizontal Blur" ));

		// Calculate vertex transform matrices
		{
			D3DXMATRIX axTransforms[4];

			// First transform is a simple scale and bias from [-1,1] space into [0,1]
			const D3DXVECTOR2 xZeroPoint5( 0.5f, 0.5f );
			D3DXMatrixTransformation2D( &axTransforms[0], NULL, 0.0f, &xZeroPoint5, NULL, 0.0f, &xZeroPoint5 );

			const float fSize = m_fSize / 4.0f;
			const float fCentreX = m_fCentreX / 100.0f;
			const float afScaleFactors[3] = { 1.0f, 3.0f, 5.0f };

			for( u_int u = 1; u < 4; ++u )
			{
				const D3DXVECTOR2 xScaleX( 1.0f - afScaleFactors[ u - 1 ] * fSize / fBlurBufferHeight, 1.0f );
				const D3DXVECTOR2 xTranslateX( (1.0f - xScaleX.x) * fCentreX, 0.0f );

				D3DXMatrixTransformation2D( &axTransforms[u], NULL, 0.0f, &xScaleX, NULL, 0.0f, &xTranslateX ); 
				D3DXMatrixMultiply( &axTransforms[u], &axTransforms[u], &axTransforms[0] );
			}
			for( u_int u = 0; u < 4; ++u )
			{
				axTransforms[u]._22 = -axTransforms[u].m[1][1];
			}

			g_pxRadialBlurEffect->GetInterface()->SetMatrixArrayF4x4( g_xRadialBlurVertexTransformsHandle, axTransforms[0], 4 );
		}

		// Use the bloom buffers
		g_pxRadialBlurEffect->GetInterface()->SetSampler( g_xRadialBlurTextureHandle, Asura_Xbox360_Graphics::GetPostToneMapTexture() );
		g_pxRadialBlurEffect->Commit();

		Asura_Xbox360_Graphics::GetDevice()->DrawVertices( D3DPT_RECTLIST, 0, 3 );
	}

	Asura_Xbox360_Graphics::GetDevice()->Resolve( D3DRESOLVE_RENDERTARGET0, NULL, g_pxRadialBlurTexture, NULL, 0, 0, NULL, 0.0f, 0, NULL );

	// Vertical pass
	{
		SCOPEDPIXEVENT(( D3DCOLOR_XRGB( 0xA8, 0x9C, 0x90 ), "Vertical Blur" ));

		// Calculate vertex transform matrices
		{
			D3DXMATRIX axTransforms[4];

			// First transform is a simple scale and bias from [-1,1] space into [0,1]
			const D3DXVECTOR2 xZeroPoint5( 0.5f, 0.5f );
			D3DXMatrixTransformation2D( &axTransforms[0], NULL, 0.0f, &xZeroPoint5, NULL, 0.0f, &xZeroPoint5 );

			const float fSize = m_fSize / 4.0f;
			const float fCentreY = m_fCentreY / 100.0f;
			const float afScaleFactors[3] = { 1.0f, 3.0f, 5.0f };

			for( u_int u = 1; u < 4; ++u )
			{
				const D3DXVECTOR2 xScaleY( 1.0f, 1.0f - afScaleFactors[ u - 1 ] * fSize / fBlurBufferHeight );
				const D3DXVECTOR2 xTranslateY( 0.0f, (1.0f - xScaleY.y) * fCentreY );

				D3DXMatrixTransformation2D( &axTransforms[u], NULL, 0.0f, &xScaleY, NULL, 0.0f, &xTranslateY ); 
				D3DXMatrixMultiply( &axTransforms[u], &axTransforms[u], &axTransforms[0] );
			}

			for( u_int u = 0; u < 4; ++u )
			{
				axTransforms[u]._22 = -axTransforms[u].m[1][1];
//				axTransforms[u]._41 += 1;
			}
			g_pxRadialBlurEffect->GetInterface()->SetMatrixArrayF4x4( g_xRadialBlurVertexTransformsHandle, axTransforms[0], 4 );
		}

		// Replace the final image entirely
		g_pxRadialBlurEffect->GetInterface()->SetSampler( g_xRadialBlurTextureHandle, g_pxRadialBlurTexture );
		g_pxRadialBlurEffect->Commit();

		Asura_Xbox360_Graphics::GetDevice()->DrawVertices( D3DPT_RECTLIST, 0, 3 );
	}

	g_pxRadialBlurEffect->End();

	ASURA_GPU_PROFILE_END(ASURA_GPUPROFILE_FSFX);
}

void Asura_FSFX_Component_DepthOfField::Platform_Render( const float fIntensity )
{
}

////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_Component_Bloom::Platform_Render()
//
// Renders a bloom FSFX
//
// Parameters:		fIntensity - Intensity level
// Return value:	None
//
////////////////////////////////////////////////////////////////////////////////

void Asura_FSFX_Component_Bloom::Platform_Render( const float fIntensity )
{
	PIXBeginNamedEvent( D3DCOLOR_XRGB( 0xE0, 0xD0, 0xC0 ), "FSFX: Bloom" );

	// Resolve the current RT back out so we can read the initial colours
	Asura_Xbox360_Graphics::Resolve( Asura_Xbox360_Graphics::GetPostToneMapTexture() );

	ASURA_GPU_PROFILE_START(ASURA_GPUPROFILE_FSFX);

	Asura_Xbox360_Graphics::GetFullScreenVB().Bind();
	Asura_Xbox360_Graphics::GetDevice()->SetVertexDeclaration( Asura_Xbox360_Graphics::GetFullScreenVD() );

	const float afTint[3] =
	{
        // (AAM - 14.01.2008) The PC bloom effect doesn't actually pass on the user params from the
		// FSFX, so we'll do the same here

		//m_fIntensityR * fIntensity / 100.0f,
		//m_fIntensityG * fIntensity / 100.0f,
		//m_fIntensityB * fIntensity / 100.0f,

		0.296875,
		0.59375,
		0.109375,
	};

	g_pxBloomEffect->GetInterface()->SetVectorF( g_xBloomTintHandle, afTint );

	const float fScale = 1.0f / (1.0f - 0.25f);
	g_pxBloomEffect->GetInterface()->SetFloat( g_xBloomScaleHandle, fScale );

	const float fBias = -0.25f / (1.0f - 0.25f);
	g_pxBloomEffect->GetInterface()->SetFloat( g_xBloomBiasHandle, fBias );

	const float fLevel = m_fThreshold * 0.75f / 100.0f;
	g_pxBloomEffect->GetInterface()->SetFloat( g_xBloomLevelHandle, fLevel );

	const float fScreenWidth = static_cast< float >( Asura_Viewport::GetWidth() );
	const float fScreenHeight = static_cast< float >( Asura_Viewport::GetHeight() );

	const float afRcpScreenSizes[] = { 1.0f / g_uBloomRTWidth, 1.0f / g_uBloomRTHeight,
		1.0f / fScreenWidth, 1.0f / fScreenHeight };
	g_pxBloomEffect->SetVector( g_xBloomRcpSizesHandle, afRcpScreenSizes );

	Asura_Render::CurrentStates.RequestTranslucencyMode( ASURA_TRANSLUCENCY_OFF );

	Asura_Xbox360_Graphics::GetDevice()->SetRenderTarget( 0, g_pxBloomRT );

	g_pxBloomEffect->Begin(0);
	g_pxBloomEffect->Commit();

	// Extract glowing parts of the source image
	{
		PIXBeginNamedEvent( D3DCOLOR_XRGB( 0xA8, 0x9C, 0x90 ), "Extract" );
		Asura_Xbox360_Graphics::GetDevice()->DrawVertices( D3DPT_RECTLIST, 0, 3 );
		PIXEndNamedEvent(); // Extract
	}

	Asura_Xbox360_Graphics::GetDevice()->Resolve( D3DRESOLVE_RENDERTARGET0, NULL, g_pxBloomTexture, NULL, 0, 0, NULL, 0.0f, 0, NULL );

	// Blur the glow horizontally
	{
		PIXBeginNamedEvent( D3DCOLOR_XRGB( 0xA8, 0x9C, 0x90 ), "Horizontal Blur" );

		g_pxBloomEffect->BeginPass(1);
		g_pxBloomEffect->Commit();
		Asura_Xbox360_Graphics::GetDevice()->DrawVertices( D3DPT_RECTLIST, 0, 3 );

		PIXEndNamedEvent(); // Horizontal Blur
	}

	Asura_Xbox360_Graphics::GetDevice()->Resolve( D3DRESOLVE_RENDERTARGET0, NULL, g_pxBloomTexture, NULL, 0, 0, NULL, 0.0f, 0, NULL );

	// Then blur it vertically
	{
		PIXBeginNamedEvent( D3DCOLOR_XRGB( 0xA8, 0x9C, 0x90 ), "Vertical Blur" );

		g_pxBloomEffect->BeginPass(2);
		g_pxBloomEffect->Commit();
		Asura_Xbox360_Graphics::GetDevice()->DrawVertices( D3DPT_RECTLIST, 0, 3 );

		PIXEndNamedEvent(); // Vertical Blur
	}

	Asura_Xbox360_Graphics::GetDevice()->Resolve( D3DRESOLVE_RENDERTARGET0, NULL, g_pxBloomTexture, NULL, 0, 0, NULL, 0.0f, 0, NULL );

	Asura_Xbox360_Graphics::GetDevice()->SetRenderTarget( 0, Asura_Xbox360_Graphics::GetPostToneMapRT() );

	// Finally, add it on top of the scene
	{
		PIXBeginNamedEvent( D3DCOLOR_XRGB( 0xA8, 0x9C, 0x90 ), "Apply" );

		g_pxBloomEffect->BeginPass(3);
		g_pxBloomEffect->Commit();

		// Need a different translucency mode for addsmooth blending
		D3DBLENDSTATE xOldBlendState;
		Asura_Xbox360_Graphics::GetDevice()->GetBlendState( 0, &xOldBlendState );

		{
			D3DBLENDSTATE xNewBlendState;

			xNewBlendState.SrcBlend = D3DBLEND_INVDESTCOLOR;
			xNewBlendState.BlendOp = D3DBLENDOP_ADD;
			xNewBlendState.DestBlend = D3DBLEND_ONE;
			xNewBlendState.SrcBlendAlpha = D3DBLEND_ZERO;
			xNewBlendState.BlendOpAlpha = D3DBLENDOP_ADD;
			xNewBlendState.DestBlendAlpha = D3DBLEND_ONE;

			Asura_Xbox360_Graphics::GetDevice()->SetBlendState( 0, xNewBlendState );
			Asura_Xbox360_Graphics::GetDevice()->SetRenderState_Inline( D3DRS_HIGHPRECISIONBLENDENABLE, TRUE );
		}

		Asura_Xbox360_Graphics::GetDevice()->DrawVertices( D3DPT_RECTLIST, 0, 3 );
		Asura_Xbox360_Graphics::GetDevice()->SetBlendState( 0, xOldBlendState );
		Asura_Xbox360_Graphics::GetDevice()->SetRenderState_Inline( D3DRS_HIGHPRECISIONBLENDENABLE, FALSE );

		PIXEndNamedEvent(); // Apply
	}

	g_pxBloomEffect->End();

	ASURA_GPU_PROFILE_END(ASURA_GPUPROFILE_FSFX);
	PIXEndNamedEvent(); // FSFX
}

////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_Component_Gamma::Platform_Render()
//
// Renders a gamma correction FSFX
//
// Parameters:		fIntensity - Intensity level
// Return value:	None
//
////////////////////////////////////////////////////////////////////////////////

void Asura_FSFX_Component_Gamma::Platform_Render( const float fIntensity )
{
	RenderGamma( 1.0f - fIntensity + fIntensity * m_fAmount,
		1.0f - fIntensity + fIntensity * m_fAmount,
		1.0f - fIntensity + fIntensity * m_fAmount );
}

////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_Component_RGBGamma::Platform_Render()
//
// Renders a gamma correction FSFX with separate colour channel control
//
// Parameters:		fIntensity - Intensity level
// Return value:	None
//
////////////////////////////////////////////////////////////////////////////////

void Asura_FSFX_Component_RGBGamma::Platform_Render( const float fIntensity )
{
	RenderGamma( 1.0f - fIntensity + fIntensity * m_fAmountR,
		1.0f - fIntensity + fIntensity * m_fAmountG,
		1.0f - fIntensity + fIntensity * m_fAmountB );
}

void Asura_FSFX_Component_Test::Platform_Render( const float fIntensity )
{
}


////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_Component_SM30_Bloom::Platform_Render()
//
// Renders the Advanced Bloom effect
// (Nothing really very advanced about it, it's just a lot more controllable
//  than the old one, and should look the same on 360 and PC)
//
// Parameters:		fIntensity - Intensity level
// Return value:	None
//
////////////////////////////////////////////////////////////////////////////////


void Asura_FSFX_Component_SM30_Bloom::Platform_Render( const float fIntensity )
{
	if ( fIntensity == 0.0f || g_pxBloomEffect == NULL )
	{
		return;
	}

	PIXBeginNamedEvent( D3DCOLOR_XRGB( 0xA8, 0x9C, 0x90 ), "FSFX: Advanced Bloom" );

	Direct3D_Surface* pxOldDepthStencilSurface = NULL;
	Asura_Xbox360_Graphics::GetDevice()->GetDepthStencilSurface(&pxOldDepthStencilSurface);
	Asura_Xbox360_Graphics::GetDevice()->SetDepthStencilSurface(NULL);

	Asura_Xbox360_Graphics::Resolve( Asura_Xbox360_Graphics::GetPostToneMapTexture() );

	ASURA_GPU_PROFILE_START(ASURA_GPUPROFILE_FSFX);

	// First pass - from the back buffer to the blur accumulation buffer, extracting the parts we want to bloom
	// If we're accumulating it, it's an additive pass, else alpha blending is disabled
	// ---------------------------------------------------------------------------------------------------------------
	const float fViewWidth		= static_cast<float> ( Asura_Viewport::GetWidth());
	const float fViewHeight		= static_cast<float> ( Asura_Viewport::GetHeight());
	const float fBufferWidth	= fViewWidth / 2.0f;
	const float fBufferHeight	= fViewHeight / 2.0f;

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

	FSFXVertex 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;

	// Set the RT, and clear any unused RTs
	Asura_Xbox360_Graphics::GetDevice()->SetRenderTarget(0, g_pxAdvBloomAccumRT);

	for(int i=1;i<4;i++)
	{
		Asura_Xbox360_Graphics::GetDevice()->SetRenderTarget(i, NULL);
	}

	Asura_Xbox360_Graphics::GetDevice()->SetVertexDeclaration( g_pxFSFX_VD );


	Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_OFF);

	{	
		float afUVOffsets[2] = {0.0f,0.0f};	
		g_pxAdvBloomEffect->GetInterface()->SetVectorF(g_xAdvBloomUVOffsetHandle, afUVOffsets);

		float afInputThreshold[4] = {m_fRBloomThreshold, m_fGBloomThreshold, m_fBBloomThreshold,0};
		g_pxAdvBloomEffect->GetInterface()->SetVectorF(g_xAdvBloomInputThresholdHandle,afInputThreshold);
		g_pxAdvBloomEffect->GetInterface()->SetFloat(g_xAdvBloomInputScaleHandle, m_fInputScale);

		// No blurring on this pass, but we want do subtract the input threshold and 'monochromize' it if desired
		g_pxAdvBloomEffect->GetInterface()->SetBool(g_xAdvBloomBlurHandle, false);
		g_pxAdvBloomEffect->GetInterface()->SetBool(g_xAdvBloomExtractBrightBitsHandle, true);
		g_pxAdvBloomEffect->GetInterface()->SetFloat(g_xAdvBloomSaturationHandle, m_fSaturation);
		g_pxAdvBloomEffect->GetInterface()->SetSampler(g_xAdvBloomSourceTextureHandle, Asura_Xbox360_Graphics::GetPostToneMapTexture());

		g_pxAdvBloomEffect->GetInterface()->SetBool(g_xAdvBloomAccumulateHandle, m_bAccumulate);

		if (m_bAccumulate)
		{
			g_pxAdvBloomEffect->GetInterface()->SetFloat(g_xAdvBloomAccumFadeHandle, 1.0f-m_fAccumFade);
			g_pxAdvBloomEffect->GetInterface()->SetSampler(g_xAdvBloomAccumTextureHandle, g_pxAdvBloomAccumTexture);			
		}

		const float afUVCorrection[] = { 0.5f / fViewWidth, 0.5f / fViewHeight };
		g_pxAdvBloomEffect->SetVector( g_xAdvBloomUVCorrectionHandle, afUVCorrection );

		// If we're accumulating the bloom, we need to sample from a 2nd texture, to pick up the previous frame's bloom
		g_pxAdvBloomEffect->Begin(0);
		g_pxAdvBloomEffect->Commit();
		Asura_Xbox360_Graphics::GetDevice()->DrawVerticesUP(D3DPT_TRIANGLESTRIP ,4, axVerts, sizeof(FSFXVertex));
		g_pxAdvBloomEffect->End();
	}

	// Remember to resolve it!
	Asura_Xbox360_Graphics::GetDevice()->Resolve( D3DRESOLVE_RENDERTARGET0, NULL, g_pxAdvBloomAccumTexture, NULL, 0, 0, NULL, 0.0f, 0, NULL );

	// Blur passes - From the accum buffer to the temp buffer, and back
	// ---------------------------------------------------------------------------------------------------------------

	// Update the UVs
	fHalfTexelU = 0.5f/fBufferWidth;
	fHalfTexelV = 0.5f/fBufferHeight;

	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;

	for (int iPass = 0; iPass<m_iBlurPasses; iPass++)
	{
		for (int iDir = 0; iDir<2; iDir++)
		{
			if (iDir==0)
			{
				// Horiz blur
				float afUVOffsets[2] = {0.0025f*m_fBlurRadius,0.0f};
				g_pxAdvBloomEffect->GetInterface()->SetVectorF(g_xAdvBloomUVOffsetHandle, afUVOffsets);
			}
			else
			{
				// Vert blur
				float afUVOffsets[2] = {0.0f,0.0025f*m_fBlurRadius};					
				g_pxAdvBloomEffect->GetInterface()->SetVectorF(g_xAdvBloomUVOffsetHandle, afUVOffsets);				
			}

			float afOutputColour[4] = {1.0f,1.0f,1.0f,1.0f};
			g_pxAdvBloomEffect->GetInterface()->SetSampler(g_xAdvBloomSourceTextureHandle, g_pxAdvBloomAccumTexture);
			g_pxAdvBloomEffect->GetInterface()->SetVectorF(g_xAdvBloomOutputColourHandle, afOutputColour);				
			g_pxAdvBloomEffect->GetInterface()->SetBool(g_xAdvBloomBlurHandle, true);
			g_pxAdvBloomEffect->GetInterface()->SetBool(g_xAdvBloomExtractBrightBitsHandle, false);

			// Draw it
			g_pxAdvBloomEffect->Begin(0);
			g_pxAdvBloomEffect->Commit();
			Asura_Xbox360_Graphics::GetDevice()->DrawVerticesUP(D3DPT_TRIANGLESTRIP ,4, axVerts, sizeof(FSFXVertex));
			g_pxAdvBloomEffect->End();

			// Remember to resolve it!
			Asura_Xbox360_Graphics::GetDevice()->Resolve( D3DRESOLVE_RENDERTARGET0, NULL, g_pxAdvBloomAccumTexture, NULL, 0, 0, NULL, 0.0f, 0, NULL );
		}
	}

	Asura_Xbox360_Graphics::GetDevice()->SetDepthStencilSurface(pxOldDepthStencilSurface);
	pxOldDepthStencilSurface->Release();

	// Final pass - add the bloom to the final render
	// ---------------------------------------------------------------------------------------------------------------
	Asura_Xbox360_Graphics::GetDevice()->SetRenderTarget( 0, Asura_Xbox360_Graphics::GetPostToneMapRT() );
	Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_GLOWING);

	Asura_Xbox360_Graphics::GetDevice()->SetRenderState_Inline( D3DRS_HIGHPRECISIONBLENDENABLE,
																TRUE );

	{
		float afUVOffsets[2] = {0.0f, 0.0f};
		float afOutputColour[4] = {m_fROutputCol * fIntensity, m_fGOutputCol * fIntensity, m_fBOutputCol * fIntensity,1};
		g_pxAdvBloomEffect->GetInterface()->SetVectorF(g_xAdvBloomUVOffsetHandle, afUVOffsets);
		g_pxAdvBloomEffect->GetInterface()->SetSampler(g_xAdvBloomSourceTextureHandle, g_pxAdvBloomAccumTexture);
		g_pxAdvBloomEffect->GetInterface()->SetVectorF(g_xAdvBloomOutputColourHandle, afOutputColour);				
		g_pxAdvBloomEffect->GetInterface()->SetBool(g_xAdvBloomBlurHandle, false);
		g_pxAdvBloomEffect->GetInterface()->SetBool(g_xAdvBloomExtractBrightBitsHandle, false);

		// Draw it
		g_pxAdvBloomEffect->Begin(0);
		g_pxAdvBloomEffect->Commit();
		Asura_Xbox360_Graphics::GetDevice()->DrawVerticesUP(D3DPT_TRIANGLESTRIP ,4, axVerts, sizeof(FSFXVertex));
		g_pxAdvBloomEffect->End();
	}

	Asura_Xbox360_Graphics::GetDevice()->SetRenderState_Inline( D3DRS_HIGHPRECISIONBLENDENABLE,
																FALSE );

	Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_OFF);

	ASURA_GPU_PROFILE_END(ASURA_GPUPROFILE_FSFX);
	PIXEndNamedEvent();
}






// Function used to create a blurred copy of the back buffer, which can be used by HUD effects
// (In particular, SS2's bloodsplats, damage indicator, and weapon zoom)
// --------------------------------------------------------------------------------------------------

void Asura_Xbox360_FSFX::UpdateBlurredBuffer(int iBlurPasses, float fBlurRadius, float fSaturation, bool bDepthOfFieldMode,  float fDist0, float fDist1, float fBleedScale)
{
	Asura_Xbox360_Graphics::Resolve( Asura_Xbox360_Graphics::GetPostToneMapTexture() );

	// First pass - from the back buffer to the blur accumulation buffer, extracting the parts we want to bloom
	// If we're accumulating it, it's an additive pass, else alpha blending is disabled
	const float fViewWidth		= static_cast<float> ( Asura_Viewport::GetWidth());
	const float fViewHeight		= static_cast<float> ( Asura_Viewport::GetHeight());
	const float fBufferWidth	= fViewWidth / 2;
	const float fBufferHeight	= fViewHeight / 2;

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

	FSFXVertex 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;

	// Set the RT, and clear any unused RTs
	Asura_Xbox360_Graphics::GetDevice()->SetRenderTarget(0, g_pxAdvBloomAccumRT);

	for(int i=1;i<4;i++)
	{
		Asura_Xbox360_Graphics::GetDevice()->SetRenderTarget(i, NULL);
	}

	Asura_Xbox360_Graphics::GetDevice()->SetVertexDeclaration( g_pxFSFX_VD );


	Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_OFF);

	{	
		float afOutputColour[4] = {1.0f,1.0f,1.0f,1.0f};
		g_pxAdvBloomEffect->GetInterface()->SetVectorF(g_xAdvBloomOutputColourHandle, afOutputColour);				

		float afUVOffsets[2] = {0.0f,0.0f};	
		g_pxAdvBloomEffect->GetInterface()->SetVectorF(g_xAdvBloomUVOffsetHandle, afUVOffsets);

		float afInputThreshold[4] = {0,0,0,0};
		g_pxAdvBloomEffect->GetInterface()->SetVectorF(g_xAdvBloomInputThresholdHandle,afInputThreshold);
		g_pxAdvBloomEffect->GetInterface()->SetFloat(g_xAdvBloomInputScaleHandle, 1.0f);

		// No blurring on this pass, but we want do subtract the input threshold and 'monochromize' it if desired
		g_pxAdvBloomEffect->GetInterface()->SetBool(g_xAdvBloomBlurHandle, false);

		g_pxAdvBloomEffect->GetInterface()->SetBool(g_xAdvBloomExtractNearDepthOfFieldHandle, bDepthOfFieldMode);		
		
		if (bDepthOfFieldMode)
		{
			g_pxAdvBloomEffect->GetInterface()->SetSampler(g_xAdvBloomDepthTextureHandle, Asura_Xbox360_Graphics::GetDepthMtlTexture());

			float afFocalDistances[4] = {fDist0, fDist1, fBleedScale, 1};
			g_pxAdvBloomEffect->GetInterface()->SetVectorF(g_xAdvBloomFocalDistancesHandle, afFocalDistances);
		}

		if (fSaturation<1.0f)
		{		
			g_pxAdvBloomEffect->GetInterface()->SetBool(g_xAdvBloomExtractBrightBitsHandle, true);
			g_pxAdvBloomEffect->GetInterface()->SetFloat(g_xAdvBloomSaturationHandle, fSaturation);
		}
		else
		{
			g_pxAdvBloomEffect->GetInterface()->SetBool(g_xAdvBloomExtractBrightBitsHandle, false);
		}

		g_pxAdvBloomEffect->GetInterface()->SetSampler(g_xAdvBloomSourceTextureHandle, Asura_Xbox360_Graphics::GetPostToneMapTexture());
		g_pxAdvBloomEffect->GetInterface()->SetBool(g_xAdvBloomAccumulateHandle, false);

		g_pxAdvBloomEffect->Begin(0);
		g_pxAdvBloomEffect->Commit();
		Asura_Xbox360_Graphics::GetDevice()->DrawVerticesUP(D3DPT_TRIANGLESTRIP ,4, axVerts, sizeof(FSFXVertex));
		g_pxAdvBloomEffect->End();

		g_pxAdvBloomEffect->GetInterface()->SetBool(g_xAdvBloomExtractNearDepthOfFieldHandle, false);
	}

	// Remember to resolve it!
	Asura_Xbox360_Graphics::GetDevice()->Resolve( D3DRESOLVE_RENDERTARGET0, NULL, g_pxAdvBloomTempTexture, NULL, 0, 0, NULL, 0.0f, 0, NULL );

	// Blur passes - From the accum buffer to the temp buffer, and back
	// ---------------------------------------------------------------------------------------------------------------

	// Update the UVs
	fHalfTexelU = 0.5f/fBufferWidth;
	fHalfTexelV = 0.5f/fBufferHeight;

	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;

	for (int iPass = 0; iPass<iBlurPasses; iPass++)
	{
		for (int iDir = 0; iDir<2; iDir++)
		{
			if (iDir==0)
			{
				// Horiz blur
				float afUVOffsets[2] = {0.0025f*fBlurRadius,0.0f};
				g_pxAdvBloomEffect->GetInterface()->SetVectorF(g_xAdvBloomUVOffsetHandle, afUVOffsets);
			}
			else
			{
				// Vert blur
				float afUVOffsets[2] = {0.0f,0.0025f*fBlurRadius};					
				g_pxAdvBloomEffect->GetInterface()->SetVectorF(g_xAdvBloomUVOffsetHandle, afUVOffsets);				
			}

			float afOutputColour[4] = {1.0f,1.0f,1.0f,1.0f};
			g_pxAdvBloomEffect->GetInterface()->SetSampler(g_xAdvBloomSourceTextureHandle, g_pxAdvBloomTempTexture);
			g_pxAdvBloomEffect->GetInterface()->SetVectorF(g_xAdvBloomOutputColourHandle, afOutputColour);				
			g_pxAdvBloomEffect->GetInterface()->SetBool(g_xAdvBloomBlurHandle, true);
			g_pxAdvBloomEffect->GetInterface()->SetBool(g_xAdvBloomExtractBrightBitsHandle, false);

			// Draw it
			g_pxAdvBloomEffect->Begin(0);
			g_pxAdvBloomEffect->Commit();
			Asura_Xbox360_Graphics::GetDevice()->DrawVerticesUP(D3DPT_TRIANGLESTRIP ,4, axVerts, sizeof(FSFXVertex));
			g_pxAdvBloomEffect->End();

			// Remember to resolve it!
			Asura_Xbox360_Graphics::GetDevice()->Resolve( D3DRESOLVE_RENDERTARGET0, NULL, g_pxAdvBloomTempTexture, NULL, 0, 0, NULL, 0.0f, 0, NULL );
		}
	}


	Asura_Xbox360_Graphics::GetDevice()->SetRenderTarget( 0, Asura_Xbox360_Graphics::GetPostToneMapRT() );
	Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_NORMAL);

}



Direct3D_Texture *Asura_Xbox360_FSFX::GetBlurredBuffer(void)
{
	return g_pxAdvBloomTempTexture;
}

////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_Component_ColourMap::Platform_Render()
//
// Renders the colour map FSFX component
//
// Parameters:		fIntensity - Effect intensity level [0,1]
// Values:			None
//
////////////////////////////////////////////////////////////////////////////////

void Asura_FSFX_Component_ColourMap::Platform_Render( const float fIntensity )
{
	if( !g_pxColourMapEffect ) return;

	SCOPEDPIXEVENT(( 0xFFE0D0C0, "FSFX: Colour Map" ));

	g_pxColourMapEffect->SetTexture( g_xColourMapHandle, m_iColourMapIndex );
	g_pxColourMapEffect->SetFloat( g_xColourMapIntensityHandle, fIntensity );

	RenderFSFX( g_pxColourMapEffect );
}



////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_Component_SM30_DepthOfField::Platform_Render()
//
// Renders the depth-of-field FSFX component
//
// Parameters:		fIntensity - Effect intensity level [0,1]
// Values:			None
//
////////////////////////////////////////////////////////////////////////////////

void Asura_FSFX_Component_SM30_DepthOfField::Platform_Render( const float fIntensity )
{
	if( !g_pxDepthOfFieldEffect ) return;

	SCOPEDPIXEVENT(( 0xFFE0D0C0, "FSFX: Depth of Field" ));

	Direct3D_Surface* pxOldDepthStencilSurface = NULL;
	Asura_Xbox360_Graphics::GetDevice()->GetDepthStencilSurface(&pxOldDepthStencilSurface);
	Asura_Xbox360_Graphics::GetDevice()->SetDepthStencilSurface(NULL);

	Asura_Xbox360_FSFX::UpdateBlurredBuffer(m_iBlurPasses, m_fBlurRadius, 1.0f-m_fBlurDesaturate, true, m_afDistances[0], m_afDistances[1], m_fBleedScale);

	Asura_Xbox360_Graphics::GetDevice()->SetDepthStencilSurface(pxOldDepthStencilSurface);
	pxOldDepthStencilSurface->Release();

	g_pxDepthOfFieldEffect->SetTexture( g_xDepthOfFieldBlurredTextureHandle, Asura_Xbox360_FSFX::GetBlurredBuffer());
	g_pxDepthOfFieldEffect->SetTexture( g_xDepthOfFieldDepthTextureHandle, Asura_Xbox360_Graphics::GetDepthMtlTexture());
	g_pxDepthOfFieldEffect->SetVector( g_xDepthOfFieldFocalDistancesHandle, m_afDistances);
	g_pxDepthOfFieldEffect->SetFloat( g_xDepthOfFieldEffectStrengthHandle, fIntensity);

	Asura_Render::CurrentStates.RequestTranslucencyMode( ASURA_TRANSLUCENCY_NORMAL );
	RenderFSFX( g_pxDepthOfFieldEffect, false );
	Asura_Render::CurrentStates.RequestTranslucencyMode( ASURA_TRANSLUCENCY_OFF );
}


////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_Component_SM30_FishEye::Platform_Render()
//
// Renders the depth-of-field FSFX component
//
// Parameters:		fIntensity - Effect intensity level [0,1]
// Values:			None
//
////////////////////////////////////////////////////////////////////////////////
void Asura_FSFX_Component_SM30_FishEye::Platform_Render( const float fIntensity )
{
	Asura_Xbox360_Effect* const pxEffect = g_pxFishEyeEffect;
	if( !pxEffect ) return;

	SCOPEDPIXEVENT(( D3DCOLOR_XRGB( 0xFF, 0xFF, 0xFF ), "FSFX: FishEye"));

	// Resolve the current RT back out so we can read the initial colours
	Asura_Xbox360_Graphics::Resolve( Asura_Xbox360_Graphics::GetPostToneMapTexture() );	// Setup

	ASURA_GPU_PROFILE_START( ASURA_GPUPROFILE_FSFX );

	pxEffect->SetTexture( g_xFishEyeTextureHandle, Asura_Xbox360_Graphics::GetPostToneMapTexture() );

	float fDynamicIntensity = fIntensity;
	if ( m_uFlags & DynamicSine )
	{
		// Calculate sine value and clip
		const float fTime = Asura_Timers::GetLocalScaledTime();
		const float fSineClipped = Asura_Maths::Max( m_fSineClip, Asura_Maths::Sine( fTime * m_fSpeed ) / 2.0f + 0.5f );

		// Work out max value after clipping
		float fScaleValue = 1.0f;
		if ( m_fSineClip != 1.0f )
		{
			fScaleValue = 1.0f / ( 1.0f - m_fSineClip );
		}

		// Normalise sine back up to fill 0 to 1 range
		const float fParameter = ( fSineClipped - m_fSineClip ) * fScaleValue;

		// Lerp and multiply by intensity
		fDynamicIntensity *= Asura_Maths::Lerp( m_fMinMultiplier, m_fMaxMultiplier, fParameter );
	}

	// makes little sense to alpha out effect ?
//	pxEffect->SetFloat( g_xFishEyeIntensityHandle, fIntensity );
//	pxEffect->SetFloat( g_xFishEyeIntensityHandle, 1.0f );
	pxEffect->SetFloat( g_xFishEyeFOVHandle, m_fFov*0.5f);
	pxEffect->SetFloat( g_xFishEyeMultiplierHandle, m_fMultiplier * fDynamicIntensity);

	pxEffect->SetFloat( g_xOneOverTanFOV, 1.0f / tanf(m_fFov * 0.5f) );
	pxEffect->SetFloat( g_xSinHalfFOV, sinf( m_fFov * 0.5f * 0.5f ) );
	pxEffect->SetFloat( g_xTanHalfFOV, tanf( m_fFov * 0.5f * 0.5f ) );


	Asura_Render::CurrentStates.RequestAlphaTest( false );
	Asura_Render::CurrentStates.RequestCullMode( ASURA_CULLMODE_NONE );
	Asura_Render::CurrentStates.RequestTranslucencyMode( ASURA_TRANSLUCENCY_NORMAL );
	Asura_Render::CurrentStates.RequestZBufferEnabled( false );

	Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_HIGHPRECISIONBLENDENABLE, TRUE);
	Asura_Xbox360_Graphics::GetDevice()->SetVertexDeclaration( g_pxFishEye_VD );

	const float fWidth = static_cast< float >( Asura_Viewport::GetWidth() );
	const float fHeight = static_cast< float >( Asura_Viewport::GetHeight() );

	FXLVECTOR xScale;
	if (fWidth > fHeight)
	{
		xScale.x = m_fXScale;
		xScale.y = m_fYScale * fHeight / fWidth;
	} 
	else 
	{
		xScale.x = m_fXScale;
		xScale.y = m_fYScale * fHeight / fWidth;
	}
	xScale.z = 1.0f / xScale.x;
	xScale.w = 1.0f / xScale.y;
	pxEffect->SetVector( g_xFishEyeScaleHandle, xScale );

	const Asura_ViewingArea *pxViewingArea = Asura_Camera::GetViewingArea();
	const float fSqrt2 = 1.0f / 1.4142135623730950488016887242097f; // 1.0f / sqrt(2)

	float fPosLeft = -1.0f + pxViewingArea->m_fXOffset * 2.0f;
	float fPosRight = fPosLeft + pxViewingArea->m_fWidth * 2.0f;
	float fPosBottom = -1.0f + pxViewingArea->m_fYOffset * 2.0f;
	float fPosTop = fPosBottom + pxViewingArea->m_fHeight * 2.0f;
	float fUVLeft = -fSqrt2 + pxViewingArea->m_fXOffset * 2.0f * fSqrt2;
	float fUVRight = fUVLeft + pxViewingArea->m_fWidth * 2.0f * fSqrt2;
	float fUVBottom = -fSqrt2 + pxViewingArea->m_fYOffset * 2.0f * fSqrt2;
	float fUVTop = fUVBottom + pxViewingArea->m_fHeight * 2.0f * fSqrt2;
	const FishEyeVertex axVerts[] =
	{
		{ fPosLeft,  fPosTop, 0.0f, 1.0f,		fUVLeft, fUVBottom },
		{ fPosRight, fPosTop, 0.0f, 1.0f,		fUVRight, fUVBottom },
		{ fPosRight, fPosBottom, 0.0f, 1.0f,	fUVRight,  fUVTop },
		{ fPosLeft, fPosBottom, 0.0f, 1.0f,		fUVLeft,  fUVTop },
	};

	Asura_Xbox360_Graphics::GetDevice()->SetStreamSource(0, NULL, 0, sizeof( FishEyeVertex ));

	pxEffect->Begin(0, m_eType);

	pxEffect->Commit();

	Asura_Xbox360_Graphics::GetDevice()->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, axVerts, sizeof( FishEyeVertex ) );

	pxEffect->End();

	////// Finished
	Asura_Render::CurrentStates.RequestZBufferEnabled(true);
	Asura_Render::CurrentStates.RequestZBufferWriteEnabled(true);

	Asura_Render::CurrentStates.RequestZBufferCompareMode(ASURA_ZBUFFERCMP_LESSEQUAL);

	Asura_Render::ApplyCameraSettings();
	Asura_Xbox360_Graphics::GetDevice()->SetRenderState( D3DRS_HIGHPRECISIONBLENDENABLE, FALSE);

	ASURA_GPU_PROFILE_END( ASURA_GPUPROFILE_FSFX );
}

void Asura_FSFX_Component_SM30_FishEye::Platform_Initialise()
{

}
void Asura_FSFX_Component_SM30_FishEye::Platform_Reset()
{

}
void Asura_FSFX_Component_SM30_FishEye::Platform_Shutdown()
{

}

////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_Component_SM30_DoubleVision::Platform_Render()
//
// Renders the double vision FSFX component
//
// Parameters:		fIntensity - Effect intensity level [0,1]
// Values:			None
//
////////////////////////////////////////////////////////////////////////////////

void Asura_FSFX_Component_SM30_DoubleVision::Platform_Render( const float fIntensity )
{
	Asura_Xbox360_Effect* const pxEffect = g_pxDoubleVisionEffect;
	if( !pxEffect ) return;
	SCOPEDPIXEVENT(( D3DCOLOR_XRGB( 0xFF, 0xFF, 0xFF ), "FSFX: Double Vision"));

	Asura_Xbox360_Graphics::Resolve( Asura_Xbox360_Graphics::GetPostToneMapTexture() );

	ASURA_GPU_PROFILE_START( ASURA_GPUPROFILE_FSFX );

	const float fTime = Asura_Timers::GetLocalScaledTime();

	// Interpolate from zero to set parameters
	const float fXOffset1 = m_fOrigXOffset1 *  fIntensity;
	const float fYOffset1 = m_fOrigYOffset1 *  fIntensity;
	const float fXScale1 = m_fOrigXScale1 *  fIntensity;
	const float fYScale1 = m_fOrigYScale1 *  fIntensity;
	const float fXOffset2 = m_fOrigXOffset2 *  fIntensity;
	const float fYOffset2 = m_fOrigYOffset2 *  fIntensity;
	const float fXScale2 = m_fOrigXScale2 *  fIntensity;
	const float fYScale2 = m_fOrigYScale2 *  fIntensity;

	// Setup
	pxEffect->SetTexture( g_xDoubleVisionInitialImageHandle, Asura_Xbox360_Graphics::GetPostToneMapTexture() );

	Asura_Render::AllowFullScreenRendering();

	Asura_Render::CurrentStates.RequestAlphaTest( false );
	Asura_Render::CurrentStates.RequestCullMode( ASURA_CULLMODE_NONE );
	Asura_Render::CurrentStates.RequestTranslucencyMode( ASURA_TRANSLUCENCY_NORMAL );
	Asura_Render::CurrentStates.RequestZBufferEnabled( false );

	Asura_Xbox360_Graphics::GetDevice()->SetVertexDeclaration( g_pxDoubleVision_VD );

	const float fXMultiplier = 1.0f / 100.0f; 
	const float fYMultiplier = 1.0f / 100.0f;

	// Apply phase and speed scale to time
	const float fTime1 = fTime * m_fSpeed1 + m_fPhase1;
	const float fTime2 = fTime * m_fSpeed2 + m_fPhase2;

	float fXDist1;
	float fYDist1;
	float fXDist2;
	float fYDist2;

	Asura_Maths::SinCos( fTime1, fXDist1, fYDist1 );
	Asura_Maths::SinCos( fTime2, fXDist2, fYDist2 );
	fXDist1 *= fXScale1;
	fYDist1 *= fYScale1;
	fXDist2 *= fXScale2;
	fYDist2 *= fYScale2;

	const float fXTotalOffset1 = (fXOffset1 + fXDist1) * fXMultiplier;
	const float fYTotalOffset1 = (fYOffset1 + fYDist1) * fYMultiplier;
	const float fXTotalOffset2 = (fXOffset2 + fXDist2) * fXMultiplier;
	const float fYTotalOffset2 = (fYOffset2 + fYDist2) * fYMultiplier;

	const float fXMaxOffset = Asura_Maths::Max( Asura_Maths::Abs(fXOffset1) + Asura_Maths::Abs(fXDist1) , Asura_Maths::Abs(fXOffset2) + Asura_Maths::Abs(fXDist2) ) * fXMultiplier;
	const float fYMaxOffset = Asura_Maths::Max( Asura_Maths::Abs(fYOffset1) + Asura_Maths::Abs(fYDist1) , Asura_Maths::Abs(fYOffset2) + Asura_Maths::Abs(fYDist2) ) * fYMultiplier;
	const float fXUVScale = 1.0f / (1.0f + fXMaxOffset );
	const float fYUVScale = 1.0f / (1.0f + fYMaxOffset );

	pxEffect->SetFloat( g_xDoubleVisionXOffsetHandle1, fXTotalOffset1 );
	pxEffect->SetFloat( g_xDoubleVisionYOffsetHandle1, fYTotalOffset1 );
	pxEffect->SetFloat( g_xDoubleVisionXOffsetHandle2, fXTotalOffset2 );
	pxEffect->SetFloat( g_xDoubleVisionYOffsetHandle2, fYTotalOffset2 );
	
	float fPosLeft = -1.0f;
	float fPosRight = 1.0f;
	float fPosTop = -1.0f;
	float fPosBottom = 1.0f;
	const float fUVLeft = 1.0f - fXUVScale;
	const float fUVRight = fXUVScale;
	const float fUVTop = 1.0f - fYUVScale;
	const float fUVBottom = fYUVScale;
	const DoubleVisionVertex axVerts[] =
	{
		{ fPosLeft,  fPosTop, 0.0f, 1.0f,		fUVLeft, fUVBottom },
		{ fPosRight, fPosTop, 0.0f, 1.0f,		fUVRight, fUVBottom },
		{ fPosRight, fPosBottom, 0.0f, 1.0f,	fUVRight,  fUVTop },
		{ fPosLeft, fPosBottom, 0.0f, 1.0f,		fUVLeft,  fUVTop },
	};

	Asura_Xbox360_Graphics::GetDevice()->SetStreamSource(0, NULL, 0, sizeof( DoubleVisionVertex ));

	pxEffect->Begin();
	pxEffect->Commit();
	{
		Asura_Xbox360_Graphics::GetDevice()->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, axVerts, sizeof( DoubleVisionVertex ) );
	}
	pxEffect->End();

	// Reset this parameter to NULL since the texture is in the default pool (for device resets)
	pxEffect->SetTexture( g_xDoubleVisionInitialImageHandle, NULL );

	////// Finished
	Asura_Render::CurrentStates.RequestZBufferEnabled(true);
	Asura_Render::CurrentStates.RequestZBufferWriteEnabled(true);

	Asura_Render::CurrentStates.RequestZBufferCompareMode(ASURA_ZBUFFERCMP_LESSEQUAL);
	Asura_Render::ApplyCameraSettings();

	ASURA_GPU_PROFILE_END( ASURA_GPUPROFILE_FSFX );
}

void Asura_FSFX_Component_SM30_DoubleVision::Platform_Initialise()
{
}

void Asura_FSFX_Component_SM30_DoubleVision::Platform_Reset()
{
}

void Asura_FSFX_Component_SM30_DoubleVision::Platform_Shutdown()
{
}



////////////////////////////////////////////////////////////////////////////////
//
// Asura_FSFX_Component_SM30_MotionBlur::Platform_Render()
//
// Renders the motion blur FSFX component
//
// Parameters:		fIntensity - Effect intensity level [0,1]
// Values:			None
//
////////////////////////////////////////////////////////////////////////////////

void Asura_FSFX_Component_SM30_MotionBlur::Platform_Render( const float fIntensity )
{
}

void Asura_FSFX_Component_SM30_MotionBlur::Platform_Initialise()
{
}

void Asura_FSFX_Component_SM30_MotionBlur::Platform_Reset()
{
}

void Asura_FSFX_Component_SM30_MotionBlur::Platform_Shutdown()
{
}


#endif // defined ASURA_USE_FSFX
