//*******************************************************************
//
// File: Asura_PlatformFSFX_SM30_DepthOfField.cpp        
//
// Created: 2 Mar 2006
//
// Description: 
//
//*******************************************************************

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

#if defined( ASURA_USE_FSFX)

#ifdef 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.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"

#include "FSFX/Asura_Platform_FSFX_SM30.h"

// other libraries
#include "SpecialFX/Asura_Glow_System.h"

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

Asura_Direct3D_RenderTarget* g_apxBlurBuffers[2]			= {NULL, NULL};

void Asura_FSFX_Component_SM30_DepthOfField::Platform_Initialise()
{
	for(int i=0;i<2;i++)
	{	
		g_apxBlurBuffers[i]= NULL;
	}	
}



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


void Asura_FSFX_Component_SM30_DepthOfField::Platform_Shutdown()
{
	for(int i=0;i<2;i++)
	{	
		if (g_apxBlurBuffers[i])
		{		
			g_apxBlurBuffers[i]->MarkAsUnused();
			g_apxBlurBuffers[i]= NULL;
		}
	}	
}


void Asura_FSFX_Component_SM30_DepthOfField::Platform_Render( const float fIntensity )
{

	HRESULT xResult = 0;
	(void) xResult;		// frig to get rid of warnings when asserts are disabled...

	if ( fIntensity == 0.0f || Asura_Platform_FSFX_SM30::g_pxDepthOfFieldEffect == NULL )
	{
		return;
	}

	SCOPEDPIXEVENT(( 0xFFA89C90, L"FSFX: SM3.0 Depth of Field" ));

	Direct3D_Surface* pxOldRenderTargetDepth = NULL;
	Asura_Direct3D::D3DDevice->GetDepthStencilSurface(&pxOldRenderTargetDepth);
	Asura_Direct3D::D3DDevice->SetDepthStencilSurface(NULL);

	// We use the existing blur code for now
	Asura_Platform_FSFX_SM30::UpdateBlurredBuffer(m_iBlurPasses, m_fBlurRadius, 1.0f-m_fBlurDesaturate, true, m_afDistances[0], m_afDistances[1], m_fBleedScale);

	Asura_Direct3D::D3DDevice->SetDepthStencilSurface(pxOldRenderTargetDepth);
	pxOldRenderTargetDepth->Release();

	Asura_Render::AllowFullScreenRendering();

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

	// Set up the verts for a full-screen pass
	// ----------------------------------------------------------------------------------------------------
	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> ( fViewWidth  * Asura_Platform_FSFX_SM30::g_fBloomEffectBlurBufferScale );
	const float fBufferHeight	= static_cast< float> ( fViewHeight * Asura_Platform_FSFX_SM30::g_fBloomEffectBlurBufferScale);

	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; 

	fHalfTexelU = 0.5f/fBufferWidth;
	fHalfTexelV = 0.5f/fBufferHeight;

	float fUMax =  (fViewWidth  * Asura_Platform_FSFX_SM30::g_fBloomEffectBlurBufferScale)  / fBufferWidth;
	float fVMax =  (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;


	// This is always a standard alpha-blended pass, unless we're debugging

	if (m_bShowBlurBuffer)
	{
		Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_OFF);
	}
	else
	{	
		Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_NORMAL);
	}

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

	if (Asura_Platform_FSFX_SM30::g_pxDepthOfFieldEffect->IsD3DEffectValid())
	{

		float afOneOverScreenDimensions[4] = {1.0f / Asura_Viewport::GetWidth(), 1.0f / Asura_Viewport::GetHeight(),  fIntensity, 1};
		Asura_Platform_FSFX_SM30::g_pxDepthOfFieldEffect->GetD3DEffect()->SetFloatArray(Asura_Platform_FSFX_SM30::g_xDepthOfFieldEffectOneOverScreenDimensions, afOneOverScreenDimensions, 4);

		Asura_Platform_FSFX_SM30::g_pxDepthOfFieldEffect->GetD3DEffect()->SetFloatArray(Asura_Platform_FSFX_SM30::g_xDepthOfFieldEffectFocalDistances, m_afDistances, 4);

		Asura_Platform_FSFX_SM30::g_pxDepthOfFieldEffect->GetD3DEffect()->SetTexture(Asura_Platform_FSFX_SM30::g_xDepthOfFieldEffectSourceTextureHandle, const_cast<IDirect3DTexture9*>(Asura_Platform_FSFX_SM30::GetBlurredBuffer()));
		Asura_Platform_FSFX_SM30::g_pxDepthOfFieldEffect->GetD3DEffect()->SetTexture(Asura_Platform_FSFX_SM30::g_xDepthOfFieldEffectDepthTextureHandle,  Asura_Direct3D::GetDeferredRenderingTarget()->GetTexture( ASURA_DIRECT3D_DEFFEDRENDERTARGET_NORMAL_INDEX));

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

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

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

	// 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_pxDepthOfFieldEffect->GetD3DEffect()->SetTexture(Asura_Platform_FSFX_SM30::g_xDepthOfFieldEffectSourceTextureHandle, NULL);
	Asura_Platform_FSFX_SM30::g_pxDepthOfFieldEffect->GetD3DEffect()->SetTexture(Asura_Platform_FSFX_SM30::g_xDepthOfFieldEffectDepthTextureHandle, NULL);
	// Effect file sets it like this
	Asura_Render::CurrentStates.RequestZBufferEnabled(false);
	Asura_Render::CurrentStates.RequestZBufferWriteEnabled(false);
	// and now re-enable it for others
	Asura_Render::CurrentStates.RequestZBufferEnabled(true);
	Asura_Render::CurrentStates.RequestZBufferWriteEnabled(true);


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

#endif //ASURA_TARGET_SM3
#endif //defined( ASURA_USE_FSFX)
