#include "../../Direct3D/Shader/RuShader_D3D_FX.h"

#pragma unmanaged

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

CRuShader_FX_GhostTrail::CRuShader_FX_GhostTrail(CRuEngineD3D *engine)
:	CRuShader_Base(engine)
{
	// Setup vertex elements
	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()
	};

	// Construct vertex declaration
	m_vertexDecl = m_engine->CreateVertexDeclaration(vertexElements);

	// Vertex shader source
	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position 0							\n\
	dcl_texcoord0		v4											; Declare input texture coordinates 0			\n\
	dcl_color			v12											; Declare diffuse								\n\
																													\n\
	mov					r0,			c20.yyyy						; Move 1 into r0								\n\
	mov					r1,			c20.yyyy						; Move 1 into r1								\n\
	mov					r2,			c20.yyyy						; Move 1 into r1								\n\
																													\n\
	; Calculate position																							\n\
	m4x3				r1,			v0,			c0					; Transform vertex to world space				\n\
	m4x3				r0,			r1,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r0,			c6					; Transform vertex to homogeneous space			\n"
	"																												\n\
	; Fog factor																									\n\
	mov					oFog,		c20.y							; Output fog factor (constant 1.0)				\n"
	"																												\n\
	; Diffuse color																									\n\
	mul					r4,			v12,		c26					; Multiply diffuse by global diffuse			\n\
	mov					oD0,		r4								; Set diffuse									\n\
																													\n\
	; Calculate texture coordinates																					\n\
	mov					oT0,		v4																				\n\
	";

	// Assemble vertex shader
	m_vertexShader = RuD3DAssembleVertexShader(vsSource);

	// Overrides
	m_override_ZWrite = TRUE;
}

CRuShader_FX_GhostTrail::~CRuShader_FX_GhostTrail()
{
}

void CRuShader_FX_GhostTrail::BeginPass(INT32 passNumber)
{
	// Call base BeginPass to perform any additional setup
	CRuShader_Base::BeginPass(passNumber);

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);
		m_engine->GetD3DDevice()->SetVertexShaderConstantF(0, m_shaderConstants, m_numBaseConstants + 1);

		m_engine->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

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

		m_engine->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);

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

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

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

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

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

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

void CRuShader_FX_GhostTrail::EndPass(INT32 passNumber)
{
	m_engine->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
}

void CRuShader_FX_GhostTrail::SetParameters(const CRuParameterCache *paramCache)
{
	CRuShader_Base::SetParameters(paramCache);
}

void CRuShader_FX_GhostTrail::Instance(INT32 streamIndex, IRuMesh *mesh, UINT32 morphTargetIndex, void *buffer) const
{
	if(streamIndex == 0)
	{
		CRuVertex_Static_Prelit *vertices = (CRuVertex_Static_Prelit *) buffer;
		IRuMorphTarget *morphTarget = mesh->GetMorphTarget(morphTargetIndex);
		const CRuVector3 *position = morphTarget->GetPosition();
		const DWORD *diffuse = morphTarget->GetDiffuse();
		const float *uv = morphTarget->GetTextureCoordinate(ruTEXCHANNEL_DIFFUSEMAP);

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

					vertices[i].diffuse = diffuse[i];

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


		}
	}
}

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

CRuShader_FX_Decal::CRuShader_FX_Decal(CRuEngineD3D *engine)
:	CRuShader_Base(engine)
{
	m_override_AlphaTest = TRUE;
	m_force_AlphaBlend = TRUE;

	// Setup vertex elements
	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()
	};

	// Construct vertex declaration
	m_vertexDecl = m_engine->CreateVertexDeclaration(vertexElements);

	// Vertex shader source
	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position 0							\n\
	dcl_texcoord0		v4											; Declare input texture coordinates 0			\n\
	dcl_color			v12											; Declare diffuse								\n\
																													\n\
	mov					r0,			c20.yyyy						; Move 1 into r0								\n\
	mov					r1,			c20.yyyy						; Move 1 into r1								\n\
	mov					r2,			c20.yyyy						; Move 1 into r1								\n\
																													\n\
	; Calculate position																							\n\
	m4x3				r0,			v0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r0,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	; Fog factor																									\n\
	mov					oFog,		c20.y							; Output fog factor (constant 1.0)				\n\
																													\n\
	; Diffuse color																									\n\
	mul					r4,			v12,		c26					; Multiply diffuse by global diffuse			\n\
	mov					oD0,		r4								; Set diffuse									\n\
																													\n\
	; Calculate texture coordinates																					\n\
	m4x4				oT0,		v0,			c27					; Transform vertex to uv space into T0			\n\
	";

	char *psSource = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; DIFFUSE										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xyzw																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
																													\n\
	rcp					r0,			t0.w							; Get 1/w										\n\
	mul					r0,			t0,			r0					; Divide by w									\n\
																													\n\
	texld				r1,			r0,			s0					; Sample DIFFUSE into R1						\n\
	mul					r1,			r1,			v0					; Modulate by diffuse color						\n\
																													\n\
	mov					oC0,		r1								; Move result into output						\n\
	";

	// Assemble vertex shader
	m_vertexShader = RuD3DAssembleVertexShader(vsSource);

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

	// Overrides
	m_override_ZWrite = TRUE;
}

CRuShader_FX_Decal::~CRuShader_FX_Decal()
{
}

void CRuShader_FX_Decal::BeginPass(INT32 passNumber)
{
	// Call base BeginPass to perform any additional setup
	CRuShader_Base::BeginPass(passNumber);

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(m_pixelShader);
		m_engine->GetD3DDevice()->SetVertexShaderConstantF(0, m_shaderConstants, m_numBaseConstants + 1);
		m_engine->GetD3DDevice()->SetPixelShaderConstantF(0, m_pixelShaderConstants, m_numBasePixelShaderConstants);

		m_engine->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

		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_FILLMODE, D3DFILL_SOLID);

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

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

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

void CRuShader_FX_Decal::EndPass(INT32 passNumber)
{
	m_engine->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
}

void CRuShader_FX_Decal::SetParameters(const CRuParameterCache *paramCache)
{
	CRuShader_Base::SetParameters(paramCache);

	DWORD param;

	if(paramCache->GetParameter(ruPARAMTYPE_TEXTURE_TRANSFORM_0, param))
	{
		INT32 uvTransformOffset = 108;

		CRuMatrix4x4 *transform = (CRuMatrix4x4 *) param;

		for(UINT32 i = 0, k = uvTransformOffset; i < 4; ++i)
		{
			for(UINT32 j = 0; j < 4; ++j, ++k)
			{
				m_shaderConstants[k] = transform->m_elements[j][i];
			}
		}
	}

}

void CRuShader_FX_Decal::Instance(INT32 streamIndex, IRuMesh *mesh, UINT32 morphTargetIndex, void *buffer) const
{
	if(streamIndex == 0)
	{
		CRuVertex_Static_Prelit *vertices = (CRuVertex_Static_Prelit *) buffer;
		IRuMorphTarget *morphTarget = mesh->GetMorphTarget(morphTargetIndex);
		const CRuVector3 *position = morphTarget->GetPosition();
		const DWORD *diffuse = morphTarget->GetDiffuse();
		const float *uv = morphTarget->GetTextureCoordinate(ruTEXCHANNEL_DIFFUSEMAP);

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

					vertices[i].diffuse = diffuse[i];

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


		}
	}
}

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

#pragma managed
