#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\
	// Globals																										\n\
	float4				g_globalParams : register(c0);		// (rotation, aspect ratio X:Y, sin(t), cos(t))			\n\
	float4				g_texParams : register(c1);			// (1 / w, 1 / h, 0, 0)									\n\
	float4				g_instanceData[252] : register(c2);															\n\
																													\n\
	struct VS_INPUT																									\n\
	{																												\n\
		float4			position : POSITION;																		\n\
		float4			diffuse : COLOR;																			\n\
		float2			texcoord : TEXCOORD;																		\n\
	};																												\n\
																													\n\
	struct VS_OUTPUT																								\n\
	{																												\n\
		float4			position : POSITION;																		\n\
		float4			diffuse : COLOR;																			\n\
		float2			texcoord : TEXCOORD;																		\n\
	};																												\n\
																													\n\
	VS_OUTPUT main(const VS_INPUT v)																				\n\
	{																												\n\
		VS_OUTPUT output;																							\n\
																													\n\
		float i0 = (v.diffuse.w * 255.5) * 3;																		\n\
		float i1 = i0 + 1;																							\n\
		float i2 = i1 + 1;																							\n\
																													\n\
		float4 var_x0_u0_y0_v0 = g_instanceData[i0];																\n\
		float4 var_x1_u1_y1_v1 = g_instanceData[i1];																\n\
																													\n\
		float centroidX = (var_x1_u1_y1_v1[0] + var_x0_u0_y0_v0[0]) * 0.5f;											\n\
		float centroidY = (var_x1_u1_y1_v1[2] + var_x0_u0_y0_v0[2]) * 0.5f;											\n\
																													\n\
		float2 lrp_x_u = lerp(var_x1_u1_y1_v1, var_x0_u0_y0_v0, v.diffuse.x).xy;									\n\
		float2 lrp_y_v = lerp(var_x1_u1_y1_v1, var_x0_u0_y0_v0, v.diffuse.y).zw;									\n\
																													\n\
		float relX = lrp_x_u[0] - centroidX;																		\n\
		float relY = (lrp_y_v[0] - centroidY) / g_globalParams[1];													\n\
																													\n\
		output.position.x = relX * g_globalParams[3] - relY * g_globalParams[2] + centroidX;						\n\
		output.position.y = (relX * g_globalParams[2] + relY * g_globalParams[3]) * g_globalParams[1] + centroidY;	\n\
		output.position.z = 0.0f;																					\n\
		output.position.w = 1.0f;																					\n\
																													\n\
		output.texcoord.x = lrp_x_u[1];																				\n\
		output.texcoord.y = lrp_y_v[1];																				\n\
																													\n\
		output.diffuse = g_instanceData[i2];																		\n\
																													\n\
		return output;																								\n\
	}																												\n\
	";

	// Create shader
	m_vertexShader = RuD3DCompileVertexShader(vsSource, "main", "vs_2_0", 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)
{
	m_engine->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);

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

	m_engine->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, 4);

	m_engine->SetSamplerState(0, D3DSAMP_MIPMAPLODBIAS, RuCastFloatToDWORD(-0.5f));
}

void CRuShader_ru2DFX_Base::EndPass(INT32 passNumber)
{
	m_engine->SetRenderState(D3DRS_STENCILENABLE, FALSE);

	m_engine->SetSamplerState(0, D3DSAMP_MIPMAPLODBIAS, RuCastFloatToDWORD(0.0f));
}

void CRuShader_ru2DFX_Base::SetDefaultParameters()
{
}

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

	// NOTE: Gaussian blur needs this or something
	if(paramCache->GetParameter(ruPARAMTYPE_2DFX_TEXTURE_WIDTH, param))
	{
		INT32 texWidthOffset = 1 * 4 + 0;
		m_vsConstants[texWidthOffset] = 1.0f / static_cast<REAL>(param);
	}

	if(paramCache->GetParameter(ruPARAMTYPE_2DFX_TEXTURE_HEIGHT, param))
	{
		INT32 texHeightOffset = 1 * 4 + 1;
		m_vsConstants[texHeightOffset] = 1.0f / static_cast<REAL>(param);
		m_vsConstants[texHeightOffset + 1] = 0.0f;
		m_vsConstants[texHeightOffset + 2] = 0.0f;
	}

	if(paramCache->GetParameter(ruPARAMTYPE_GEOINSTANCE_S_COUNT, param))
	{
		m_numInstances = (UINT32) param;
	}

	if(paramCache->GetParameter(ruPARAMTYPE_GEOINSTANCE_S_DATA, param))
	{
		float *instanceData = reinterpret_cast<float *>(param);

		// Number of constants = instance dataset
		INT32 numConstants = m_numInstances * 12;
		INT32 constantOffset = 2 * 4;

		memcpy(&m_vsConstants[constantOffset], instanceData, sizeof(float) * numConstants);
	}

	if(paramCache->GetParameter(ruPARAMTYPE_CUSTOM_0, param))
	{
		INT32 constantOffset = 0 * 4;
		REAL rotation = RuCastDWORDToFloat(param);
		m_vsConstants[constantOffset] = rotation;
	}

	if(paramCache->GetParameter(ruPARAMTYPE_CUSTOM_1, param))
	{
		INT32 constantOffset = 0 * 4 + 1;
		REAL aspectRatio_XY = RuCastDWORDToFloat(param);
		m_vsConstants[constantOffset] = aspectRatio_XY;
	}

	if(paramCache->GetParameter(ruPARAMTYPE_CUSTOM_2, param))
	{
		INT32 constantOffset = 0 * 4 + 2;
		REAL sinTheta = RuCastDWORDToFloat(param);
		m_vsConstants[constantOffset] = sinTheta;
	}

	if(paramCache->GetParameter(ruPARAMTYPE_CUSTOM_3, param))
	{
		INT32 constantOffset = 0 * 4 + 3;
		REAL cosTheta = RuCastDWORDToFloat(param);
		m_vsConstants[constantOffset] = cosTheta;
	}

	if(paramCache->GetParameter(ruPARAMTYPE_SYSTEM_STENCILID, param))
	{
		m_stencilID = static_cast<UINT8>(param);
	}
}

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

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

void CRuShader_ru2DFXTYPE_FLAT::BeginPass(INT32 passNumber)
{
	// Chain call to base class
	CRuShader_ru2DFX_Base::BeginPass(passNumber);

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);
		m_engine->SetVertexShaderConstants(0, m_vsConstants, 2 + m_numInstances * 3);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
		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);

		// Disable stencil
		m_engine->SetRenderState(D3DRS_STENCILENABLE, FALSE);

		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_FLAT_MASKED::GetShaderName() const
{
	return "ru2DFXTYPE_FLAT_MASKED";
}

void CRuShader_ru2DFXTYPE_FLAT_MASKED::BeginPass(INT32 passNumber)
{
	// Chain call to base class
	CRuShader_ru2DFX_Base::BeginPass(passNumber);

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);
		m_engine->SetVertexShaderConstants(0, m_vsConstants, 2 + m_numInstances * 3);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
		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 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, m_stencilID);
		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_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);
	}
}

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

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

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

void CRuShader_ru2DFXTYPE_BLIT::BeginPass(INT32 passNumber)
{
	// Chain call to base class
	CRuShader_ru2DFX_Base::BeginPass(passNumber);

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);
		m_engine->SetVertexShaderConstants(0, m_vsConstants, 2 + m_numInstances * 3);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
		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)
{
	// Chain call to base class
	CRuShader_ru2DFX_Base::BeginPass(passNumber);

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);
		m_engine->SetVertexShaderConstants(0, m_vsConstants, 2 + m_numInstances * 3);

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

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

		// Disable stencil
		m_engine->SetRenderState(D3DRS_STENCILENABLE, FALSE);

		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_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_FILTER::GetShaderName() const
{
	return "ru2DFXTYPE_BLIT_FILTER";
}

void CRuShader_ru2DFXTYPE_BLIT_FILTER::BeginPass(INT32 passNumber)
{
	// Chain call to base class
	CRuShader_ru2DFX_Base::BeginPass(passNumber);

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);
		m_engine->SetVertexShaderConstants(0, m_vsConstants, 2 + m_numInstances * 3);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
		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);

		// Disable stencil
		m_engine->SetRenderState(D3DRS_STENCILENABLE, FALSE);

		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->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);

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

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

CRuShader_ru2DFXTYPE_TEXTBLIT_FILTER::CRuShader_ru2DFXTYPE_TEXTBLIT_FILTER(CRuEngineD3D *engine)
:	CRuShader_ru2DFX_Base(engine)
{
	char *psSource = "\
																													\n\
	sampler2D tex0 : register(s0);																					\n\
																													\n\
	struct PS_INPUT																									\n\
	{																												\n\
		float4			position				: POSITION;															\n\
		float4			diffuse					: COLOR;															\n\
		float2			texcoord0				: TEXCOORD0;														\n\
	};																												\n\
																													\n\
	struct PS_OUTPUT																								\n\
	{																												\n\
		float4			color					: COLOR;															\n\
	};																												\n\
																													\n\
	PS_OUTPUT main(const PS_INPUT v)																				\n\
	{																												\n\
		PS_OUTPUT output;																							\n\
																													\n\
		// Sample diffuse map																						\n\
		float4 color = tex2D(tex0, v.texcoord0);																	\n\
																													\n\
		// Replicate color to alpha																					\n\
		color.w = color.x * v.diffuse.w;																			\n\
		color.x = v.diffuse.x;																						\n\
		color.y = v.diffuse.y;																						\n\
		color.z = v.diffuse.z;																						\n\
																													\n\
		output.color = color;																						\n\
																													\n\
		return output;																								\n\
	}																												\n\
	";

	// Compile pixel shader
	m_pixelShader = RuD3DCompilePixelShader(psSource, "main", "ps_2_0", NULL);
}

const char *CRuShader_ru2DFXTYPE_TEXTBLIT_FILTER::GetShaderName() const
{
	return "ru2DFXTYPE_TEXTBLIT_FILTER";
}

void CRuShader_ru2DFXTYPE_TEXTBLIT_FILTER::BeginPass(INT32 passNumber)
{
	// Chain call to base class
	CRuShader_ru2DFX_Base::BeginPass(passNumber);

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(m_pixelShader);
		m_engine->SetVertexShaderConstants(0, m_vsConstants, 2 + m_numInstances * 3);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
		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);

		// Disable stencil
		m_engine->SetRenderState(D3DRS_STENCILENABLE, FALSE);
/*
		m_engine->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG2);
		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->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);

		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_BLENDOP, D3DBLENDOP_ADD);
		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);

		// Disable stencil
		m_engine->SetRenderState(D3DRS_STENCILENABLE, FALSE);
/*
		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)
{
	// Chain call to base class
	CRuShader_ru2DFX_Base::BeginPass(passNumber);

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);
		m_engine->SetVertexShaderConstants(0, m_vsConstants, 2 + m_numInstances * 3);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
		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, m_stencilID);
		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)
{
	// Chain call to base class
	CRuShader_ru2DFX_Base::BeginPass(passNumber);

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);
		m_engine->SetVertexShaderConstants(0, m_vsConstants, 2 + m_numInstances * 3);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
		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, m_stencilID);
		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);
	}
}

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

const char *CRuShader_ru2DFXTYPE_BLIT_MASK_Z::GetShaderName() const
{
	return "ru2DFXTYPE_BLIT_MASK_Z";
}

void CRuShader_ru2DFXTYPE_BLIT_MASK_Z::BeginPass(INT32 passNumber)
{
	// Chain call to base class
	CRuShader_ru2DFX_Base::BeginPass(passNumber);

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);
		m_engine->SetVertexShaderConstants(0, m_vsConstants, 2 + m_numInstances * 3);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
		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_EQUAL);
		m_engine->SetRenderState(D3DRS_ALPHAREF, 0);

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

		// Disable color writes
		m_engine->SetRenderState(D3DRS_COLORWRITEENABLE, 0);

		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_Z::EndPass(INT32 passNumber)
{
	// Enable color writes
	m_engine->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE);
}

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

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)
{
	// Chain call to base class
	CRuShader_ru2DFX_Base::BeginPass(passNumber);

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(m_pixelShader);
		m_engine->SetVertexShaderConstants(0, m_vsConstants, 2 + m_numInstances * 3);

		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
		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);

		// Disable stencil
		m_engine->SetRenderState(D3DRS_STENCILENABLE, FALSE);

		// 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)
{
	// Chain call to base class
	CRuShader_ru2DFX_Base::BeginPass(passNumber);

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);
		m_engine->SetVertexShaderConstants(0, m_vsConstants, 2 + m_numInstances * 3);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
		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);

		// Disable stencil
		m_engine->SetRenderState(D3DRS_STENCILENABLE, FALSE);

		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_CUTOFF::CRuShader_ru2DFXTYPE_CUTOFF(CRuEngineD3D *engine)
:	CRuShader_ru2DFX_Base(engine)
{
	char *psSource = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	def					c1,			0.0, 0.0, 0.0, 1.0																\n\
	def					c2,			0.45, 0.45, 0.45, 0.0															\n\
	def					c3,			5.85, 5.85, 5.85, 1.0																\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample diffuse texture						\n\
																													\n\
	; Arithmetic ops																								\n\
	mul					r1,			t0,			v0					; Modulate diffuse color by texture color		\n\
	sub_sat				r0,			r1,			c2					; Subtract cutoff								\n\
	mul_sat				r0,			r0,			c3					; Scale so positive values are in [0, 1]		\n\
	";

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

const char *CRuShader_ru2DFXTYPE_CUTOFF::GetShaderName() const
{
	return "ru2DFXTYPE_CUTOFF";
}

void CRuShader_ru2DFXTYPE_CUTOFF::BeginPass(INT32 passNumber)
{
	// Chain call to base class
	CRuShader_ru2DFX_Base::BeginPass(passNumber);

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(m_pixelShader);
		m_engine->SetVertexShaderConstants(0, m_vsConstants, 2 + m_numInstances * 3);

		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
		m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
		m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);

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

		// Disable stencil
		m_engine->SetRenderState(D3DRS_STENCILENABLE, FALSE);

		// 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);
	}
}

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

CRuShader_ru2DFXTYPE_EXPONENTIATE::CRuShader_ru2DFXTYPE_EXPONENTIATE(CRuEngineD3D *engine)
:	CRuShader_ru2DFX_Base(engine)
{
	char *psSource = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	def					c2,			0.75, 0.75, 0.75, 0.0															\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample diffuse texture						\n\
																													\n\
	; Arithmetic ops																								\n\
	mul					r0,			t0,			v0					; Modulate diffuse color by texture color		\n\
	mul					r0.xyz,		r0,			r0					; x^2											\n\
	mul					r0.xyz,		r0,			r0					; x^4											\n\
	mul					r0.xyz,		r0,			r0					; x^8											\n\
	;mul					r1,			r0,			r0					; x^4											\n\
	;mul					r0,			r1,			r1					; x^8											\n\
	;mul					r1,			r0,			r0					; x^16											\n\
	;mov					r0,			r1								; Store to output								\n\
	";

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

const char *CRuShader_ru2DFXTYPE_EXPONENTIATE::GetShaderName() const
{
	return "ru2DFXTYPE_EXPONENTIATE";
}

void CRuShader_ru2DFXTYPE_EXPONENTIATE::BeginPass(INT32 passNumber)
{
	// Chain call to base class
	CRuShader_ru2DFX_Base::BeginPass(passNumber);

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(m_pixelShader);
		m_engine->SetVertexShaderConstants(0, m_vsConstants, 2 + m_numInstances * 3);

		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
		m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
		m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);

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

		// Disable stencil
		m_engine->SetRenderState(D3DRS_STENCILENABLE, FALSE);

		// 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);
	}
}

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

CRuShader_ru2DFXTYPE_GAUSSIAN::CRuShader_ru2DFXTYPE_GAUSSIAN(CRuEngineD3D *engine)
:	CRuShader_ru2DFX_Base(engine),
	m_blurDirection(0)
{
	char *vsSource_Pass_0 = "\
																													\n\
	// Globals																										\n\
	float4				g_globalParams : register(c0);		// (rotation, aspect ratio X:Y, sin(t), cos(t))			\n\
	float4				g_texParams : register(c1);			// (1 / w, 1 / h, 0, 0)									\n\
	float4				g_instanceData[252] : register(c2);															\n\
																													\n\
	struct VS_INPUT																									\n\
	{																												\n\
		float4			position : POSITION;																		\n\
		float4			diffuse : COLOR;																			\n\
		float2			texcoord : TEXCOORD;																		\n\
	};																												\n\
																													\n\
	struct VS_OUTPUT																								\n\
	{																												\n\
		float4			position : POSITION;																		\n\
		float4			diffuse  : COLOR;																			\n\
		float2			tex_L1   : TEXCOORD0;																		\n\
		float2			tex_L2   : TEXCOORD1;																		\n\
		float2			tex_L3   : TEXCOORD2;																		\n\
		float2			tex_C    : TEXCOORD3;																		\n\
		float2			tex_R3   : TEXCOORD4;																		\n\
		float2			tex_R2   : TEXCOORD5;																		\n\
		float2			tex_R1   : TEXCOORD6;																		\n\
	};																												\n\
																													\n\
	VS_OUTPUT main(const VS_INPUT v)																				\n\
	{																												\n\
		VS_OUTPUT output;																							\n\
																													\n\
		float i0 = (v.diffuse.w * 255.5) * 3;																		\n\
		float i1 = i0 + 1;																							\n\
		float i2 = i1 + 1;																							\n\
																													\n\
		float4 var_x0_u0_y0_v0 = g_instanceData[i0];																\n\
		float4 var_x1_u1_y1_v1 = g_instanceData[i1];																\n\
																													\n\
		float centroidX = (var_x1_u1_y1_v1[0] + var_x0_u0_y0_v0[0]) * 0.5f;											\n\
		float centroidY = (var_x1_u1_y1_v1[2] + var_x0_u0_y0_v0[2]) * 0.5f;											\n\
																													\n\
		float2 lrp_x_u = lerp(var_x1_u1_y1_v1, var_x0_u0_y0_v0, v.diffuse.x).xy;									\n\
		float2 lrp_y_v = lerp(var_x1_u1_y1_v1, var_x0_u0_y0_v0, v.diffuse.y).zw;									\n\
																													\n\
		float relX = lrp_x_u[0] - centroidX;																		\n\
		float relY = (lrp_y_v[0] - centroidY) / g_globalParams[1];													\n\
																													\n\
		output.position.x = relX * g_globalParams[3] - relY * g_globalParams[2] + centroidX;						\n\
		output.position.y = (relX * g_globalParams[2] + relY * g_globalParams[3]) * g_globalParams[1] + centroidY;	\n\
		output.position.z = 0.0f;																					\n\
		output.position.w = 1.0f;																					\n\
																													\n\
		output.tex_C.x = lrp_x_u[1];																				\n\
		output.tex_C.y = lrp_y_v[1];																				\n\
																													\n\
		float2 hOffset = g_texParams.xz;																			\n\
																													\n\
		output.tex_L3 = output.tex_C - hOffset;																		\n\
		output.tex_L2 = output.tex_L3 - hOffset;																	\n\
		output.tex_L1 = output.tex_L2 - hOffset;																	\n\
		output.tex_R3 = output.tex_C + hOffset;																		\n\
		output.tex_R2 = output.tex_R3 + hOffset;																	\n\
		output.tex_R1 = output.tex_R2 + hOffset;																	\n\
																													\n\
		output.diffuse = g_instanceData[i2];																		\n\
																													\n\
		return output;																								\n\
	}																												\n\
	";

	char *vsSource_Pass_1 = "\
																													\n\
	// Globals																										\n\
	float4				g_globalParams : register(c0);		// (rotation, aspect ratio X:Y, sin(t), cos(t))			\n\
	float4				g_texParams : register(c1);			// (1 / w, 1 / h, 0, 0)									\n\
	float4				g_instanceData[252] : register(c2);															\n\
																													\n\
	struct VS_INPUT																									\n\
	{																												\n\
		float4			position : POSITION;																		\n\
		float4			diffuse : COLOR;																			\n\
		float2			texcoord : TEXCOORD;																		\n\
	};																												\n\
																													\n\
	struct VS_OUTPUT																								\n\
	{																												\n\
		float4			position : POSITION;																		\n\
		float4			diffuse  : COLOR;																			\n\
		float2			tex_L1   : TEXCOORD0;																		\n\
		float2			tex_L2   : TEXCOORD1;																		\n\
		float2			tex_L3   : TEXCOORD2;																		\n\
		float2			tex_C    : TEXCOORD3;																		\n\
		float2			tex_R3   : TEXCOORD4;																		\n\
		float2			tex_R2   : TEXCOORD5;																		\n\
		float2			tex_R1   : TEXCOORD6;																		\n\
	};																												\n\
																													\n\
	VS_OUTPUT main(const VS_INPUT v)																				\n\
	{																												\n\
		VS_OUTPUT output;																							\n\
																													\n\
		float i0 = (v.diffuse.w * 255.5) * 3;																		\n\
		float i1 = i0 + 1;																							\n\
		float i2 = i1 + 1;																							\n\
																													\n\
		float4 var_x0_u0_y0_v0 = g_instanceData[i0];																\n\
		float4 var_x1_u1_y1_v1 = g_instanceData[i1];																\n\
																													\n\
		float centroidX = (var_x1_u1_y1_v1[0] + var_x0_u0_y0_v0[0]) * 0.5f;											\n\
		float centroidY = (var_x1_u1_y1_v1[2] + var_x0_u0_y0_v0[2]) * 0.5f;											\n\
																													\n\
		float2 lrp_x_u = lerp(var_x1_u1_y1_v1, var_x0_u0_y0_v0, v.diffuse.x).xy;									\n\
		float2 lrp_y_v = lerp(var_x1_u1_y1_v1, var_x0_u0_y0_v0, v.diffuse.y).zw;									\n\
																													\n\
		float relX = lrp_x_u[0] - centroidX;																		\n\
		float relY = (lrp_y_v[0] - centroidY) / g_globalParams[1];													\n\
																													\n\
		output.position.x = relX * g_globalParams[3] - relY * g_globalParams[2] + centroidX;						\n\
		output.position.y = (relX * g_globalParams[2] + relY * g_globalParams[3]) * g_globalParams[1] + centroidY;	\n\
		output.position.z = 0.0f;																					\n\
		output.position.w = 1.0f;																					\n\
																													\n\
		output.tex_C.x = lrp_x_u[1];																				\n\
		output.tex_C.y = lrp_y_v[1];																				\n\
																													\n\
		float2 hOffset = g_texParams.zy;																			\n\
																													\n\
		output.tex_L3 = output.tex_C - hOffset;																		\n\
		output.tex_L2 = output.tex_L3 - hOffset;																	\n\
		output.tex_L1 = output.tex_L2 - hOffset;																	\n\
		output.tex_R3 = output.tex_C + hOffset;																		\n\
		output.tex_R2 = output.tex_R3 + hOffset;																	\n\
		output.tex_R1 = output.tex_R2 + hOffset;																	\n\
																													\n\
		output.diffuse = g_instanceData[i2];																		\n\
																													\n\
		return output;																								\n\
	}																												\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					r7.w,		c1.x							; Force alpha to one							\n\
																													\n\
	mov					oC0,		r7								; Move result into output						\n\
	";

	// Create shader
	m_vertexShaders[0] = RuD3DCompileVertexShader(vsSource_Pass_0, "main", "vs_2_0", NULL);
	m_vertexShaders[1]= RuD3DCompileVertexShader(vsSource_Pass_1, "main", "vs_2_0", NULL);

	// 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[4] = 1.000f;
	m_psConstants[5] = 0.000f;
	m_psConstants[6] = 0.000f;
	m_psConstants[7] = 0.000f;

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

	m_vertexDecl->Select();
	m_engine->SetVertexShader(m_vertexShaders[m_blurDirection]);
	m_engine->SetPixelShader(m_pixelShader);
	m_engine->SetVertexShaderConstants(0, m_vsConstants, 2 + m_numInstances * 3);
	m_engine->SetPixelShaderConstants(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);

	// Disable stencil
	m_engine->SetRenderState(D3DRS_STENCILENABLE, FALSE);

	// 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 clamp
	m_engine->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
	m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);

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

void CRuShader_ru2DFXTYPE_GAUSSIAN::EndPass(INT32 passNumber)
{
}

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

	DWORD param;

	if(paramCache->GetParameter(ruPARAMTYPE_DWORD_0, param))
	{
		m_blurDirection = param;
	}
}

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

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_BLENDOP, D3DBLENDOP_ADD);
		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);

		// Disable stencil
		m_engine->SetRenderState(D3DRS_STENCILENABLE, FALSE);

		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);
	}
}

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

#pragma managed
