//*******************************************************************
//
// File: Asura_FSFX_Component_DesaturateAndTint.cpp        
//
// Created: 27 Feb 2006
//
// Description: 
//
//*******************************************************************

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

#if defined( ASURA_USE_FSFX)

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

#include "Rendering/Asura_ViewPort.h"
#include "Rendering/Asura_Render.h"

#include "Rendering/Asura_Direct3D_RenderTargetManager.h"
#include "Rendering/Asura_Direct3D_BackBufferCapture.h"
#include "Rendering/Asura_Direct3D_Shaders.h"

// other libraries

// internal dependencies

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


//*******************************************************************
// Local Classes
//*******************************************************************

static const char* const g_szPS_DESATURATE_AND_TINT_CODE =

"ps.1.1 \n"

// Expected constants:
// c0 - 1/3 scales
// c1 - Tint

"tex t0 \n"

"dp3 r0.rgb, c0, t0 \n"
"mul_x4 r0.rgb, r0, c1 \n"

// DLH - 07 July 2006 14:32:43 - Original Lerp before JacobT redesigned it to use a 0-2 control value
//"lrp r0.rgb, c1.a, r0, t0 \n"

// DLH - 07 July 2006 14:34:10 - New operation that can use a 0-2 control range
// r1 = Lerp * (Delta of Grey and Texture).		Lerp is 0-2 encoded in a 0-1 range
// op = t0 + r1 + r1.	// The Double add allows the Lerp to be 0-2 range with out clipping the r0 value on the registers +1 upper range

"sub r1.rgb, r0, t0 \n"
"mul r1.rgb, c1.a, r1 \n"
"add r0.rgb, t0, r1 \n"
"add r0.rgb, r0, r1 \n"

"mov r0.a, c0.a \n"			// Output a 1.0 alpha - we now have an alpha in the captured backbuffer, and want to ignore it for this effect
;

// Register the shader with Asura

const Asura_Direct3D_PixelShader g_xPS_DESATURATE_AND_TINT_SHADER( ASURA_D3D_PS_DESATURATE_AND_TINT, g_szPS_DESATURATE_AND_TINT_CODE);

struct SimpleVertex
{
	float m_fX, m_fY, m_fZ;
	float m_fU, m_fV;
};

static SimpleVertex axQUAD_VERTEX_DATA[4] =
{
	{ -1.0f,  1.0f,  0.0f,  0.0f,  0.0f },
	{  1.0f,  1.0f,  0.0f,  1.0f,  0.0f },
	{  1.0f, -1.0f,  0.0f,  1.0f,  1.0f },
	{ -1.0f, -1.0f,  0.0f,  0.0f,  1.0f },
};


//*******************************************************************
// Function Definitions
//*******************************************************************

void Asura_FSFX_Component_DesaturateAndTint::Platform_Render( const float fIntensity )
{
	SCOPEDPIXEVENT(( 0xFFE0D0C0, L"FSFX: Desaturate and Tint" ));

	const ASURA_D3D_VERTEXSHADER_ID eVertexShaderID = ASURA_D3D_VS_LINEAR;
	const ASURA_D3D_PIXELSHADER_ID ePixelShaderID = ASURA_D3D_PS_DESATURATE_AND_TINT;
	const uint32 uCoeffCount = 2;
	const float fRGBScale = 1.0f / (4.0f * 100.0f);
	const float fStrengthScale = 1.0f / (2.0f * 100.0f);
	float afPSConsts[uCoeffCount][4] =
	{
		{ 0.33f, 0.33f, 0.33f, 1.0f},
		{ this->m_fIntensityR * fRGBScale, this->m_fIntensityG * fRGBScale, this->m_fIntensityB * fRGBScale, fIntensity * this->m_fStrength * fStrengthScale},
	};
	const float* pxCoeffs = &afPSConsts[0][0];
	
	// set up some states that persist across the effect

	Asura_Render::CurrentStates.RequestTextureOpMode(ASURA_TEXTUREOP_OPAQUE);
	Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_OFF);
	Asura_Render::CurrentStates.RequestAlphaTest(false);
	Asura_Render::CurrentStates.RequestZBufferWriteEnabled(false);

	// Use clamping of tex co-ords

	DWORD uOldAddressU[4], uOldAddressV[4];
	Direct3D_BaseTexture* pxOldTexture[4];
	for (u_int u = 0; u < 1; ++u)
	{
		Asura_Direct3D::D3DDevice->GetSamplerState(u, D3DSAMP_ADDRESSU, &uOldAddressU[u]);
		Asura_Direct3D::D3DDevice->GetSamplerState(u, D3DSAMP_ADDRESSV, &uOldAddressV[u]);

		Asura_Direct3D::D3DDevice->SetSamplerState(u, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
		Asura_Direct3D::D3DDevice->SetSamplerState(u, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);

		Asura_Direct3D::D3DDevice->GetTexture(u, &pxOldTexture[u]);
	}

	// ensure that we have a backbuffer capture knocking about
	if(!Asura_Direct3D_BackBufferCapture::HasCapturedThisFrame())
	{
		Asura_Direct3D_BackBufferCapture::CaptureCurrentBackBuffer();
	}
	Asura_Render::AllowFullScreenRendering();

	// DLH - 22 February 2006 12:52:16 - I have 2* the blur buffer to get the size back to what the original buffer is. Stops the vertical bluring twice as fast as the horizontal.
	const float fInvBufferWidth = 0.5f / static_cast<float>( Asura_Direct3D::GetPresentParameters().BackBufferWidth);
	const float fInvBufferHeight = 0.5f / static_cast<float>( Asura_Direct3D::GetPresentParameters().BackBufferHeight);
	
	axQUAD_VERTEX_DATA[0].m_fU = 0.0f + fInvBufferWidth;
	axQUAD_VERTEX_DATA[0].m_fV = 0.0f + fInvBufferHeight;
	axQUAD_VERTEX_DATA[1].m_fU = 1.0f + fInvBufferWidth;
	axQUAD_VERTEX_DATA[1].m_fV = 0.0f + fInvBufferHeight;
	axQUAD_VERTEX_DATA[2].m_fU = 1.0f + fInvBufferWidth;
	axQUAD_VERTEX_DATA[2].m_fV = 1.0f + fInvBufferHeight;
	axQUAD_VERTEX_DATA[3].m_fU = 0.0f + fInvBufferWidth;
	axQUAD_VERTEX_DATA[3].m_fV = 1.0f + fInvBufferHeight;
	
	// set up the blur shaders
	Asura_Direct3D_Shaders::RequestVertexShader( eVertexShaderID);
	Asura_Direct3D_Shaders::RequestPixelShader( ePixelShaderID);
	Asura_Direct3D::D3DDevice->SetPixelShaderConstantF(0, pxCoeffs, uCoeffCount);

	// set the backbuffer capture as the textures
	Asura_Direct3D::D3DDevice->SetTexture( 0, Asura_Direct3D_BackBufferCapture::GetCaptureTexture());

	#if defined ASURA_TARGET_SM3
		// At this point, the frame buffer should be in sRGB space
		const bool bSRGB = Asura_Direct3D::UseGammaCorrection();
		Asura_Direct3D::D3DDevice->SetSamplerState( 0, D3DSAMP_SRGBTEXTURE, bSRGB );
	#endif

	axQUAD_VERTEX_DATA[0].m_fZ = axQUAD_VERTEX_DATA[1].m_fZ = axQUAD_VERTEX_DATA[2].m_fZ = axQUAD_VERTEX_DATA[3].m_fZ = 0.0f;

	Asura_Direct3D::D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, axQUAD_VERTEX_DATA, sizeof(SimpleVertex));

////// Finished

	// clean up
	for(u_int u = 0; u < 1; ++u)
	{
		Asura_Direct3D::D3DDevice->SetTexture(u, pxOldTexture[u]);
		if(pxOldTexture[u]) pxOldTexture[u]->Release();

		Asura_Direct3D::D3DDevice->SetSamplerState(u, D3DSAMP_ADDRESSU, uOldAddressU[u]);
		Asura_Direct3D::D3DDevice->SetSamplerState(u, D3DSAMP_ADDRESSV, uOldAddressV[u]);
	}
	
	Asura_Render::CurrentStates.RequestZBufferEnabled(true);
	Asura_Render::CurrentStates.RequestZBufferWriteEnabled(true);

	Asura_Direct3D_Shaders::RequestPixelShader(ASURA_D3D_PS_NONE);
	Asura_Render::CurrentStates.RequestZBufferCompareMode(ASURA_ZBUFFERCMP_LESSEQUAL);
	
	Asura_Direct3D_BackBufferCapture::AdviseNextFrame();

	Asura_Render::ApplyCameraSettings();

	#if defined ASURA_TARGET_SM3
		Asura_Direct3D::D3DDevice->SetSamplerState( 0, D3DSAMP_SRGBTEXTURE, FALSE );
	#endif
}


//*******************************************************************
//
// (c) 2006 Rebellion (Derby)
//
// Warning: This computer program is protected by copyright law and 
// international treaties. Unauthorized reproduction or distribution
// of this program, or any portion of it, may result in severe civil and
// criminal penalties, and will be prosecuted to the maximum extent 
// possible under the law.
//
//*******************************************************************

#endif //defined( ASURA_USE_FSFX)
