#include "../../Direct3D/Shader/RuShader_D3D_2DFX.h"
#include "../../Direct3D/Shader/RuShader_D3D_Base.h"

#pragma unmanaged

// ************************************************************************************************************************************************************

CRuShader_ru2DFX_Base::CRuShader_ru2DFX_Base(CRuEngineD3D *engine)
{
	m_engine = engine;
	m_pixelShader = NULL;

	CRuVertexElement vertexElements[] =
	{
		{ 0,	0,	ruELEMENTTYPE_FLOAT3,		ruELEMENTMETHOD_DEFAULT,	ruELEMENTUSAGE_POSITION,	0 },
		{ 0,	12,	ruELEMENTTYPE_D3DCOLOR,		ruELEMENTMETHOD_DEFAULT,	ruELEMENTUSAGE_COLOR,		0 },
		{ 0,	16,	ruELEMENTTYPE_FLOAT2,		ruELEMENTMETHOD_DEFAULT,	ruELEMENTUSAGE_TEXCOORD,	0 },
		RUVERTEXDECL_END()
	};

	m_vertexDecl = m_engine->CreateVertexDeclaration(vertexElements);

	char *vsSource = "\
																													\n\
	struct VS_INPUT																									\n\
	{																												\n\
		float4			vPosition : POSITION;																		\n\
		float4			vColor : COLOR;																				\n\
		float2			vTexCoord : TEXCOORD;																		\n\
	};																												\n\
																													\n\
	struct VS_OUTPUT																								\n\
	{																												\n\
		float4			vPosition : POSITION;																		\n\
		float4			vColor : COLOR;																				\n\
		float2			vTexCoord : TEXCOORD;																		\n\
	};																												\n\
																													\n\
	VS_OUTPUT main(const VS_INPUT v)																				\n\
	{																												\n\
		VS_OUTPUT output;																							\n\
																													\n\
		output.vPosition = v.vPosition;																				\n\
		output.vColor = v.vColor;																					\n\
		output.vTexCoord = v.vTexCoord;																				\n\
																													\n\
		return output;																								\n\
	}																												\n\
	";

	// Create shader
	m_vertexShader = RuD3DCompileVertexShader(vsSource, "main", "vs_1_1", NULL);
}

CRuShader_ru2DFX_Base::~CRuShader_ru2DFX_Base()
{
	if(m_vertexDecl)
		m_vertexDecl->Release();

	if(m_vertexShader)
		m_vertexShader->Release();

	if(m_pixelShader)
		m_pixelShader->Release();
}

void CRuShader_ru2DFX_Base::BeginPass(INT32 passNumber)
{
}

void CRuShader_ru2DFX_Base::EndPass(INT32 passNumber)
{
}

void CRuShader_ru2DFX_Base::SetParameters(const CRuParameterCache *paramCache)
{
	DWORD param;

	if(paramCache->GetParameter(ruPARAMTYPE_2DFX_TEXTURE_WIDTH, param))
	{
		INT32 texWidthOffset = 0;
		m_vsConstants[texWidthOffset] = static_cast<REAL>(param);
	}

	if(paramCache->GetParameter(ruPARAMTYPE_2DFX_TEXTURE_HEIGHT, param))
	{
		INT32 texHeightOffset = 1;
		m_vsConstants[texHeightOffset] = static_cast<REAL>(param);
	}
}

void CRuShader_ru2DFX_Base::Instance(INT32 streamIndex, IRuMesh *mesh, UINT32 morphTargetIndex, void *buffer) const
{
	if(streamIndex == 0)
	{
		SLitSingleTextureVertex *vertices = (SLitSingleTextureVertex *) buffer;
		IRuMorphTarget *morphTarget = mesh->GetMorphTarget(morphTargetIndex);
		const float *texCoords = morphTarget->GetTextureCoordinate(ruTEXCHANNEL_DIFFUSEMAP);

		if(morphTarget && texCoords && vertices)
		{
			for(INT32 i = 0, j = 0; i < mesh->GetNumVertices(); i++)
			{
				vertices[i].x = morphTarget->GetPosition()[i].x;
				vertices[i].y = morphTarget->GetPosition()[i].y;
				vertices[i].z = morphTarget->GetPosition()[i].z;

				vertices[i].diffuse = morphTarget->GetDiffuse()[i];

				vertices[i].u = texCoords[j++];
				vertices[i].v = texCoords[j++];
			}
		}
	}
}

// ************************************************************************************************************************************************************

const char *CRuShader_ru2DFXTYPE_FLAT::GetShaderName() const
{
	return "ru2DFXTYPE_FLAT";
}

void CRuShader_ru2DFXTYPE_FLAT::BeginPass(INT32 passNumber)
{
	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
		m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);

		m_engine->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
		m_engine->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
		m_engine->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
		m_engine->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

		m_engine->SetRenderState(D3DRS_FOGENABLE, FALSE);
	}
}

// ************************************************************************************************************************************************************

const char *CRuShader_ru2DFXTYPE_BLIT::GetShaderName() const
{
	return "ru2DFXTYPE_BLIT";
}

void CRuShader_ru2DFXTYPE_BLIT::BeginPass(INT32 passNumber)
{
	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
		m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);

		m_engine->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
		m_engine->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		m_engine->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
		m_engine->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		m_engine->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
		m_engine->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

		// Enable point filtering
		m_engine->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
		m_engine->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
		m_engine->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);

		// Set addressing mode to wrap
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);

		m_engine->SetRenderState(D3DRS_FOGENABLE, FALSE);
	}
}

// ************************************************************************************************************************************************************

const char *CRuShader_ru2DFXTYPE_BLIT_ADD::GetShaderName() const
{
	return "ru2DFXTYPE_BLIT_ADD";
}

void CRuShader_ru2DFXTYPE_BLIT_ADD::BeginPass(INT32 passNumber)
{
	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
		m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);

		m_engine->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
		m_engine->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		m_engine->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
		m_engine->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		m_engine->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
		m_engine->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

		// Enable point filtering
		m_engine->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
		m_engine->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
		m_engine->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);

		// Set addressing mode to wrap
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);

		m_engine->SetRenderState(D3DRS_FOGENABLE, FALSE);
	}
}

// ************************************************************************************************************************************************************

const char *CRuShader_ru2DFXTYPE_BLIT_FILTER::GetShaderName() const
{
	return "ru2DFXTYPE_BLIT_FILTER";
}

void CRuShader_ru2DFXTYPE_BLIT_FILTER::BeginPass(INT32 passNumber)
{
	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
		m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);

		m_engine->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
		m_engine->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		m_engine->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
		m_engine->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		m_engine->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
		m_engine->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

		// Enable linear filtering
		m_engine->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
		m_engine->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
		m_engine->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

		// Set addressing mode to wrap
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);

		m_engine->SetRenderState(D3DRS_FOGENABLE, FALSE);
	}
}

// ************************************************************************************************************************************************************

CRuShader_ru2DFXTYPE_BLIT_FILTER_CUBIC::CRuShader_ru2DFXTYPE_BLIT_FILTER_CUBIC(CRuEngineD3D *engine)
:	CRuShader_ru2DFX_Base(engine)
{
	char *psSource = "\
																													\n\
	sampler2D tex_source : register(s0) = sampler_state																\n\
	{																												\n\
		mipfilter = none;																							\n\
		minfilter = linear;																							\n\
		magfilter = linear;																							\n\
	};																												\n\
																													\n\
	sampler1D tex_hg : register(s1) = sampler_state																	\n\
	{																												\n\
		addressu = wrap;																							\n\
		addressv = wrap;																							\n\
		mipfilter = none;																							\n\
		minfilter = point;																							\n\
		magfilter = point;																							\n\
	};																												\n\
																													\n\
	struct PS_OUTPUT																								\n\
	{																												\n\
		float4 color : COLOR0;  // Pixel color																		\n\
	};																												\n\
																													\n\
//	PS_OUTPUT main(	float2 coord_source : TEXCOORD0,																\n\
//					uniform float2 e_x,																				\n\
//					uniform float2 e_y,																				\n\
//					uniform float2 size_source)																		\n\
	PS_OUTPUT main(	float2 coord_source : TEXCOORD0 )																\n\
	{																												\n\
		PS_OUTPUT output;																							\n\
																													\n\
																													\n\
		float2 e_x = float2(1 / 2048.0f, 0.0f);																											\n\
		float2 e_y = float2(0.0f, 1 / 2048.0f);																											\n\
		float2 size_source = float2(2048.0f, 2048.0f);																													\n\
																													\n\
		float2 coord_hg = coord_source * size_source - float2(0.5f, 0.5f);											\n\
																													\n\
		// Fetch offsets and weights from filter texture															\n\
		float3 hg_x = tex1D(tex_hg, coord_hg.x).xyz;																\n\
		float3 hg_y = tex1D(tex_hg, coord_hg.y).xyz;																\n\
																													\n\
		// Determine linear sampling coordinates																	\n\
		float2 coord_source10 = coord_source + hg_x.x * e_x;														\n\
		float2 coord_source00 = coord_source - hg_x.y * e_x;														\n\
																													\n\
		float2 coord_source11 = coord_source10 + hg_y.x * e_y;														\n\
		float2 coord_source01 = coord_source00 + hg_y.x * e_y;														\n\
		coord_source10 = coord_source10 - hg_y.y * e_y;																\n\
		coord_source00 = coord_source00 - hg_y.y * e_y;																\n\
																													\n\
		// Fetch four linearly interpolated inputs																	\n\
		float4 tex_source00 = tex2D(tex_source, coord_source00);													\n\
		float4 tex_source10 = tex2D(tex_source, coord_source10);													\n\
		float4 tex_source01 = tex2D(tex_source, coord_source01);													\n\
		float4 tex_source11 = tex2D(tex_source, coord_source11);													\n\
																													\n\
		// Weight along y direction																					\n\
		tex_source00 = lerp(tex_source00, tex_source01, hg_y.z);													\n\
		tex_source10 = lerp(tex_source10, tex_source11, hg_y.z);													\n\
																													\n\
		// Weight along x direction																					\n\
		output.color = lerp(tex_source00, tex_source10, hg_x.z);													\n\
																													\n\
		return output;																								\n\
	}																												\n\
	";


	IDirect3DPixelShader9 *pixelShader = NULL;

	LPD3DXBUFFER compiledShader;
	LPD3DXBUFFER errorMessages;
	ID3DXConstantTable *constantTable;
	if(D3DXCompileShader(psSource, strlen(psSource), NULL, NULL, "main", "ps_2_0", 0, &compiledShader,	&errorMessages, &constantTable) != D3D_OK)
	{
		if(compiledShader)
			compiledShader->Release();
		if(errorMessages)
		{
			MessageBox(NULL, (LPCSTR) errorMessages->GetBufferPointer(), "", MB_OK);
			errorMessages->Release();
		}
	}

	// Create shader
	if(g_ruEngineD3D->GetD3DDevice()->CreatePixelShader((DWORD *) compiledShader->GetBufferPointer(), &pixelShader) != D3D_OK)
	{
		// Handle error here
	}

	if(compiledShader)
		compiledShader->Release();
	if(errorMessages)
		errorMessages->Release();

	m_pixelShader = pixelShader;

	// Create shader
//	m_vertexShader = RuD3DAssembleVertexShader(vsSource);
}

CRuShader_ru2DFXTYPE_BLIT_FILTER_CUBIC::~CRuShader_ru2DFXTYPE_BLIT_FILTER_CUBIC()
{
}

const char *CRuShader_ru2DFXTYPE_BLIT_FILTER_CUBIC::GetShaderName() const
{
	return "ru2DFXTYPE_BLIT_FILTER_CUBIC";
}

void CRuShader_ru2DFXTYPE_BLIT_FILTER_CUBIC::BeginPass(INT32 passNumber)
{
	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(m_pixelShader);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
		m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
/*
		m_engine->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
		m_engine->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		m_engine->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
		m_engine->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		m_engine->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
		m_engine->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

		// Enable linear filtering
		m_engine->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
		m_engine->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
		m_engine->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

		// Set addressing mode to wrap
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
*/
		m_engine->SetRenderState(D3DRS_FOGENABLE, FALSE);
	}
}

// ************************************************************************************************************************************************************

const char *CRuShader_ru2DFXTYPE_BLIT_MASK::GetShaderName() const
{
	return "ru2DFXTYPE_BLIT_MASK";
}

void CRuShader_ru2DFXTYPE_BLIT_MASK::BeginPass(INT32 passNumber)
{
	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
		m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
		m_engine->SetRenderState(D3DRS_ALPHAREF, 0);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);

		// Set render states to write stencil value of 1
		m_engine->SetRenderState(D3DRS_STENCILENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
		m_engine->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);
		m_engine->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
		m_engine->SetRenderState(D3DRS_STENCILREF, 0x00000001);
		m_engine->SetRenderState(D3DRS_STENCILMASK, 0xFFFFFFFF);
		m_engine->SetRenderState(D3DRS_STENCILWRITEMASK, 0xFFFFFFFF);
		m_engine->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);

		m_engine->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
		m_engine->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		m_engine->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
		m_engine->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		m_engine->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
		m_engine->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

		// Enable linear filtering
		m_engine->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
		m_engine->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
		m_engine->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

		// Set addressing mode to clamp
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);

		m_engine->SetRenderState(D3DRS_FOGENABLE, FALSE);
	}
}

void CRuShader_ru2DFXTYPE_BLIT_MASK::EndPass(INT32 passNumber)
{
	if(passNumber == 0)
	{
		m_engine->SetRenderState(D3DRS_STENCILENABLE, FALSE);
	}
}

// ************************************************************************************************************************************************************

const char *CRuShader_ru2DFXTYPE_BLIT_MASKED::GetShaderName() const
{
	return "ru2DFXTYPE_BLIT_MASKED";
}

void CRuShader_ru2DFXTYPE_BLIT_MASKED::BeginPass(INT32 passNumber)
{
	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
		m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);

		// Enable stencil testing
		m_engine->SetRenderState(D3DRS_STENCILENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
		m_engine->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);
		m_engine->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP);
		m_engine->SetRenderState(D3DRS_STENCILREF, 0x00000001);
		m_engine->SetRenderState(D3DRS_STENCILMASK, 0xFFFFFFFF);
		m_engine->SetRenderState(D3DRS_STENCILWRITEMASK, 0xFFFFFFFF);
		m_engine->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);

		m_engine->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
		m_engine->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		m_engine->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
		m_engine->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		m_engine->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
		m_engine->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

		// Enable linear filtering
		m_engine->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
		m_engine->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
		m_engine->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

		// Set addressing mode to clamp
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);

		m_engine->SetRenderState(D3DRS_FOGENABLE, FALSE);
	}
}

void CRuShader_ru2DFXTYPE_BLIT_MASKED::EndPass(INT32 passNumber)
{
	if(passNumber == 0)
	{
		m_engine->SetRenderState(D3DRS_STENCILENABLE, FALSE);
	}
}

// ************************************************************************************************************************************************************

CRuShader_ru2DFXTYPE_BLIT_LUMINANCE::CRuShader_ru2DFXTYPE_BLIT_LUMINANCE(CRuEngineD3D *engine)
:	CRuShader_ru2DFX_Base(engine)
{
	char *psSource = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	def					c1,			1.0, 1.0, 1.0, 0.0																\n\
	def					c2,			0.33, 0.33, 0.33, 1.0															\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample diffuse texture						\n\
																													\n\
	; Arithmetic ops																								\n\
	dp3					r1,			t0,			c1					; Add RGB into r1								\n\
	mul					r0,			r1,			c2					; Divide sum by 3 to get luminance (sort of)	\n\
	mov					r0.w,		t0.w							; Get texture alpha into r0.w					\n\
																													\n\
	mul					r0,			r0,			v0					; Modulate luminance with diffuse color			\n\
	";

	// Assemble pixel shader
	m_pixelShader = RuD3DAssemblePixelShader(psSource);
}

const char *CRuShader_ru2DFXTYPE_BLIT_LUMINANCE::GetShaderName() const
{
	return "ru2DFXTYPE_BLIT_LUMINANCE";
}

void CRuShader_ru2DFXTYPE_BLIT_LUMINANCE::BeginPass(INT32 passNumber)
{
	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(m_pixelShader);

		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
		m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);

		// Enable point filtering
		m_engine->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
		m_engine->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
		m_engine->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);

		// Set addressing mode to wrap
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);

		m_engine->SetRenderState(D3DRS_FOGENABLE, FALSE);
	}
}

// ************************************************************************************************************************************************************

const char *CRuShader_ru2DFXTYPE_DARKEN::GetShaderName() const
{
	return "ru2DFXTYPE_DARKEN";
}

void CRuShader_ru2DFXTYPE_DARKEN::BeginPass(INT32 passNumber)
{
	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
		m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);

		m_engine->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
		m_engine->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
		m_engine->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

		m_engine->SetRenderState(D3DRS_FOGENABLE, FALSE);
	}
}

// ************************************************************************************************************************************************************

CRuShader_ru2DFXTYPE_GAUSSIAN::CRuShader_ru2DFXTYPE_GAUSSIAN(CRuEngineD3D *engine)
: CRuShader_ru2DFX_Base(engine)
{
	char *vsSource_Pass_0 = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_color			v1											; Declare diffuse color							\n\
	dcl_texcoord0		v2											; Declare input texcoord 0						\n\
																													\n\
	mov					oPos,		v0								; Copy vertex to output							\n\
	mov					oD0,		v1								; Set diffuse									\n\
																													\n\
	; Calculate texel offsets																						\n\
	rcp					r7.x,		c0.x							; u offset into r7.x							\n\
	mov					r7.y,		c0.z							; v offset into r7.y							\n\
																													\n\
	mov					r3.xy,		v2.xy							; Center texel									\n\
	sub					r2.xy,		r3.xy,		r7.xy				; L0											\n\
	sub					r1.xy,		r2.xy,		r7.xy				; L1											\n\
	sub					r0.xy,		r1.xy,		r7.xy				; L2											\n\
	add					r4.xy,		r3.xy,		r7.xy				; R0											\n\
	add					r5.xy,		r4.xy,		r7.xy				; R1											\n\
	add					r6.xy,		r5.xy,		r7.xy				; R2											\n\
																													\n\
	mov					oT0.xy,		r0.xy							; Copy texture coordinates to output			\n\
	mov					oT1.xy,		r1.xy							; Copy texture coordinates to output			\n\
	mov					oT2.xy,		r2.xy							; Copy texture coordinates to output			\n\
	mov					oT3.xy,		r3.xy							; Copy texture coordinates to output			\n\
	mov					oT4.xy,		r4.xy							; Copy texture coordinates to output			\n\
	mov					oT5.xy,		r5.xy							; Copy texture coordinates to output			\n\
	mov					oT6.xy,		r6.xy							; Copy texture coordinates to output			\n\
	";

	char *vsSource_Pass_1 = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_color			v1											; Declare diffuse color							\n\
	dcl_texcoord0		v2											; Declare input texcoord 0						\n\
																													\n\
	mov					oPos,		v0								; Copy vertex to output							\n\
	mov					oD0,		v1								; Set diffuse									\n\
																													\n\
	; Calculate texel offsets																						\n\
	mov					r7.x,		c0.z							; u offset into r7.x							\n\
	rcp					r7.y,		c0.y							; v offset into r7.y							\n\
																													\n\
	mov					r3.xy,		v2.xy							; Center texel									\n\
	sub					r2.xy,		r3.xy,		r7.xy				; L0											\n\
	sub					r1.xy,		r2.xy,		r7.xy				; L1											\n\
	sub					r0.xy,		r1.xy,		r7.xy				; L2											\n\
	add					r4.xy,		r3.xy,		r7.xy				; R0											\n\
	add					r5.xy,		r4.xy,		r7.xy				; R1											\n\
	add					r6.xy,		r5.xy,		r7.xy				; R2											\n\
																													\n\
	mov					oT0.xy,		r0.xy							; Copy texture coordinates to output			\n\
	mov					oT1.xy,		r1.xy							; Copy texture coordinates to output			\n\
	mov					oT2.xy,		r2.xy							; Copy texture coordinates to output			\n\
	mov					oT3.xy,		r3.xy							; Copy texture coordinates to output			\n\
	mov					oT4.xy,		r4.xy							; Copy texture coordinates to output			\n\
	mov					oT5.xy,		r5.xy							; Copy texture coordinates to output			\n\
	mov					oT6.xy,		r6.xy							; Copy texture coordinates to output			\n\
	";

	char *psSource = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; DIFFUSE MAP									\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy										; L2											\n\
	dcl					t1.xy										; L1											\n\
	dcl					t2.xy										; L0											\n\
	dcl					t3.xy										; C												\n\
	dcl					t4.xy										; R0											\n\
	dcl					t5.xy										; R1											\n\
	dcl					t6.xy										; R2											\n\
																													\n\
	dcl					v0.xyzw																						\n\
																													\n\
	texld				r0,			t0,			s0					; Sample L2										\n\
	texld				r1,			t1,			s0					; Sample L1										\n\
	texld				r2,			t2,			s0					; Sample L0										\n\
	texld				r3,			t3,			s0					; Sample C										\n\
	texld				r4,			t4,			s0					; Sample R0										\n\
	texld				r5,			t5,			s0					; Sample R1										\n\
	texld				r6,			t6,			s0					; Sample R2										\n\
																													\n\
	mul					r7,			r0,			c0.x				; Accumulate L2									\n\
	mad					r7,			r1,			c0.y,		r7		; Accumulate L1									\n\
	mad					r7,			r2,			c0.z,		r7		; Accumulate L0									\n\
	mad					r7,			r3,			c0.w,		r7		; Accumulate C									\n\
	mad					r7,			r4,			c0.z,		r7		; Accumulate R0									\n\
	mad					r7,			r5,			c0.y,		r7		; Accumulate R1									\n\
	mad					r7,			r6,			c0.x,		r7		; Accumulate R2									\n\
																													\n\
	mov					oC0,		r7								; Move result into output						\n\
	";

	// Create shader
	m_vertexShaders[0] = RuD3DAssembleVertexShader(vsSource_Pass_0);
	m_vertexShaders[1] = RuD3DAssembleVertexShader(vsSource_Pass_1);

	// Assemble pixel shader
	m_pixelShader = RuD3DAssemblePixelShader(psSource);
}

CRuShader_ru2DFXTYPE_GAUSSIAN::~CRuShader_ru2DFXTYPE_GAUSSIAN()
{
	if(m_vertexShaders[0])
		m_vertexShaders[0]->Release();
	if(m_vertexShaders[1])
		m_vertexShaders[1]->Release();
}

const char *CRuShader_ru2DFXTYPE_GAUSSIAN::GetShaderName() const
{
	return "ru2DFXTYPE_GAUSSIAN";
}

void CRuShader_ru2DFXTYPE_GAUSSIAN::BeginPass(INT32 passNumber)
{
	if(passNumber == 0)
	{
		m_vsConstants[4] = 1.0f;
		m_vsConstants[5] = 0.0f;
		m_vsConstants[6] = 0.0f;
		m_vsConstants[7] = 0.0f;
	}
	else
	{
		m_vsConstants[4] = 0.0f;
		m_vsConstants[5] = 0.0f;
		m_vsConstants[6] = 0.0f;
		m_vsConstants[7] = 0.0f;
	}


	m_vsConstants[2] = 0.0f;
	m_vsConstants[3] = 0.0f;

	m_psConstants[0] = 0.006f;
	m_psConstants[1] = 0.061f;
	m_psConstants[2] = 0.242f;
	m_psConstants[3] = 0.383f;

//	m_psConstants[0] = 0.025f;
//	m_psConstants[1] = 0.075f;
//	m_psConstants[2] = 0.200f;
//	m_psConstants[3] = 0.400f;

//	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShaders[passNumber]);
		m_engine->SetPixelShader(m_pixelShader);
		m_engine->GetD3DDevice()->SetVertexShaderConstantF(0, m_vsConstants, 2);
		m_engine->GetD3DDevice()->SetPixelShaderConstantF(0, m_psConstants, 2);

		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);

		// Enable linear filtering
		m_engine->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
		m_engine->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
		m_engine->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

		// Set addressing mode to wrap
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);

		// Disable fog
		m_engine->SetRenderState(D3DRS_FOGENABLE, FALSE);
	}
//	else
	{
	}
}

void CRuShader_ru2DFXTYPE_GAUSSIAN::EndPass(INT32 passNumber)
{
}

// ************************************************************************************************************************************************************

const char *CRuShader_ru2DFXTYPE_MODULATE::GetShaderName() const
{
	return "ru2DFXTYPE_MODULATE";
}

void CRuShader_ru2DFXTYPE_MODULATE::BeginPass(INT32 passNumber)
{
	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);

		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
		m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);

		m_engine->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
		m_engine->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		m_engine->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
		m_engine->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		m_engine->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);

		m_engine->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
		m_engine->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

		// Enable point filtering
		m_engine->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
		m_engine->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
		m_engine->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

		// Set addressing mode to wrap
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);

		m_engine->SetRenderState(D3DRS_FOGENABLE, FALSE);
	}
}

// ************************************************************************************************************************************************************

CRuShader_ru2DFXTYPE_SPLAT_PS11::CRuShader_ru2DFXTYPE_SPLAT_PS11(CRuEngineD3D *engine)
:	CRuShader_ru2DFX_Base(engine)
{
	if(m_vertexShader)
		m_vertexShader->Release();

	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_color			v1											; Declare diffuse color							\n\
	dcl_texcoord0		v2											; Declare input texcoord 0						\n\
																													\n\
	def					c0,			16.0, 16.0, 1.0, 1.0															\n\
																													\n\
	mov					oPos,		v0								; Copy vertex to output							\n\
	mov					oD0,		v1								; Set diffuse									\n\
	mov					oT0,		v2								; Copy texture coordinates to output			\n\
	mul					oT1,		v2,			c0					; Copy texture coordinates to output			\n\
	mul					oT2,		v2,			c0					; Copy texture coordinates to output			\n\
	mul					oT3,		v2,			c0					; Copy texture coordinates to output			\n\
	";

	char *psSource = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	def					c1,			1.0, 0.0, 0.0, 0.0																\n\
	def					c2,			0.0, 1.0, 0.0, 0.0																\n\
	def					c3,			0.0, 0.0, 1.0, 0.0																\n\
	def					c4,			1.0, 1.0, 1.0, 1.0																\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample diffuse texture						\n\
	tex					t1											; Sample diffuse texture						\n\
	tex					t2											; Sample diffuse texture						\n\
	tex					t3											; Sample diffuse texture						\n\
																													\n\
	; Arithmetic ops																								\n\
	dp3					r1,			t0,			c1					; Get RED into r1								\n\
	mul_sat				r0,			t1,			r1					; Modulate layer 0								\n\
																													\n\
	dp3					r1,			t0,			c2					; Get BLUE into r1								\n\
	mad_sat				r0,			t2,			r1,			r0		; Modulate layer 1								\n\
																													\n\
	dp3					r1,			t0,			c3					; Get GREEN into r1								\n\
	mad_sat				r0,			t3,			r1,			r0		; Modulate layer 2								\n\
																													\n\
	mul					r0,			r0,			c0					; Scale output alpha							\n\
	; These two instructions can correct the problem of alpha not adding up to 1: use as a postprocess				\n\
	;sub					r1,			c4,			r0.w																\n\
	;mad					r0,			r0,			r1,			r0														\n\
	";

	LPD3DXBUFFER assembledShader;
	LPD3DXBUFFER errorMessages;
	if(D3DXAssembleShader(vsSource, strlen(vsSource), NULL, NULL, 0, &assembledShader,	&errorMessages) != D3D_OK)
	{
		MessageBox(NULL, "Error assembling VS", "", MB_OK);

		if(assembledShader)
			assembledShader->Release();
		if(errorMessages)
		{
			MessageBox(NULL, (LPCSTR) errorMessages->GetBufferPointer(), "", MB_OK);
			errorMessages->Release();
		}

		return;
	}

	// Create shader
	IDirect3DVertexShader9 *vertexShader = NULL;
	if(m_engine->GetD3DDevice()->CreateVertexShader((DWORD *) assembledShader->GetBufferPointer(), &m_vertexShader) != D3D_OK)
	{
//		MessageBox(NULL, "Error creating VS", "", MB_OK);
	}

	if(assembledShader)
		assembledShader->Release();
	if(errorMessages)
		errorMessages->Release();

	if(D3DXAssembleShader(psSource, strlen(psSource), NULL, NULL, 0, &assembledShader,	&errorMessages) != D3D_OK)
	{
		MessageBox(NULL, "Error assembling PS", "", MB_OK);

		if(assembledShader)
			assembledShader->Release();
		if(errorMessages)
		{
			MessageBox(NULL, (LPCSTR) errorMessages->GetBufferPointer(), "", MB_OK);
			errorMessages->Release();
		}

		return;
	}

	// Create shader
	IDirect3DPixelShader9 *pixelShader = NULL;
	if(m_engine->GetD3DDevice()->CreatePixelShader((DWORD *) assembledShader->GetBufferPointer(), &m_pixelShader) != D3D_OK)
	{
//		MessageBox(NULL, "Error creating VS", "", MB_OK);
	}

	if(assembledShader)
		assembledShader->Release();
	if(errorMessages)
		errorMessages->Release();
}

const char *CRuShader_ru2DFXTYPE_SPLAT_PS11::GetShaderName() const
{
	return "ru2DFXTYPE_SPLAT_PS11";
}

void CRuShader_ru2DFXTYPE_SPLAT_PS11::BeginPass(INT32 passNumber)
{
	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(m_pixelShader);
		m_engine->GetD3DDevice()->SetPixelShaderConstantF(0, m_psConstants, 1);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
		m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);

		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);

		m_engine->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
		m_engine->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
		m_engine->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

		for(INT32 i = 1; i <= 4; ++i)
		{
			m_engine->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
			m_engine->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);

			m_engine->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_POINT);
			m_engine->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
			m_engine->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
		}

		m_engine->SetRenderState(D3DRS_FOGENABLE, FALSE);
	}
}

void CRuShader_ru2DFXTYPE_SPLAT_PS11::SetParameters(const CRuParameterCache *paramCache)
{
	DWORD param;

	CRuShader_ru2DFX_Base::SetParameters(paramCache);

	if(paramCache->GetParameter(ruPARAMTYPE_MIPMAP_ALPHASCALE, param))
	{
		m_psConstants[0] = 1.0f;
		m_psConstants[1] = 1.0f;
		m_psConstants[2] = 1.0f;
		m_psConstants[3] = *((float *) param);
	}
}

// ************************************************************************************************************************************************************

CRuShader_ru2DFXTYPE_SPLAT_PS20::CRuShader_ru2DFXTYPE_SPLAT_PS20(CRuEngineD3D *engine)
:	CRuShader_ru2DFX_Base(engine)
{
	if(m_vertexShader)
		m_vertexShader->Release();

	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_color			v1											; Declare diffuse color							\n\
	dcl_texcoord0		v2											; Declare input texcoord 0						\n\
																													\n\
	def					c0,			4.0, 4.0, 4.0, 4.0																\n\
																													\n\
	mov					oPos,		v0								; Copy vertex to output							\n\
	mov					oD0,		v1								; Set diffuse									\n\
	mov					oT0,		v2								; Copy texture coordinates to output			\n\
	mov					oT1,		v2								; Copy texture coordinates to output			\n\
	mul					oT2,		v2,			c0					; Copy texture coordinates to output			\n\
	mul					oT3,		v2,			c0					; Copy texture coordinates to output			\n\
	mul					oT4,		v2,			c0					; Copy texture coordinates to output			\n\
	mul					oT5,		v2,			c0					; Copy texture coordinates to output			\n\
	mul					oT6,		v2,			c0					; Copy texture coordinates to output			\n\
	mul					oT7,		v2,			c0					; Copy texture coordinates to output			\n\
	";

	char *psSource = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; ALPHA_1										\n\
	dcl_2d				s2											; LAYER_0										\n\
	dcl_2d				s3											; LAYER_1										\n\
	dcl_2d				s4											; LAYER_2										\n\
	dcl_2d				s5											; LAYER_3										\n\
	dcl_2d				s6											; LAYER_4										\n\
	dcl_2d				s7											; LAYER_5										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
	dcl					t2.xy																						\n\
	dcl					t3.xy																						\n\
	dcl					t4.xy																						\n\
	dcl					t5.xy																						\n\
	dcl					t6.xy																						\n\
	dcl					t7.xy																						\n"
	"																												\n\
	; Texture sampling																								\n\
	texld				r6,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld				r7,			t1,			s1					; Sample ALPHA_1 into R2						\n\
	texld				r0,			t2,			s2					; Sample layer 0								\n\
	texld				r1,			t3,			s3					; Sample layer 1								\n\
	texld				r2,			t4,			s4					; Sample layer 2								\n\
	texld				r3,			t5,			s5					; Sample layer 3								\n\
	texld				r4,			t6,			s6					; Sample layer 4								\n\
	texld				r5,			t7,			s7					; Sample layer 5								\n\
																													\n\
	mul					r8,			r0,			r6.x				; Multiply layer 0 by its factor into R8		\n\
	mad					r8,			r1,			r6.y,		r8		; Multiply layer 1 by its factor into R8		\n\
	mad					r8,			r2,			r6.z,		r8		; Multiply layer 2 by its factor into R8		\n\
	mad					r8,			r3,			r7.x,		r8		; Multiply layer 3 by its factor into R8		\n\
	mad					r8,			r4,			r7.y,		r8		; Multiply layer 4 by its factor into R8		\n\
	mad					r8,			r5,			r7.z,		r8		; Multiply layer 5 by its factor into R8		\n\
	mul					r8,			r8,			c0					; Multiply by alpha scale						\n\
	mov					oC0,		r8								; Store to output								\n\
	";

	LPD3DXBUFFER assembledShader;
	LPD3DXBUFFER errorMessages;
	if(D3DXAssembleShader(vsSource, strlen(vsSource), NULL, NULL, 0, &assembledShader,	&errorMessages) != D3D_OK)
	{
		MessageBox(NULL, "Error assembling VS", "", MB_OK);

		if(assembledShader)
			assembledShader->Release();
		if(errorMessages)
		{
			MessageBox(NULL, (LPCSTR) errorMessages->GetBufferPointer(), "", MB_OK);
			errorMessages->Release();
		}

		return;
	}

	// Create shader
	IDirect3DVertexShader9 *vertexShader = NULL;
	if(m_engine->GetD3DDevice()->CreateVertexShader((DWORD *) assembledShader->GetBufferPointer(), &m_vertexShader) != D3D_OK)
	{
//		MessageBox(NULL, "Error creating VS", "", MB_OK);
	}

	if(assembledShader)
		assembledShader->Release();
	if(errorMessages)
		errorMessages->Release();

	if(D3DXAssembleShader(psSource, strlen(psSource), NULL, NULL, 0, &assembledShader,	&errorMessages) != D3D_OK)
	{
		MessageBox(NULL, "Error assembling PS", "", MB_OK);

		if(assembledShader)
			assembledShader->Release();
		if(errorMessages)
		{
			MessageBox(NULL, (LPCSTR) errorMessages->GetBufferPointer(), "", MB_OK);
			errorMessages->Release();
		}

		return;
	}

	// Create shader
	IDirect3DPixelShader9 *pixelShader = NULL;
	if(m_engine->GetD3DDevice()->CreatePixelShader((DWORD *) assembledShader->GetBufferPointer(), &m_pixelShader) != D3D_OK)
	{
//		MessageBox(NULL, "Error creating VS", "", MB_OK);
	}

	if(assembledShader)
		assembledShader->Release();
	if(errorMessages)
		errorMessages->Release();
}

const char *CRuShader_ru2DFXTYPE_SPLAT_PS20::GetShaderName() const
{
	return "ru2DFXTYPE_SPLAT_PS20";
}

void CRuShader_ru2DFXTYPE_SPLAT_PS20::BeginPass(INT32 passNumber)
{
	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(m_pixelShader);
		m_engine->GetD3DDevice()->SetPixelShaderConstantF(0, m_psConstants, 1);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
		m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);

		for(INT32 i = 0; i < 2; ++i)
		{
			m_engine->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
			m_engine->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);

			m_engine->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
			m_engine->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
			m_engine->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
		}

		for(INT32 i = 2; i < 8 ; ++i)
		{
			m_engine->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
			m_engine->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);

			m_engine->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_POINT);
			m_engine->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
			m_engine->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
		}
	}
}

void CRuShader_ru2DFXTYPE_SPLAT_PS20::SetParameters(const CRuParameterCache *paramCache)
{
	DWORD param;

	CRuShader_ru2DFX_Base::SetParameters(paramCache);

	if(paramCache->GetParameter(ruPARAMTYPE_MIPMAP_ALPHASCALE, param))
	{
		m_psConstants[0] = 1.0f;
		m_psConstants[1] = 1.0f;
		m_psConstants[2] = 1.0f;
		m_psConstants[3] = *((float *) param);
	}
}

// ************************************************************************************************************************************************************

#pragma managed
