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

#pragma unmanaged

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

CRuShader_NULL::CRuShader_NULL(CRuEngineD3D *engine)
:	CRuShader_Static_Base(engine)
{
	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
																													\n\
	; Transform position into homogeneous space																		\n\
	mov					r0,			c20.yyyy						; Move 1 into r0								\n\
	mov					r1,			c20.yyyy						; Move 1 into r1								\n\
	m4x3				r0,			v0,			c0					; Transform vertex to world space				\n\
	m4x3				r1,			r0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	mov					oD0,		c20.yyyy						; Set diffuse									\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();
}

CRuShader_NULL::~CRuShader_NULL()
{
}

void CRuShader_NULL::BeginPass(INT32 passNumber)
{
	// Call base BeginPass to perform any additional setup
	CRuShader_Static_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);

		m_engine->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		m_engine->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);

		m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);

		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_NULL::EndPass(INT32 passNumber)
{
	m_engine->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
}

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

CRuShader_Gizmo::CRuShader_Gizmo(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 },
		RUVERTEXDECL_END()
	};

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

	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_color			v2											; Declare diffuse								\n\
																													\n\
	; Transform position into homogeneous space																		\n\
	mov					r0,			c20.yyyy						; Move 1 into r0								\n\
	mov					r1,			c20.yyyy						; Move 1 into r1								\n\
	m4x3				r0,			v0,			c0					; Transform vertex to world space				\n\
	m4x3				r1,			r0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	mov					oD0,		v2								; Set diffuse									\n\
	";

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

CRuShader_Gizmo::~CRuShader_Gizmo()
{
}

void CRuShader_Gizmo::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);

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

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

void CRuShader_Gizmo::EndPass(INT32 passNumber)
{
	// Call base BeginPass to perform any additional cleanup
	CRuShader_Base::EndPass(passNumber);

	m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
}

void CRuShader_Gizmo::Instance(INT32 streamIndex, IRuMesh *mesh, UINT32 morphTargetIndex, void *buffer) const
{
	if(streamIndex == 0)
	{
		CRuVertex_Bare_Colored *vertices = (CRuVertex_Bare_Colored *) buffer;
		IRuMorphTarget *morphTarget = mesh->GetMorphTarget(morphTargetIndex);
		const DWORD *diffuse = morphTarget->GetDiffuse();

		if(morphTarget)
		{
			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;

				if(diffuse)
				{
					vertices[i].diffuse = diffuse[i];
				}
				else
				{
					vertices[i].diffuse = 0xFFFFFFFF;
				}
			}
		}
	}
}

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

CRuShader_Static_Flat::CRuShader_Static_Flat(CRuEngineD3D *engine)
:	CRuShader_Static_Base(engine)
{
/*
	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_normal0			v1											; Declare normal								\n\
	dcl_texcoord0		v5											; Declare input texcoord 0						\n\
	dcl_position1		v2											; Declare position								\n\
	dcl_normal1			v3											; Declare normal								\n\
																													\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\
	; Tween	position																								\n\
	mov					r1.x,		c25.w																			\n\
	mul					r0.xyz,		v2,			r1.x																\n\
	sub					r1.x,		c20.y,		r1.x																\n\
	mad					r2.xyz,		v0,			r1.x,		r0														\n\
																													\n\
	; Transform position into homogeneous space																		\n\
	m4x3				r0.xyz,		r2,			c0					; Transform vertex to world space				\n\
	m4x3				r1.xyz,		r0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	; Fog factor																									\n\
	sub					r2.x,		c25.z,		c25.y				; Fog End - Fog Start into r2.x					\n\
	rcp					r2.x,		r2.x							; Reciprocal of fog range into r0.x				\n\
	sub					r3.x,		r1.z,		c25.y				; Offset vertex z by fog start into r3.x		\n\
	mul					r2.x,		r3.x,		r2.x				; Divide z by fog range into r0					\n\
	sub					r2.x,		c20.y,		r2.x				; Invert fog factor								\n\
	max					r2.x,		r2.x,		c20.w				; Clamp to [0, 1]								\n\
	min					r2.x,		r2.x,		c20.y																\n\
	mov					oFog,		r2.x							; Output fog factor								\n"
	"																												\n\
	; Ambient lighting into r4																						\n\
	mov					r4,			c10																				\n\
																													\n\
	; Tween	normal																								\n\
	mov					r1.x,		c25.w																			\n\
	mul					r0.xyz,		v3,			r1.x																\n\
	sub					r1.x,		c20.y,		r1.x																\n\
	mad					r2.xyz,		v1,			r1.x,		r0														\n\
																													\n\
	; Object-level spherical harmonics																				\n\
	add					r4,			c11,		r4					; Constant term									\n\
	mad					r4,			c12,		r2.x,		r4		; 1st-order terms								\n\
	mad					r4,			c13,		r2.y,		r4														\n\
	mad					r4,			c14,		r2.z,		r4														\n\
	mul					r5.x,		r2.x,		r2.z				; X * Z											\n\
	mul					r5.y,		r2.z,		r2.y				; Z * Y											\n\
	mul					r5.z,		r2.y,		r2.x				; Y * X											\n\
	mad					r4,			c15,		r5.x,		r4		; 2nd-order terms								\n\
	mad					r4,			c16,		r5.y,		r4														\n\
	mad					r4,			c17,		r5.z,		r4														\n\
	mul					r5.xyz,		r2,			r2																	\n\
	mul					r5.z,		r5.z,		c20.x																\n\
	sub					r5.z,		r5.z,		c20.y																\n\
	mad					r4,			c18,		r5.z,		r4														\n\
	sub					r5.x,		r5.x,		r5.y																\n\
	mad					r4,			c19,		r5.x,		r4														\n\
																													\n\
	; Diffuse color																									\n\
	mov					r4.w,		c25.x							; Set light alpha to global alpha				\n\
	mov					oD0,		r4								; Set diffuse									\n\
																													\n\
	mov					oT0,		v5								; Copy texture coordinates to output			\n\
																													\n\
	mov					r0,			c20.yyyy						; Move 1 into r1								\n\
	m4x3				r0.xyz,		v0,			c0					; Transform vertex to world space				\n\
	m4x4				oT1,		r0,			c26					; Transform vertex to light homogeneous space	\n\
	mov					oT2,		c30								; Copy object ID								\n\
	";

	char *psSource = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample diffuse texture						\n\
																													\n\
	; Arithmetic ops																								\n\
	mul					r0,			t0,			v0					; Modulate texture with diffuse					\n\
	";
*/

	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_normal			v1											; Declare normal								\n\
	dcl_texcoord0		v5											; Declare input texcoord 0						\n\
																													\n\
	; Transform position into homogeneous space																		\n\
	mov					r0,			c20.yyyy						; Move 1 into r0								\n\
	mov					r1,			c20.yyyy						; Move 1 into r1								\n\
	m4x3				r0.xyz,		v0,			c0					; Transform vertex to world space				\n\
	m4x3				r1.xyz,		r0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	; Fog factor																									\n\
	sub					r2.x,		c25.z,		c25.y				; Fog End - Fog Start into r2.x					\n\
	rcp					r2.x,		r2.x							; Reciprocal of fog range into r0.x				\n\
	sub					r3.x,		r1.z,		c25.y				; Offset vertex z by fog start into r3.x		\n\
	mul					r2.x,		r3.x,		r2.x				; Divide z by fog range into r0					\n\
	sub					r2.x,		c20.y,		r2.x				; Invert fog factor								\n\
	max					r2.x,		r2.x,		c20.w				; Clamp to [0, 1]								\n\
	min					r2.x,		r2.x,		c20.y																\n\
	mov					oFog,		r2.x							; Output fog factor								\n"
	"																												\n\
	; Ambient lighting into r4																						\n\
	mov					r4,			c10																				\n\
																													\n\
	; Object-level spherical harmonics																				\n\
	add					r4,			c11,		r4					; Constant term									\n\
	mad					r4,			c12,		v1.x,		r4		; 1st-order terms								\n\
	mad					r4,			c13,		v1.y,		r4														\n\
	mad					r4,			c14,		v1.z,		r4														\n\
	mul					r5.x,		v1.x,		v1.z				; X * Z											\n\
	mul					r5.y,		v1.z,		v1.y				; Z * Y											\n\
	mul					r5.z,		v1.y,		v1.x				; Y * X											\n\
	mad					r4,			c15,		r5.x,		r4		; 2nd-order terms								\n\
	mad					r4,			c16,		r5.y,		r4														\n\
	mad					r4,			c17,		r5.z,		r4														\n\
	mul					r5.xyz,		v1,			v1																	\n\
	mul					r5.z,		r5.z,		c20.x																\n\
	sub					r5.z,		r5.z,		c20.y																\n\
	mad					r4,			c18,		r5.z,		r4														\n\
	sub					r5.x,		r5.x,		r5.y																\n\
	mad					r4,			c19,		r5.x,		r4														\n\
																													\n\
	; Diffuse color																									\n\
	mov					r4.w,		c20.y							; Set diffuse alpha to one						\n\
	mul					r4,			r4,			c26					; Multiply diffuse by global diffuse			\n\
	mov					oD0,		r4								; Set diffuse									\n"
	"																												\n\
	mov					oT0,		v5								; Copy texture coordinates to output			\n\
	";

	char *psSource = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample diffuse texture						\n\
																													\n\
	; Arithmetic ops																								\n\
	mul					r0,			t0,			v0					; Modulate texture with diffuse					\n\
	";

/*
	char *psSource = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; DIFFUSE										\n\
	dcl_2d				s1											; SHADOW										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xyzw																						\n\
	dcl					t1.xyzw																						\n\
																													\n\
	rcp					r0,			t1.w							; Get 1/w										\n\
	mul					r0,			t1,			r0					; Divide by w									\n\
	mul					r1,			r0,			c0.y				; Scale t1 by 0.5								\n\
	add					r1,			r1,			c0.y				; Bias by 0.5									\n\
	add					r1.y,		c0.x,		-r1.y				; Invert y										\n\
																													\n\
	texld				r2,			r1,			s1					; Sample SHADOW into R2							\n\
																													\n\
	sub					r3.z,		r2.x,		r0.z				; Shadow z - object light z						\n\
	cmp					r0,			r3.z,		c0.x,		c0.y	;												\n\
																													\n\
	texld				r1,			t0,			s0					; Sample DIFFUSE into R1						\n\
	mul					r0,			r0,			r1					; 									\n\
																													\n\
	mov					oC0,		r0								; Move result into output						\n\
	";
*/
/*
	char *psSource = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; DIFFUSE										\n\
	dcl_2d				s1											; SHADOW										\n\
																													\n\
	def					c2,			0.01, 0.2, 0, 0.002																\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xyzw																						\n\
	dcl					t1.xyzw																						\n\
	dcl					t2.xyzw																						\n\
																													\n\
	rcp					r0,			t1.w							; Get 1/w										\n\
	mul					r0,			t1,			r0					; Divide by w									\n\
	mul					r1,			r0,			c0.y				; Scale t1 by 0.5								\n\
	add					r1,			r1,			c0.y				; Bias by 0.5									\n\
	add					r1.y,		c0.x,		-r1.y				; Invert y										\n\
																													\n\
	; Sample center																									\n\
	texld				r2,			r1,			s1					; Sample SHADOW object ID into R2				\n\
																													\n\
	sub					r3,			r2,			t2					; Subtract object IDs							\n\
	abs					r3,			r3								; Get absolute value							\n\
	dp3					r3,			r3,			c0.x				; Add up difference								\n\
	sub					r3,			c2.x,		r3					; Negate										\n\
	cmp					r4,			r3.x,		c2.z,		c2.y	; Set shadow factor								\n\
																													\n\
	; Sample top																									\n\
	sub					r1.y,		r1.y,		c2.w				; Offset uv										\n\
	texld				r2,			r1,			s1					; Sample SHADOW object ID into R2				\n\
																													\n\
	sub					r3,			r2,			t2					; Subtract object IDs							\n\
	abs					r3,			r3								; Get absolute value							\n\
	dp3					r3,			r3,			c0.x				; Add up difference								\n\
	sub					r3,			c2.x,		r3					; Negate										\n\
	cmp					r0,			r3.x,		c2.z,		c2.y	; Set shadow factor								\n\
	add					r4,			r4,			r0					; Accumulate shadow factor into R4				\n"
	"																												\n\
	; Sample bottom																									\n\
	add					r1.y,		r1.y,		c2.w				; Offset uv										\n\
	add					r1.y,		r1.y,		c2.w				; Offset uv										\n\
	texld				r2,			r1,			s1					; Sample SHADOW object ID into R2				\n\
																													\n\
	sub					r3,			r2,			t2					; Subtract object IDs							\n\
	abs					r3,			r3								; Get absolute value							\n\
	dp3					r3,			r3,			c0.x				; Add up difference								\n\
	sub					r3,			c2.x,		r3					; Negate										\n\
	cmp					r0,			r3.x,		c2.z,		c2.y	; Set shadow factor								\n\
	add					r4,			r4,			r0					; Accumulate shadow factor into R4				\n\
																													\n\
	; Adjust r4																										\n\
	sub					r4.xyz,		c0.x,		r4																	\n\
	mov					r4.w,		c0.x																			\n\
																													\n\
	texld				r1,			t0,			s0					; Sample DIFFUSE into R1						\n\
	mul					r0,			r4,			r1					; 									\n\
																													\n\
	mov					oC0,		r0								; Move result into 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();
}

CRuShader_Static_Flat::~CRuShader_Static_Flat()
{
}

void CRuShader_Static_Flat::BeginPass(INT32 passNumber)
{
	// Call base BeginPass to perform any additional setup
	CRuShader_Static_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_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_WRAP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);

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

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

void CRuShader_Static_Flat::EndPass(INT32 passNumber)
{
}

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

	CRuShader_Static_Base::SetParameters(paramCache);

	if(paramCache->GetParameter(ruPARAMTYPE_TRANSFORM_SHADOW, param))
	{
		CRuMatrix4x4 *transform = (CRuMatrix4x4 *) param;

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

	if(paramCache->GetParameter(ruPARAMTYPE_SHADOW_OBJECTID, param))
	{
		INT32 constantOffset = 30 * 4;
/*
		m_shaderConstants[constantOffset++] = ((param / (35 * 35)) * 7 + 8) / 255.0f;
		m_shaderConstants[constantOffset++] = (((param % (35 * 35)) / 35) * 7 + 8) / 255.0f;
		m_shaderConstants[constantOffset++] = ((param % 35) * 7 + 8) / 255.0f;
		m_shaderConstants[constantOffset++] = 0.0f;
*/
		m_shaderConstants[constantOffset++] = ((param / (35 * 35)) * 7) / 255.0f;
		m_shaderConstants[constantOffset++] = (((param % (35 * 35)) / 35) * 7) / 255.0f;
		m_shaderConstants[constantOffset++] = ((param % 35) * 7) / 255.0f;
		m_shaderConstants[constantOffset++] = 0.0f;

	}
}

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

CRuShader_Static_SH9::CRuShader_Static_SH9(CRuEngineD3D *engine)
:	CRuShader_Static_Base(engine)
{
	char *vsSource = "\
																													\n\
	// Globals																										\n\
	float4x3			g_worldTransform : register(c0);															\n\
	float4x3			g_viewTransform : register(c3);																\n\
	float4x4			g_projectionTransform : register(c6);														\n\
																													\n\
	float4				g_ambientColor : register(c10);																\n\
	float4				g_shCoefficients[9] : register(c11);														\n\
	float4				g_selfIllumination : register(c23);															\n\
	float4				g_globalSettings : register(c25);		// (?, Fog Start, Fog End, Tween Factor)			\n\
	float4				g_globalDiffuse : register(c26);															\n\
																													\n\
	struct VS_INPUT																									\n\
	{																												\n\
		float4			position : POSITION;																		\n\
		float3			normal : NORMAL;																			\n\
		float2			texcoord : TEXCOORD;																		\n\
	};																												\n\
																													\n\
	struct VS_OUTPUT																								\n\
	{																												\n\
		float4			position : POSITION;																		\n\
		float4			color : COLOR;																				\n\
		float2			texcoord : TEXCOORD;																		\n\
		float1			fog : FOG;																					\n\
	};																												\n\
																													\n\
	VS_OUTPUT main(const VS_INPUT v)																				\n\
	{																												\n\
		VS_OUTPUT output;																							\n\
																													\n\
		// Initialize world-view vectors to 1																		\n\
		float4 worldPos = float4(1, 1, 1, 1);																		\n\
		float4 viewPos = float4(1, 1, 1, 1);																		\n\
																													\n\
		// Transform position to projected space																	\n\
		worldPos.xyz = mul(v.position, (float4x3) g_worldTransform);												\n\
		viewPos.xyz = mul(worldPos, (float4x3) g_viewTransform);													\n\
		output.position = mul(viewPos, (float4x4) g_projectionTransform);											\n\
																													\n\
		// Calculate fog																							\n\
		float1 rcpFogRange = 1.0f / (g_globalSettings.z - g_globalSettings.y);										\n\
		float1 relativeZ = viewPos.z - g_globalSettings.y;															\n\
		output.fog = clamp(1.0f - (relativeZ * rcpFogRange), 0.0f, 1.0f);											\n\
																													\n\
		// Accumulate ambient color																					\n\
		output.color = g_ambientColor;																				\n\
																													\n\
		// Accumulate SH color																						\n\
		output.color += g_shCoefficients[0];																		\n\
		output.color += g_shCoefficients[1] * (float4) v.normal.x;													\n\
		output.color += g_shCoefficients[2] * (float4) v.normal.y;													\n\
		output.color += g_shCoefficients[3] * (float4) v.normal.z;													\n\
		output.color += g_shCoefficients[4] * (float4) (v.normal.x * v.normal.z);									\n\
		output.color += g_shCoefficients[5] * (float4) (v.normal.z * v.normal.y);									\n\
		output.color += g_shCoefficients[6] * (float4) (v.normal.y * v.normal.x);									\n\
		output.color += g_shCoefficients[7] * (float4) (3 * v.normal.z * v.normal.z - 1);							\n\
		output.color += g_shCoefficients[8] * (float4) (v.normal.x * v.normal.x - v.normal.y * v.normal.y);			\n\
																													\n\
		// Accumulate global diffuse and self illumination															\n\
		output.color.w = 1;																							\n\
		output.color *= g_globalDiffuse;																			\n\
		output.color += (float4) g_selfIllumination.x;																\n\
																													\n\
		// Copy texture coordinates																					\n\
		output.texcoord = v.texcoord;																				\n\
																													\n\
		return output;																								\n\
	}																												\n\
	";
/*
	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_normal			v1											; Declare normal								\n\
	dcl_texcoord0		v5											; Declare input texcoord 0						\n\
																													\n\
	; Transform position into homogeneous space																		\n\
	mov					r0,			c20.yyyy						; Move 1 into r0								\n\
	mov					r1,			c20.yyyy						; Move 1 into r1								\n\
	m4x3				r0.xyz,		v0,			c0					; Transform vertex to world space				\n\
	m4x3				r1.xyz,		r0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	; Fog factor																									\n\
	sub					r2.x,		c25.z,		c25.y				; Fog End - Fog Start into r2.x					\n\
	rcp					r2.x,		r2.x							; Reciprocal of fog range into r0.x				\n\
	sub					r3.x,		r1.z,		c25.y				; Offset vertex z by fog start into r3.x		\n\
	mul					r2.x,		r3.x,		r2.x				; Divide z by fog range into r0					\n\
	sub					r2.x,		c20.y,		r2.x				; Invert fog factor								\n\
	max					r2.x,		r2.x,		c20.w				; Clamp to [0, 1]								\n\
	min					r2.x,		r2.x,		c20.y																\n\
	mov					oFog,		r2.x							; Output fog factor								\n"
	"																												\n\
	; Ambient lighting into r4																						\n\
	mov					r4,			c10																				\n\
																													\n\
	; Object-level spherical harmonics																				\n\
	add					r4,			c11,		r4					; Constant term									\n\
	mad					r4,			c12,		v1.x,		r4		; 1st-order terms								\n\
	mad					r4,			c13,		v1.y,		r4														\n\
	mad					r4,			c14,		v1.z,		r4														\n\
	mul					r5.x,		v1.x,		v1.z				; X * Z											\n\
	mul					r5.y,		v1.z,		v1.y				; Z * Y											\n\
	mul					r5.z,		v1.y,		v1.x				; Y * X											\n\
	mad					r4,			c15,		r5.x,		r4		; 2nd-order terms								\n\
	mad					r4,			c16,		r5.y,		r4														\n\
	mad					r4,			c17,		r5.z,		r4														\n\
	mul					r5.xyz,		v1,			v1																	\n\
	mul					r5.z,		r5.z,		c20.x																\n\
	sub					r5.z,		r5.z,		c20.y																\n\
	mad					r4,			c18,		r5.z,		r4														\n\
	sub					r5.x,		r5.x,		r5.y																\n\
	mad					r4,			c19,		r5.x,		r4														\n\
																													\n\
	; Diffuse color																									\n\
	mov					r4.w,		c20.y							; Set diffuse alpha to one						\n\
	mul					r4,			r4,			c26					; Multiply diffuse by global diffuse			\n\
	add					r4.xyz,		r4.xyz,		c23.x				; Add self-illumination term					\n\
	mov					oD0,		r4								; Output diffuse								\n"
	"																												\n\
	; Texture coordinates																							\n\
	mov					oT0,		v5								; Copy diffuse texture coordinates to output	\n\
	";
*/
	char *psSource = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample diffuse texture						\n\
																													\n\
	; Arithmetic ops																								\n\
	mul					r0,			t0,			v0					; Modulate diffuse texture with diffuse color	\n\
	";

	// Assemble vertex shader
//	m_vertexShader = RuD3DAssembleVertexShader(vsSource);
	m_vertexShader = RuD3DCompileVertexShader(vsSource, "main", "vs_1_1", NULL);

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

CRuShader_Static_SH9::~CRuShader_Static_SH9()
{
}

void CRuShader_Static_SH9::BeginPass(INT32 passNumber)
{
	// Call base BeginPass to perform any additional setup
	CRuShader_Static_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 + 2);
		m_engine->GetD3DDevice()->SetPixelShaderConstantF(0, m_pixelShaderConstants, m_numBasePixelShaderConstants);

		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_WRAP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
	}
}

void CRuShader_Static_SH9::EndPass(INT32 passNumber)
{
}

void CRuShader_Static_SH9::SetParameters(const CRuParameterCache *paramCache)
{
	CRuShader_Static_Base::SetParameters(paramCache);
}

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

CRuShader_Static_SH9_Gloss::CRuShader_Static_SH9_Gloss(CRuEngineD3D *engine)
:	CRuShader_Static_Base(engine)
{
	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_normal			v1											; Declare normal								\n\
	dcl_texcoord0		v5											; Declare input texcoord 0						\n\
																													\n\
	; Transform position into homogeneous space																		\n\
	mov					r0,			c20.yyyy						; Move 1 into r0								\n\
	mov					r1,			c20.yyyy						; Move 1 into r1								\n\
	m4x3				r0.xyz,		v0,			c0					; Transform vertex to world space				\n\
	m4x3				r1.xyz,		r0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	; Fog factor																									\n\
	sub					r2.x,		c25.z,		c25.y				; Fog End - Fog Start into r2.x					\n\
	rcp					r2.x,		r2.x							; Reciprocal of fog range into r0.x				\n\
	sub					r3.x,		r1.z,		c25.y				; Offset vertex z by fog start into r3.x		\n\
	mul					r2.x,		r3.x,		r2.x				; Divide z by fog range into r0					\n\
	sub					r2.x,		c20.y,		r2.x				; Invert fog factor								\n\
	max					r2.x,		r2.x,		c20.w				; Clamp to [0, 1]								\n\
	min					r2.x,		r2.x,		c20.y																\n\
	mov					oFog,		r2.x							; Output fog factor								\n"
	"																												\n\
	; Ambient lighting into r4																						\n\
	mov					r4,			c10																				\n\
																													\n\
	; Object-level spherical harmonics																				\n\
	add					r4,			c11,		r4					; Constant term									\n\
	mad					r4,			c12,		v1.x,		r4		; 1st-order terms								\n\
	mad					r4,			c13,		v1.y,		r4														\n\
	mad					r4,			c14,		v1.z,		r4														\n\
	mul					r5.x,		v1.x,		v1.z				; X * Z											\n\
	mul					r5.y,		v1.z,		v1.y				; Z * Y											\n\
	mul					r5.z,		v1.y,		v1.x				; Y * X											\n\
	mad					r4,			c15,		r5.x,		r4		; 2nd-order terms								\n\
	mad					r4,			c16,		r5.y,		r4														\n\
	mad					r4,			c17,		r5.z,		r4														\n\
	mul					r5.xyz,		v1,			v1																	\n\
	mul					r5.z,		r5.z,		c20.x																\n\
	sub					r5.z,		r5.z,		c20.y																\n\
	mad					r4,			c18,		r5.z,		r4														\n\
	sub					r5.x,		r5.x,		r5.y																\n\
	mad					r4,			c19,		r5.x,		r4														\n\
																													\n\
	; Diffuse color																									\n\
	mov					r4.w,		c20.y							; Set diffuse alpha to one						\n\
	mul					r4,			r4,			c26					; Multiply diffuse by global diffuse			\n\
	add					r4.xyz,		r4.xyz,		c23.x				; Add self-illumination term					\n\
	mov					oD0,		r4								; Output diffuse								\n"
	"																												\n\
	; Specular color																								\n\
	m3x3				r3.xyz,		v1,			c0					; Transform normal to world space				\n\
	m3x3				r2.xyz,		r3,			c3					; Transform normal to view space				\n\
	dp3					r2.w,		r2,			r2					; r2.w contains ||N||^2							\n\
	rsq					r4.w,		r2.w							; r4.w contains 1 / ||N||						\n\
	mul					r2.xyz,		r2.xyz,		r4.w				; Store normalized N in r2						\n\
																													\n\
	sub					r3,			c20.w,		r1					; Calculate V									\n\
	dp3					r3.w,		r3,			r3					; r3.w contains ||V||^2							\n\
	rsq					r4.w,		r3.w							; r4.w contains 1 / ||V||						\n\
	mul					r5.xyz,		r3.xyz,		r4.w				; Store normalized V in r5						\n\
																													\n\
	sub					r3.xyz,		c21.xyz,	v0.xyz				; Calculate L									\n\
	m3x3				r1.xyz,		r3,			c0					; Transform L to world space					\n\
	m3x3				r3.xyz,		r1,			c3					; Transform L to view space						\n\
	dp3					r3.w,		r3,			r3					; r3.w contains ||L||^2							\n\
	rsq					r4.w,		r3.w							; r4.w contains 1 / ||L||						\n\
	mul					r6.xyz,		r3.xyz,		r4.w				; Store normalized L in r6						\n\
																													\n\
	add					r3.xyz,		r5.xyz,		r6.xyz				; H = V + L										\n\
	dp3					r3.w,		r3,			r3					; r3.w contains ||H||^2							\n\
	rsq					r4.w,		r3.w							; r4.w contains 1 / ||H||						\n\
	mul					r5.xyz,		r3.xyz,		r4.w				; Store normalized H in r4						\n\
																													\n\
	dp3					r6,			r6.xyz,		r2.xyz				; Calculate N.L									\n\
	sge					r6,			r6.x,		c20.w				; r6 is 1 if N.L is positive					\n\
																													\n\
	dp3					r5,			r5,			r2					; Calculate H.N									\n\
	max					r5,			r5,			c20.w				; Clamp to [0, 1]								\n\
	min					r5,			r5,			c20.y																\n\
																													\n\
	mul					r5,			r5,			r5					; Exponentiate to n^64 							\n\
	mul					r5,			r5,			r5																	\n\
	mul					r5,			r5,			r5																	\n\
	mul					r5,			r5,			r5																	\n\
	mul					r5,			r5,			r6					; Multiply by light direction					\n\
	mul					r5,			r5,			c20.x				; Triple the output								\n\
	mov					r5.w,		c20.y							; Set specular alpha to 1.0						\n\
																													\n\
	mul					oD1,		r5,			c22					; Output specular								\n\
																													\n\
	; Texture coordinates																							\n\
	mov					oT0,		v5								; Copy diffuse texture coordinates to output	\n\
	mov					oT1,		v5								; Copy gloss texture coordinates to output		\n\
	";

	char *psSource = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample diffuse texture						\n\
	tex					t1											; Sample gloss texture							\n\
																													\n\
	; Arithmetic ops																								\n\
	mul					r0,			t0,			v0					; Modulate diffuse texture with diffuse color	\n\
	mad					r0.xyz,		t1,			v1,			r0		; Modulate gloss texture with specular and add	\n\
	";

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

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

CRuShader_Static_SH9_Gloss::~CRuShader_Static_SH9_Gloss()
{
}

void CRuShader_Static_SH9_Gloss::BeginPass(INT32 passNumber)
{
	// Call base BeginPass to perform any additional setup
	CRuShader_Static_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_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_WRAP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);

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

		m_engine->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
		m_engine->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
	}
}

void CRuShader_Static_SH9_Gloss::EndPass(INT32 passNumber)
{
}

void CRuShader_Static_SH9_Gloss::SetParameters(const CRuParameterCache *paramCache)
{
	CRuShader_Static_Base::SetParameters(paramCache);
}

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

CRuShader_Static_Prelit::CRuShader_Static_Prelit(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);

	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position 0							\n\
	dcl_texcoord0		v5											; Declare input texcoord 0						\n\
	dcl_color			v12											; Declare diffuse								\n\
																													\n\
	; Transform position into homogeneous space																		\n\
	mov					r0,			c20.yyyy						; Move 1 into r0								\n\
	mov					r1,			c20.yyyy						; Move 1 into r1								\n\
	m4x3				r0.xyz,		v0,			c0					; Transform vertex to world space				\n\
	m4x3				r1.xyz,		r0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	; Fog factor																									\n\
	sub					r2.x,		c25.z,		c25.y				; Fog End - Fog Start into r2.x					\n\
	rcp					r2.x,		r2.x							; Reciprocal of fog range into r0.x				\n\
	sub					r3.x,		r1.z,		c25.y				; Offset vertex z by fog start into r3.x		\n\
	mul					r2.x,		r3.x,		r2.x				; Divide z by fog range into r0					\n\
	sub					r2.x,		c20.y,		r2.x				; Invert fog factor								\n\
	max					r2.x,		r2.x,		c20.w				; Clamp to [0, 1]								\n\
	min					r2.x,		r2.x,		c20.y																\n\
	mov					oFog,		r2.x							; Output fog factor								\n"
	"																												\n\
	; Diffuse color																									\n\
	mul					r4,			v12,		c26					; Multiply diffuse by global diffuse			\n\
	mov					oD0,		r4								; Set diffuse									\n\
																													\n\
	mov					oT0,		v5								; Copy texture coordinates to output			\n\
	";

	char *psSource = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample diffuse texture						\n\
																													\n\
	; Arithmetic ops																								\n\
	mul					r0,			t0,			v0					; Modulate texture with diffuse					\n\
	";

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

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

CRuShader_Static_Prelit::~CRuShader_Static_Prelit()
{
}

void CRuShader_Static_Prelit::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_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_WRAP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
	}
}

void CRuShader_Static_Prelit::EndPass(INT32 passNumber)
{
}

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

void CRuShader_Static_Prelit::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 float *texCoords = morphTarget->GetTextureCoordinate(ruTEXCHANNEL_DIFFUSEMAP);

		if(morphTarget)
		{
			const CRuVector3 *position = morphTarget->GetPosition();
			const DWORD *diffuse = morphTarget->GetDiffuse();

			if(diffuse && texCoords)
			{
				for(INT32 i = 0, j = 0, numVertices = mesh->GetNumVertices(); i < numVertices; 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 = texCoords[j++];
					vertices[i].v = texCoords[j++];
				}
			}
			else if(diffuse)
			{
				for(INT32 i = 0, j = 0, numVertices = mesh->GetNumVertices(); i < numVertices; 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 = 0.0f;
					vertices[i].v = 0.0f;
				}
			}
			else if(texCoords)
			{
				for(INT32 i = 0, j = 0, numVertices = mesh->GetNumVertices(); i < numVertices; i++)
				{
					vertices[i].x = position[i].x;
					vertices[i].y = position[i].y;
					vertices[i].z = position[i].z;

					vertices[i].diffuse = 0xFFFFFFFF;

					vertices[i].u = texCoords[j++];
					vertices[i].v = texCoords[j++];
				}
			}
			else
			{
				for(INT32 i = 0, j = 0, numVertices = mesh->GetNumVertices(); i < numVertices; i++)
				{
					vertices[i].x = position[i].x;
					vertices[i].y = position[i].y;
					vertices[i].z = position[i].z;

					vertices[i].diffuse = 0xFFFFFFFF;

					vertices[i].u = 0.0f;
					vertices[i].v = 0.0f;
				}
			}
		}
	}
}

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

CRuShader_Static_SH9_Translucent::CRuShader_Static_SH9_Translucent(CRuEngineD3D *engine)
:	CRuShader_Static_Base(engine)
{
	m_override_AlphaBlend = TRUE;

	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_normal			v1											; Declare normal								\n\
	dcl_texcoord0		v5											; Declare input texcoord 0						\n\
																													\n\
	; Transform position into homogeneous space																		\n\
	mov					r0,			c20.yyyy						; Move 1 into r0								\n\
	mov					r1,			c20.yyyy						; Move 1 into r1								\n\
	m4x3				r0.xyz,		v0,			c0					; Transform vertex to world space				\n\
	m4x3				r1.xyz,		r0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	; Fog factor																									\n\
	sub					r2.x,		c25.z,		c25.y				; Fog End - Fog Start into r2.x					\n\
	rcp					r2.x,		r2.x							; Reciprocal of fog range into r0.x				\n\
	sub					r3.x,		r1.z,		c25.y				; Offset vertex z by fog start into r3.x		\n\
	mul					r2.x,		r3.x,		r2.x				; Divide z by fog range into r0					\n\
	sub					r2.x,		c20.y,		r2.x				; Invert fog factor								\n\
	max					r2.x,		r2.x,		c20.w				; Clamp to [0, 1]								\n\
	min					r2.x,		r2.x,		c20.y																\n\
	mov					oFog,		r2.x							; Output fog factor								\n"
	"																												\n\
	; Ambient lighting into r4																						\n\
	mov					r4,			c10																				\n\
																													\n\
	; Object-level spherical harmonics																				\n\
	add					r4,			c11,		r4					; Constant term									\n\
	mad					r4,			c12,		v1.x,		r4		; 1st-order terms								\n\
	mad					r4,			c13,		v1.y,		r4														\n\
	mad					r4,			c14,		v1.z,		r4														\n\
	mul					r5.x,		v1.x,		v1.z				; X * Z											\n\
	mul					r5.y,		v1.z,		v1.y				; Z * Y											\n\
	mul					r5.z,		v1.y,		v1.x				; Y * X											\n\
	mad					r4,			c15,		r5.x,		r4		; 2nd-order terms								\n\
	mad					r4,			c16,		r5.y,		r4														\n\
	mad					r4,			c17,		r5.z,		r4														\n\
	mul					r5.xyz,		v1,			v1																	\n\
	mul					r5.z,		r5.z,		c20.x																\n\
	sub					r5.z,		r5.z,		c20.y																\n\
	mad					r4,			c18,		r5.z,		r4														\n\
	sub					r5.x,		r5.x,		r5.y																\n\
	mad					r4,			c19,		r5.x,		r4														\n\
																													\n\
	; Diffuse color																									\n\
	mul					r4,			r4,			c26					; Multiply diffuse by global diffuse			\n\
	add					r4.xyz,		r4.xyz,		c23.x				; Add self-illumination term					\n\
	mov					oD0,		r4								; Output diffuse								\n"
	"																												\n\
	; Texture coordinates																							\n\
	mov					oT0,		v5								; Copy diffuse texture coordinates to output	\n\
	";

	char *psSource = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample diffuse texture						\n\
																													\n\
	; Arithmetic ops																								\n\
	mul					r0,			t0,			v0					; Modulate diffuse texture with diffuse color	\n\
	";

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

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

CRuShader_Static_SH9_Translucent::~CRuShader_Static_SH9_Translucent()
{
}

void CRuShader_Static_SH9_Translucent::BeginPass(INT32 passNumber)
{
	// Call base BeginPass to perform any additional setup
	CRuShader_Static_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 + 2);
		m_engine->GetD3DDevice()->SetPixelShaderConstantF(0, m_pixelShaderConstants, m_numBasePixelShaderConstants);

		switch(m_material_AlphaMode)
		{
			case ruALPHAMODE_NORMAL:
				{
					m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
					m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
					m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
				}

				break;

			case ruALPHAMODE_ADD:
				{
					m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
					m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
					m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
				}

				break;

			case ruALPHAMODE_SUBTRACT:
				{
					m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
					m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
				}

				break;
		}

		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_WRAP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
	}
}

void CRuShader_Static_SH9_Translucent::EndPass(INT32 passNumber)
{
}

void CRuShader_Static_SH9_Translucent::SetParameters(const CRuParameterCache *paramCache)
{
	CRuShader_Static_Base::SetParameters(paramCache);
}

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

CRuShader_Static_Prelit_Translucent::CRuShader_Static_Prelit_Translucent(CRuEngineD3D *engine)
:	CRuShader_Base(engine)
{
	m_override_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);

	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position 0							\n\
	dcl_texcoord0		v5											; Declare input texcoord 0						\n\
	dcl_color			v12											; Declare diffuse								\n\
																													\n\
	; Transform position into homogeneous space																		\n\
	mov					r0,			c20.yyyy						; Move 1 into r0								\n\
	mov					r1,			c20.yyyy						; Move 1 into r1								\n\
	m4x3				r0.xyz,		v0,			c0					; Transform vertex to world space				\n\
	m4x3				r1.xyz,		r0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	; Fog factor																									\n\
	sub					r2.x,		c25.z,		c25.y				; Fog End - Fog Start into r2.x					\n\
	rcp					r2.x,		r2.x							; Reciprocal of fog range into r0.x				\n\
	sub					r3.x,		r1.z,		c25.y				; Offset vertex z by fog start into r3.x		\n\
	mul					r2.x,		r3.x,		r2.x				; Divide z by fog range into r0					\n\
	sub					r2.x,		c20.y,		r2.x				; Invert fog factor								\n\
	max					r2.x,		r2.x,		c20.w				; Clamp to [0, 1]								\n\
	min					r2.x,		r2.x,		c20.y																\n\
	mov					oFog,		r2.x							; Output fog factor								\n"
	"																												\n\
	; Diffuse color																									\n\
	mul					r4,			v12,		c26					; Multiply diffuse by global diffuse			\n\
	mov					oD0,		r4								; Set diffuse									\n\
																													\n\
	mov					oT0,		v5								; Copy texture coordinates to output			\n\
	";

	char *psSource = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample diffuse texture						\n\
																													\n\
	; Arithmetic ops																								\n\
	mul					r0,			t0,			v0					; Modulate texture with diffuse					\n\
	";

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

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

CRuShader_Static_Prelit_Translucent::~CRuShader_Static_Prelit_Translucent()
{
}

void CRuShader_Static_Prelit_Translucent::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);

		switch(m_material_AlphaMode)
		{
			case ruALPHAMODE_NORMAL:
				{
					m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
					m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
					m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
				}

				break;

			case ruALPHAMODE_ADD:
				{
					m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
					m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
					m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
				}

				break;

			case ruALPHAMODE_SUBTRACT:
				{
					m_engine->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
					m_engine->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
				}

				break;
		}

		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_WRAP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
	}
}

void CRuShader_Static_Prelit_Translucent::EndPass(INT32 passNumber)
{
}

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

void CRuShader_Static_Prelit_Translucent::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 float *texCoords = morphTarget->GetTextureCoordinate(ruTEXCHANNEL_DIFFUSEMAP);

		if(morphTarget)
		{
			const CRuVector3 *position = morphTarget->GetPosition();
			const DWORD *diffuse = morphTarget->GetDiffuse();

			if(diffuse && texCoords)
			{
				for(INT32 i = 0, j = 0, numVertices = mesh->GetNumVertices(); i < numVertices; 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 = texCoords[j++];
					vertices[i].v = texCoords[j++];
				}
			}
			else if(diffuse)
			{
				for(INT32 i = 0, j = 0, numVertices = mesh->GetNumVertices(); i < numVertices; 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 = 0.0f;
					vertices[i].v = 0.0f;
				}
			}
			else if(texCoords)
			{
				for(INT32 i = 0, j = 0, numVertices = mesh->GetNumVertices(); i < numVertices; i++)
				{
					vertices[i].x = position[i].x;
					vertices[i].y = position[i].y;
					vertices[i].z = position[i].z;

					vertices[i].diffuse = 0xFFFFFFFF;

					vertices[i].u = texCoords[j++];
					vertices[i].v = texCoords[j++];
				}
			}
			else
			{
				for(INT32 i = 0, j = 0, numVertices = mesh->GetNumVertices(); i < numVertices; i++)
				{
					vertices[i].x = position[i].x;
					vertices[i].y = position[i].y;
					vertices[i].z = position[i].z;

					vertices[i].diffuse = 0xFFFFFFFF;

					vertices[i].u = 0.0f;
					vertices[i].v = 0.0f;
				}
			}
		}
	}
}

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

CRuShader_Static_FX::CRuShader_Static_FX(CRuEngineD3D *engine)
:	CRuShader_Static_Prelit(engine)
{
	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position 0							\n\
	dcl_texcoord0		v5											; Declare input texcoord 0						\n\
	dcl_color			v12											; Declare diffuse								\n\
																													\n\
	; Transform position into homogeneous space																		\n\
	mov					r0,			c20.yyyy						; Move 1 into r0								\n\
	mov					r1,			c20.yyyy						; Move 1 into r1								\n\
	m4x3				r0.xyz,		v0,			c0					; Transform vertex to world space				\n\
	m4x3				r1.xyz,		r0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	; Fog factor																									\n\
	mov					oFog,		c20.y							; Output fog factor								\n"
	"																												\n\
	; Diffuse color																									\n\
	mul					r4,			v12,		c26					; Multiply diffuse by global diffuse			\n\
	mov					oD0,		r4								; Set diffuse									\n\
																													\n\
	mov					oT0,		v5								; Copy texture coordinates to output			\n\
	";

	char *psSource = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample diffuse texture						\n\
																													\n\
	; Arithmetic ops																								\n\
	mul					r0,			t0,			v0					; Modulate texture with diffuse					\n\
	";

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

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

	// Overrides
	m_override_ZWrite = TRUE;
}

CRuShader_Static_FX::~CRuShader_Static_FX()
{
}

void CRuShader_Static_FX::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_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_WRAP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
	}
}

void CRuShader_Static_FX::EndPass(INT32 passNumber)
{
}

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

CRuShader_Static_Fader::CRuShader_Static_Fader(CRuEngineD3D *engine)
:	CRuShader_Static_Base(engine)
{
	char *vsSource0 = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_normal			v1											; Declare normal								\n\
	dcl_texcoord0		v5											; Declare input texcoord 0						\n\
																													\n\
	; Transform position into homogeneous space																		\n\
	mov					r0,			c20.yyyy						; Move 1 into r0								\n\
	mov					r1,			c20.yyyy						; Move 1 into r1								\n\
	m4x3				r0.xyz,		v0,			c0					; Transform vertex to world space				\n\
	m4x3				r1.xyz,		r0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	; Fog factor																									\n\
	mov					oFog,		c20.y							; Output fog factor	as constant 1.0				\n"
	"																												\n\
	; Diffuse color																									\n\
	mov					oD0,		c20.y							; Set diffuse									\n\
																													\n\
	mov					oT0,		v5								; Copy texture coordinates to output			\n\
	";

	char *vsSource1 = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_normal			v1											; Declare normal								\n\
	dcl_texcoord0		v5											; Declare input texcoord 0						\n\
																													\n\
	; Transform position into homogeneous space																		\n\
	mov					r0,			c20.yyyy						; Move 1 into r0								\n\
	mov					r1,			c20.yyyy						; Move 1 into r1								\n\
	m4x3				r0.xyz,		v0,			c0					; Transform vertex to world space				\n\
	m4x3				r1.xyz,		r0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	; Fog factor																									\n\
	sub					r2.x,		c25.z,		c25.y				; Fog End - Fog Start into r2.x					\n\
	rcp					r2.x,		r2.x							; Reciprocal of fog range into r0.x				\n\
	sub					r3.x,		r1.z,		c25.y				; Offset vertex z by fog start into r3.x		\n\
	mul					r2.x,		r3.x,		r2.x				; Divide z by fog range into r0					\n\
	sub					r2.x,		c20.y,		r2.x				; Invert fog factor								\n\
	max					r2.x,		r2.x,		c20.w				; Clamp to [0, 1]								\n\
	min					r2.x,		r2.x,		c20.y																\n\
	mov					oFog,		r2.x							; Output fog factor								\n"
	"																												\n\
	; Ambient lighting into r4																						\n\
	mov					r4,			c10																				\n\
																													\n\
	; Object-level spherical harmonics																				\n\
	add					r4,			c11,		r4					; Constant term									\n\
	mad					r4,			c12,		v1.x,		r4		; 1st-order terms								\n\
	mad					r4,			c13,		v1.y,		r4														\n\
	mad					r4,			c14,		v1.z,		r4														\n\
	mul					r5.x,		v1.x,		v1.z				; X * Z											\n\
	mul					r5.y,		v1.z,		v1.y				; Z * Y											\n\
	mul					r5.z,		v1.y,		v1.x				; Y * X											\n\
	mad					r4,			c15,		r5.x,		r4		; 2nd-order terms								\n\
	mad					r4,			c16,		r5.y,		r4														\n\
	mad					r4,			c17,		r5.z,		r4														\n\
	mul					r5.xyz,		v1,			v1																	\n\
	mul					r5.z,		r5.z,		c20.x																\n\
	sub					r5.z,		r5.z,		c20.y																\n\
	mad					r4,			c18,		r5.z,		r4														\n\
	sub					r5.x,		r5.x,		r5.y																\n\
	mad					r4,			c19,		r5.x,		r4														\n\
																													\n\
	; Diffuse color																									\n\
	mul					r4,			r4,			c26					; Multiply diffuse by global diffuse			\n\
	add					r4.xyz,		r4.xyz,		c23.x				; Add self-illumination term					\n\
	mov					oD0,		r4								; Set diffuse									\n\
																													\n\
	mov					oT0,		v5								; Copy texture coordinates to output			\n\
	";

	char *psSource = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample diffuse texture						\n\
																													\n\
	; Arithmetic ops																								\n\
	mul					r0,			t0,			v0					; Modulate texture with diffuse					\n\
	";

	// Assemble vertex shader
	m_vertexShaders[0] = RuD3DAssembleVertexShader(vsSource0);
	m_vertexShaders[1] = RuD3DAssembleVertexShader(vsSource1);

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

	// Overrides
	m_override_ZWrite = TRUE;
}

CRuShader_Static_Fader::~CRuShader_Static_Fader()
{
	for(INT32 i = 0; i < 2; ++i)
	{
		ruSAFE_RELEASE(m_vertexShaders[i]);
	}
}

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

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShaders[passNumber]);
		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_ALPHATESTENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_ALPHAREF, 0x70);
		m_engine->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
*/
		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);

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

		m_engine->SetRenderState(D3DRS_COLORWRITEENABLE, 0);

		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_WRAP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
	}
	else
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShaders[passNumber]);
		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_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_EQUAL);

		m_engine->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE);

		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_WRAP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
	}
}

void CRuShader_Static_Fader::EndPass(INT32 passNumber)
{
}

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

CRuShader_Skin_Flat::CRuShader_Skin_Flat(CRuEngineD3D *engine)
:	CRuShader_Skin_Base(engine)
{
	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_normal			v1											; Declare normal  								\n\
	dcl_blendweight		v2											; Declare blend indices							\n\
	dcl_blendindices	v3											; Declare blend indices							\n\
	dcl_texcoord0		v5											; Declare input texcoord 0						\n\
																													\n\
	; First bone matrix constant = index * 3 + start index															\n\
	mad			r7,			v3.xyzw,	c27.y,		c27.x															\n\
																													\n\
	; Figure out the last weight																					\n\
	dp3			r5,			v2,			c20.yyyy																	\n\
	sub			r5.w,		c20.yyyy,	r5																			\n\
																													\n\
	; Feed 1.0 into r0.w																							\n\
	mov			r0.w,		c20.y																					\n"
	"																												\n\
	; Skin by matrix 0																								\n\
	mov			a0.x,		r7.x									; Setup matrix index							\n\
	m4x3		r0,			v0,			c[a0.x]						; Skin position									\n\
	mul			r1,			r0,			v2.xxxx																		\n\
																													\n\
	; Skin by matrix 1																								\n\
	mov			a0.x,		r7.y									; Setup matrix index							\n\
	m4x3		r0,			v0,			c[a0.x]						; Skin position									\n\
	mad			r1,			r0,			v2.yyyy,	r1				; Sum position									\n\
																													\n\
	; Skin by matrix 2																								\n\
	mov			a0.x,		r7.z									; Setup matrix index							\n\
	m4x3		r0,			v0,			c[a0.x]						; Skin position									\n\
	mad			r1,			r0,			v2.zzzz,	r1				; Sum position									\n\
																													\n\
	; Skin by matrix 3																								\n\
	mov			a0.x,		r7.w									; Setup matrix index							\n\
	m4x3		r0,			v0,			c[a0.x]						; Skin position									\n\
	mad			r1,			r0,			r5.wwww,	r1				; Sum position									\n\
																													\n\
	; Feed 1.0 into r1.w and r2.w																					\n\
	mov			r1.w,		c20.y																					\n\
	mov			r2.w,		c20.y																					\n\
																													\n\
	m4x3		r2,			r1,			c0							; Transform vertex to world space				\n\
	m4x3		r1,			r2,			c3							; Transform vertex to view space				\n\
	m4x4		oPos,		r1,			c6							; Transform vertex to homogeneous space			\n\
																													\n\
	; Fog factor																									\n\
	sub			r2.x,		c25.z,		c25.y						; Fog End - Fog Start into r2.x					\n\
	rcp			r2.x,		r2.x									; Reciprocal of fog range into r0.x				\n\
	sub			r3.x,		r1.z,		c25.y						; Offset vertex z by fog start into r3.x		\n\
	mul			r2.x,		r3.x,		r2.x						; Divide z by fog range into r0					\n\
	sub			r2.x,		c20.y,		r2.x						; Invert fog factor								\n\
	max			r2.x,		r2.x,		c20.w						; Clamp to [0, 1]								\n\
	min			r2.x,		r2.x,		c20.y																		\n\
	mov			oFog,		r2.x									; Output fog factor								\n"
	"																												\n\
	mov			oT0,		v5										; Copy texture coordinates to output			\n\
	mov			oD0,		c20.yyyy								; Set diffuse									\n\
	mov			oD0.w,		c25.x									; Set diffuse alpha to global alpha				\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();
}

CRuShader_Skin_Flat::~CRuShader_Skin_Flat()
{
}

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

	if(passNumber == 0)
	{
		// Setup vertex shader
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(NULL);
		m_engine->GetD3DDevice()->SetVertexShaderConstantF(0, m_shaderConstants, m_numBaseConstants + m_numSubFrames * 3);

		m_engine->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);

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

		m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);

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

		m_engine->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
		m_engine->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		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->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_WRAP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
	}
}

void CRuShader_Skin_Flat::EndPass(INT32 passNumber)
{
}

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

CRuShader_Skin_SH9::CRuShader_Skin_SH9(CRuEngineD3D *engine)
:	CRuShader_Skin_Base(engine)
{
	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_normal			v1											; Declare normal  								\n\
	dcl_blendweight		v2											; Declare blend indices							\n\
	dcl_blendindices	v3											; Declare blend indices							\n\
	dcl_texcoord0		v5											; Declare input texcoord 0						\n\
																													\n\
	; First bone matrix constant = index * 3 + start index															\n\
	mad			r7,			v3.xyzw,	c27.y,		c27.x															\n\
																													\n\
	; Figure out the last weight																					\n\
	dp3			r5,			v2,			c20.yyyy																	\n\
	sub			r5.w,		c20.yyyy,	r5																			\n\
																													\n\
	; Feed 1.0 into r0.w																							\n\
	mov			r0.w,		c20.y																					\n"
	"																												\n\
	; Skin by matrix 0																								\n\
	mov			a0.x,		r7.x									; Setup matrix index							\n\
	m4x3		r0,			v0,			c[a0.x]						; Skin position									\n\
	mul			r1,			r0,			v2.xxxx																		\n\
																													\n\
	; Skin by matrix 1																								\n\
	mov			a0.x,		r7.y									; Setup matrix index							\n\
	m4x3		r0,			v0,			c[a0.x]						; Skin position									\n\
	mad			r1,			r0,			v2.yyyy,	r1				; Sum position									\n\
																													\n\
	; Skin by matrix 2																								\n\
	mov			a0.x,		r7.z									; Setup matrix index							\n\
	m4x3		r0,			v0,			c[a0.x]						; Skin position									\n\
	mad			r1,			r0,			v2.zzzz,	r1				; Sum position									\n\
																													\n\
	; Skin by matrix 3																								\n\
	mov			a0.x,		r7.w									; Setup matrix index							\n\
	m4x3		r0,			v0,			c[a0.x]						; Skin position									\n\
	mad			r1,			r0,			r5.wwww,	r1				; Sum position									\n\
																													\n\
	; Feed 1.0 into r1.w and r2.w																					\n\
	mov			r1.w,		c20.y																					\n\
	mov			r2.w,		c20.y																					\n\
																													\n\
	m4x3		r2,			r1,			c0							; Transform vertex to world space				\n\
	m4x3		r1,			r2,			c3							; Transform vertex to view space				\n\
	m4x4		oPos,		r1,			c6							; Transform vertex to homogeneous space			\n\
																													\n\
	; Fog factor																									\n\
	sub			r2.x,		c25.z,		c25.y						; Fog End - Fog Start into r2.x					\n\
	rcp			r2.x,		r2.x									; Reciprocal of fog range into r0.x				\n\
	sub			r3.x,		r1.z,		c25.y						; Offset vertex z by fog start into r3.x		\n\
	mul			r2.x,		r3.x,		r2.x						; Divide z by fog range into r0					\n\
	sub			r2.x,		c20.y,		r2.x						; Invert fog factor								\n\
	max			r2.x,		r2.x,		c20.w						; Clamp to [0, 1]								\n\
	min			r2.x,		r2.x,		c20.y																		\n\
	mov			oFog,		r2.x									; Output fog factor								\n"
	"																												\n\
	; Ambient lighting into r4																						\n\
	mov			r4,			c10																						\n\
																													\n\
	; Object-level spherical harmonics																				\n\
	add			r4,			c11,		r4							; Constant term									\n\
	mad			r4,			c12,		v1.x,		r4				; 1st-order terms								\n\
	mad			r4,			c13,		v1.y,		r4																\n\
	mad			r4,			c14,		v1.z,		r4																\n\
	mul			r5.x,		v1.x,		v1.z						; X * Z											\n\
	mul			r5.y,		v1.z,		v1.y						; Z * Y											\n\
	mul			r5.z,		v1.y,		v1.x						; Y * X											\n\
	mad			r4,			c15,		r5.x,		r4				; 2nd-order terms								\n\
	mad			r4,			c16,		r5.y,		r4																\n\
	mad			r4,			c17,		r5.z,		r4																\n\
	mul			r5.xyz,		v1,			v1																			\n\
	mul			r5.z,		r5.z,		c20.x																		\n\
	sub			r5.z,		r5.z,		c20.y																		\n\
	mad			r4,			c18,		r5.z,		r4																\n\
	sub			r5.x,		r5.x,		r5.y																		\n\
	mad			r4,			c19,		r5.x,		r4																\n\
																													\n\
	; Diffuse color																									\n\
	mov			r4.w,		c25.x									; Set light alpha to global alpha				\n\
	mov			oD0,		r4										; Set diffuse									\n\
																													\n\
	; Texture coordinates																							\n\
	mov			oT0,		v5										; Copy texture coordinates to output			\n\
	";

	char *psSource = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample diffuse texture						\n\
																													\n\
	; Arithmetic ops																								\n\
	mul					r0,			t0,			v0					; Modulate texture with diffuse					\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();
}

CRuShader_Skin_SH9::~CRuShader_Skin_SH9()
{
}

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

	if(passNumber == 0)
	{
		// Setup vertex shader
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(m_pixelShader);
		m_engine->GetD3DDevice()->SetVertexShaderConstantF(0, m_shaderConstants, m_numBaseConstants + m_numSubFrames * 3);

		m_engine->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);

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

		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_WRAP);
		m_engine->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
	}
}

void CRuShader_Skin_SH9::EndPass(INT32 passNumber)
{
}

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

#pragma managed
