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

#pragma unmanaged

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

CRuShader_Terrain_Base::CRuShader_Terrain_Base(CRuEngineD3D *engine)
:	CRuShader_Base(engine)
{
	// Setup vertex elements
	CRuVertexElement vertexElements[] =
	{
		{ 0,	0,	ruELEMENTTYPE_FLOAT3,		ruELEMENTMETHOD_DEFAULT,	ruELEMENTUSAGE_POSITION,	0 },
		{ 0,	12,	ruELEMENTTYPE_FLOAT3,		ruELEMENTMETHOD_DEFAULT,	ruELEMENTUSAGE_NORMAL,		0 },
		{ 0,	24,	ruELEMENTTYPE_D3DCOLOR,		ruELEMENTMETHOD_DEFAULT,	ruELEMENTUSAGE_COLOR,		0 },
		{ 0,	28,	ruELEMENTTYPE_FLOAT2,		ruELEMENTMETHOD_DEFAULT,	ruELEMENTUSAGE_TEXCOORD,	0 },
		RUVERTEXDECL_END()
	};

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

CRuShader_Terrain_Base::~CRuShader_Terrain_Base()
{
}

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

		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(morphTarget->GetNormal())
				{
					vertices[i].nx = morphTarget->GetNormal()[i].x;
					vertices[i].ny = morphTarget->GetNormal()[i].y;
					vertices[i].nz = morphTarget->GetNormal()[i].z;
				}

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

				if(texCoords)
				{
					vertices[i].u = texCoords[j++];
					vertices[i].v = texCoords[j++];
				}
			}
		}
	}
}

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

CRuShader_Terrain::CRuShader_Terrain(CRuEngineD3D *engine)
:	CRuShader_Terrain_Base(engine),
	m_maxLayersPerPass(6),
	m_maxTextureLayers(12),
	m_numTextureLayers(0)
{
	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_color			v2											; Declare diffuse								\n\
	dcl_texcoord0		v5											; Declare input texcoord 0						\n\
																													\n\
	mov					r1,			c20.yyyy																		\n\
	mov					r2,			c20.yyyy																		\n\
	m4x3				r1.xyz,		v0,			c3					; Transform vertex to view space				\n\
	m3x3				r2.xyz,		v1,			c3					; Transform normal to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\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					oD0.w,		r2.x							; Output fog factor to diffuse alpha			\n\
	mov					oFog,		c20.y							; Output fog factor (disable it)				\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					oD0.xyz,	r4,			v2					; Set diffuse									\n\
																													\n\
	; Specular color																								\n\
	m3x3				r2.xyz,		v1,			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,			c3					; Transform L to view space						\n\
	dp3					r3.w,		r1,			r1					; r3.w contains ||L||^2							\n\
	rsq					r4.w,		r3.w							; r4.w contains 1 / ||L||						\n\
	mul					r6.xyz,		r1.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,			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 alpha 0 uv to T0							\n\
	mul					oT1,		v5,			c28					; Copy splat 0 uv to T1							\n\
	mul					oT2,		v5,			c28					; Copy splat 1 uv to T2							\n\
	mul					oT3,		v5,			c28					; Copy splat 2 uv to T3							\n\
																													\n\
	mov					oT4,		v5								; Copy alpha 0 uv to T0							\n\
	mul					oT5,		v5,			c28					; Copy splat 3 uv to T5							\n\
	mul					oT6,		v5,			c28					; Copy splat 4 uv to T6							\n\
	mul					oT7,		v5,			c28					; Copy splat 5 uv to T7							\n\
	";

	char *psSource0_1_1 = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Fog																											\n\
	mov					r0,			c1								; Move fog color to output						\n\
	mov					r0.w,		v0.w							; Move fog factor to output alpha				\n\
	";

	char *psSource1_1_1 = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	def					c1,			1.0, 0.0, 0.0, 0.0																\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample alpha 0								\n\
	tex					t1											; Sample splat 0								\n\
																													\n\
	; Arithmetic ops																								\n\
	dp3					r1,			t0,			c1					; Get RED into r1								\n\
	mul_sat				r0,			t1,			r1					; Modulate layer 0								\n\
																													\n\
	; Fog and diffuse color																							\n\
	mul					r0.xyz,		r0,			v0					; Modulate base texture with diffuse into r0	\n\
	";

	char *psSource2_1_1 = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	def					c1,			1.0, 0.0, 0.0, 0.0																\n\
	def					c2,			0.0, 1.0, 0.0, 0.0																\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample alpha 0								\n\
	tex					t1											; Sample splat 0								\n\
	tex					t2											; Sample splat 1								\n\
																													\n\
	; Arithmetic ops																								\n\
	dp3					r1,			t0,			c1					; Get RED into r1								\n\
	mul_sat				r0,			t1,			r1					; Modulate layer 0								\n\
																													\n\
	dp3					r1,			t0,			c2					; Get BLUE into r1								\n\
	mad_sat				r0,			t2,			r1,			r0		; Modulate layer 1								\n\
																													\n\
	; Fog and diffuse color																							\n\
	mul					r0.xyz,		r0,			v0					; Modulate base texture with diffuse into r0	\n\
	";

	char *psSource3_1_1 = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	def					c1,			1.0, 0.0, 0.0, 0.0																\n\
	def					c2,			0.0, 1.0, 0.0, 0.0																\n\
	def					c3,			0.0, 0.0, 1.0, 0.0																\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample alpha 0								\n\
	tex					t1											; Sample splat 0								\n\
	tex					t2											; Sample splat 1								\n\
	tex					t3											; Sample splat 2								\n\
																													\n\
	; Arithmetic ops																								\n\
	dp3					r1,			t0,			c1					; Get RED into r1								\n\
	mul_sat				r0,			t1,			r1					; Modulate layer 0								\n\
																													\n\
	dp3					r1,			t0,			c2					; Get BLUE into r1								\n\
	mad_sat				r0,			t2,			r1,			r0		; Modulate layer 1								\n\
																													\n\
	dp3					r1,			t0,			c3					; Get GREEN into r1								\n\
	mad_sat				r0,			t3,			r1,			r0		; Modulate layer 2								\n\
																													\n\
	mul					r0.xyz,		r0,			v0					; Modulate base texture with diffuse into r0	\n\
	";

	char *psSourceFog_1_1 = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Fog																											\n\
	mov					r0,			c1								; Move fog color to output						\n\
	mov					r0.w,		v0.w							; Move fog factor to output alpha				\n\
	";

	char *psSource1_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n"
	"																												\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
																													\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
																													\n\
	; Accumulate alpha factor into r9																				\n\
	dp3_pp				r9.x,		r0,			c0.x				; Combine alpha factor from ALPHA_0 into r9.x	\n\
																													\n\
	; Calculate base color * diffuse * fog																			\n\
	mul_pp				r7,			c1,			r9.x				; Modulate fog color by alpha factor into r7	\n\
	mul_pp				r8,			r8,			v0					; Modulate base texture with diffuse into r8	\n\
	lrp_pp				r0,			v0.w,		r8,			r7		; Linearly interpolate between fog and diffuse	\n\
																													\n\
	mad_pp				r0.xyz,		v1,			r8.w,		r0		; Modulate specular by alpha channel (*)		\n\
	mov_pp				r0.w,		r9.x							; Copy alpha factor into diffuse channel alpha	\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r0								; Move result into output						\n\
	";

	char *psSource2_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
	dcl_2d				s2											; LAYER_1										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
	dcl					t2.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n"
	"																												\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
	texld_pp			r2,			t2,			s2					; Sample layer 1								\n\
																													\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
	mad_pp				r8,			r2,			r0.y,		r8		; Multiply layer 1 by its factor into R8		\n\
																													\n\
	; Accumulate alpha factor into r9																				\n\
	dp3_pp				r9.x,		r0,			c0.x				; Combine alpha factor from ALPHA_0 into r9.x	\n\
																													\n\
	; Calculate base color * diffuse * fog																			\n\
	mul_pp				r7,			c1,			r9.x				; Modulate fog color by alpha factor into r7	\n\
	mul_pp				r8,			r8,			v0					; Modulate base texture with diffuse into r8	\n\
	lrp_pp				r0,			v0.w,		r8,			r7		; Linearly interpolate between fog and diffuse	\n\
																													\n\
	mad_pp				r0.xyz,		v1,			r8.w,		r0		; Modulate specular by alpha channel (*)		\n\
	mov_pp				r0.w,		r9.x							; Copy alpha factor into diffuse channel alpha	\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r0								; Move result into output						\n\
	";

	char *psSource3_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
	dcl_2d				s2											; LAYER_1										\n\
	dcl_2d				s3											; LAYER_2										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
	dcl					t2.xy																						\n\
	dcl					t3.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n"
	"																												\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
	texld_pp			r2,			t2,			s2					; Sample layer 1								\n\
	texld_pp			r3,			t3,			s3					; Sample layer 2								\n\
																													\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
	mad_pp				r8,			r2,			r0.y,		r8		; Multiply layer 1 by its factor into R8		\n\
	mad_pp				r8,			r3,			r0.z,		r8		; Multiply layer 2 by its factor into R8		\n\
																													\n\
	; Accumulate alpha factor into r9																				\n\
	dp3_pp				r9.x,		r0,			c0.x				; Combine alpha factor from ALPHA_0 into r9.x	\n\
																													\n\
	; Calculate base color * diffuse * fog																			\n\
	mul_pp				r7,			c1,			r9.x				; Modulate fog color by alpha factor into r7	\n\
	mul_pp				r8,			r8,			v0					; Modulate base texture with diffuse into r8	\n\
	lrp_pp				r0,			v0.w,		r8,			r7		; Linearly interpolate between fog and diffuse	\n\
																													\n\
	mad_pp				r0.xyz,		v1,			r8.w,		r0		; Modulate specular by alpha channel (*)		\n\
	mov_pp				r0.w,		r9.x							; Copy alpha factor into diffuse channel alpha	\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r0								; Move result into output						\n\
	";

	char *psSource4_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
	dcl_2d				s2											; LAYER_1										\n\
	dcl_2d				s3											; LAYER_2										\n\
	dcl_2d				s4											; ALPHA_1										\n\
	dcl_2d				s5											; LAYER_3										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
	dcl					t2.xy																						\n\
	dcl					t3.xy																						\n\
	dcl					t4.xy																						\n\
	dcl					t5.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n"
	"																												\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
	texld_pp			r2,			t2,			s2					; Sample layer 1								\n\
	texld_pp			r3,			t3,			s3					; Sample layer 2								\n\
	texld_pp			r4,			t4,			s4					; Sample ALPHA_1 into R2						\n\
	texld_pp			r5,			t5,			s5					; Sample layer 3								\n\
																													\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
	mad_pp				r8,			r2,			r0.y,		r8		; Multiply layer 1 by its factor into R8		\n\
	mad_pp				r8,			r3,			r0.z,		r8		; Multiply layer 2 by its factor into R8		\n\
	mad_pp				r8,			r5,			r4.x,		r8		; Multiply layer 3 by its factor into R8		\n\
																													\n\
	; Accumulate alpha factor into r9																				\n\
	dp3_pp				r9.x,		r0,			c0.x				; Combine alpha factor from ALPHA_0 into r9.x	\n\
	dp3_pp				r9.y,		r4,			c0.x				; Combine alpha factor from ALPHA_1 into r9.y	\n\
	add_pp				r9.x,		r9.x,		r9.y				; Combine alpha factor from both textures		\n\
																													\n\
	; Calculate base color * diffuse * fog																			\n\
	mul_pp				r7,			c1,			r9.x				; Modulate fog color by alpha factor into r7	\n\
	mul_pp				r8,			r8,			v0					; Modulate base texture with diffuse into r8	\n\
	lrp_pp				r0,			v0.w,		r8,			r7		; Linearly interpolate between fog and diffuse	\n\
																													\n\
	mad_pp				r0.xyz,		v1,			r8.w,		r0		; Modulate specular by alpha channel (*)		\n\
	mov_pp				r0.w,		r9.x							; Copy alpha factor into diffuse channel alpha	\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r0								; Move result into output						\n\
	";

	char *psSource5_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
	dcl_2d				s2											; LAYER_1										\n\
	dcl_2d				s3											; LAYER_2										\n\
	dcl_2d				s4											; ALPHA_1										\n\
	dcl_2d				s5											; LAYER_3										\n\
	dcl_2d				s6											; LAYER_4										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
	dcl					t2.xy																						\n\
	dcl					t3.xy																						\n\
	dcl					t4.xy																						\n\
	dcl					t5.xy																						\n\
	dcl					t6.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n"
	"																												\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
	texld_pp			r2,			t2,			s2					; Sample layer 1								\n\
	texld_pp			r3,			t3,			s3					; Sample layer 2								\n\
	texld_pp			r4,			t4,			s4					; Sample ALPHA_1 into R2						\n\
	texld_pp			r5,			t5,			s5					; Sample layer 3								\n\
	texld_pp			r6,			t6,			s6					; Sample layer 4								\n\
																													\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
	mad_pp				r8,			r2,			r0.y,		r8		; Multiply layer 1 by its factor into R8		\n\
	mad_pp				r8,			r3,			r0.z,		r8		; Multiply layer 2 by its factor into R8		\n\
	mad_pp				r8,			r5,			r4.x,		r8		; Multiply layer 3 by its factor into R8		\n\
	mad_pp				r8,			r6,			r4.y,		r8		; Multiply layer 4 by its factor into R8		\n\
																													\n\
	; Accumulate alpha factor into r9																				\n\
	dp3_pp				r9.x,		r0,			c0.x				; Combine alpha factor from ALPHA_0 into r9.x	\n\
	dp3_pp				r9.y,		r4,			c0.x				; Combine alpha factor from ALPHA_1 into r9.y	\n\
	add_pp				r9.x,		r9.x,		r9.y				; Combine alpha factor from both textures		\n\
																													\n\
	; Calculate base color * diffuse * fog																			\n\
	mul_pp				r7,			c1,			r9.x				; Modulate fog color by alpha factor into r7	\n\
	mul_pp				r8,			r8,			v0					; Modulate base texture with diffuse into r8	\n\
	lrp_pp				r0,			v0.w,		r8,			r7		; Linearly interpolate between fog and diffuse	\n\
																													\n\
	mad_pp				r0.xyz,		v1,			r8.w,		r0		; Modulate specular by alpha channel (*)		\n\
	mov_pp				r0.w,		r9.x							; Copy alpha factor into diffuse channel alpha	\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r0								; Move result into output						\n\
	";

	char *psSource6_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
	dcl_2d				s2											; LAYER_1										\n\
	dcl_2d				s3											; LAYER_2										\n\
	dcl_2d				s4											; ALPHA_1										\n\
	dcl_2d				s5											; LAYER_3										\n\
	dcl_2d				s6											; LAYER_4										\n\
	dcl_2d				s7											; LAYER_5										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
	dcl					t2.xy																						\n\
	dcl					t3.xy																						\n\
	dcl					t4.xy																						\n\
	dcl					t5.xy																						\n\
	dcl					t6.xy																						\n\
	dcl					t7.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n\
																													\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
	texld_pp			r2,			t2,			s2					; Sample layer 1								\n\
	texld_pp			r3,			t3,			s3					; Sample layer 2								\n\
	texld_pp			r4,			t4,			s4					; Sample ALPHA_1 into R2						\n\
	texld_pp			r5,			t5,			s5					; Sample layer 3								\n\
	texld_pp			r6,			t6,			s6					; Sample layer 4								\n\
	texld_pp			r7,			t7,			s7					; Sample layer 5								\n"
	"																												\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
	mad_pp				r8,			r2,			r0.y,		r8		; Multiply layer 1 by its factor into R8		\n\
	mad_pp				r8,			r3,			r0.z,		r8		; Multiply layer 2 by its factor into R8		\n\
	mad_pp				r8,			r5,			r4.x,		r8		; Multiply layer 3 by its factor into R8		\n\
	mad_pp				r8,			r6,			r4.y,		r8		; Multiply layer 4 by its factor into R8		\n\
	mad_pp				r8,			r7,			r4.z,		r8		; Multiply layer 5 by its factor into R8		\n\
																													\n\
	; Accumulate alpha factor into r9																				\n\
	dp3_pp				r9.x,		r0,			c0.x				; Combine alpha factor from ALPHA_0 into r9.x	\n\
	dp3_pp				r9.y,		r4,			c0.x				; Combine alpha factor from ALPHA_1 into r9.y	\n\
	add_pp				r9.x,		r9.x,		r9.y				; Combine alpha factor from both textures		\n\
																													\n\
	; Calculate base color * diffuse * fog																			\n\
	mul_pp				r7,			c1,			r9.x				; Modulate fog color by alpha factor into r7	\n\
	mul_pp				r8,			r8,			v0					; Modulate base texture with diffuse into r8	\n\
	lrp_pp				r0,			v0.w,		r8,			r7		; Linearly interpolate between fog and diffuse	\n\
																													\n\
	mad_pp				r0.xyz,		v1,			r8.w,		r0		; Modulate specular by alpha channel (*)		\n\
	mov_pp				r0.w,		r9.x							; Copy alpha factor into diffuse channel alpha	\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r0								; Move result into output						\n\
	";

	char *psSources_1_1[] = { psSource0_1_1, psSource1_1_1, psSource2_1_1, psSource3_1_1, psSourceFog_1_1 };
	char *psSources_2_0[] = { psSource0_1_1, psSource1_2_0, psSource2_2_0, psSource3_2_0, psSource4_2_0, psSource5_2_0, psSource6_2_0 };

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

	// Assemble pixel shaders (1.1)
	for(INT32 i = 0; i < 5; ++i)
	{
		m_pixelShaders_1_1[i] = RuD3DAssemblePixelShader(psSources_1_1[i]);

		if(m_pixelShaders_1_1[i] == NULL)
		{
			// Massive error, no pixel-shading capabilities
			m_maxLayersPerPass = 0;
		}
	}

	// Assemble pixel shaders (2.0)
	for(INT32 i = 0; i < 7; ++i)
	{
		m_pixelShaders_2_0[i] = RuD3DAssemblePixelShader(psSources_2_0[i]);

		if(m_pixelShaders_2_0[i] == NULL)
		{
			m_maxLayersPerPass = 3;
		}
	}

	// Overrides
	m_override_ZWrite = TRUE;
}

CRuShader_Terrain::~CRuShader_Terrain()
{
}

void CRuShader_Terrain::BeginPass(INT32 passNumber)
{
	BOOL isFogPass = ((passNumber == m_numPasses - 1) && (m_maxLayersPerPass == 3)) ? TRUE : FALSE;

	// Call base BeginPass to perform any additional setup
	CRuShader_Terrain_Base::BeginPass(passNumber);

	// Common
	INT32 uvStretchModifierConstantsOffset = 28 * 4;
	m_shaderConstants[uvStretchModifierConstantsOffset++] = 24.0f;
	m_shaderConstants[uvStretchModifierConstantsOffset++] = -24.0f;
	m_shaderConstants[uvStretchModifierConstantsOffset++] = 4.0f;
	m_shaderConstants[uvStretchModifierConstantsOffset++] = 4.0f;

	m_vertexDecl->Select();
	m_engine->SetVertexShader(m_vertexShader);

	INT32 numTexturesRemaining = m_numTextureLayers - (passNumber * m_maxLayersPerPass);

	if(m_maxLayersPerPass == 6)
	{
		// If the number of textures remaining is greater than the maximum number of layers per pass, then ...
		if(numTexturesRemaining >= m_maxLayersPerPass)
		{
			m_engine->SetPixelShader(m_pixelShaders_2_0[m_maxLayersPerPass]);
		}
		else
		{
			m_engine->SetPixelShader(m_pixelShaders_2_0[numTexturesRemaining]);
		}
	}
	else
	{
		// Fog pass - no samplers
		if(isFogPass)
		{
			m_engine->SetPixelShader(m_pixelShaders_1_1[4]);
		}
		else
		{
			// If the number of textures remaining is greater than the maximum number of layers per pass, then ...
			if(numTexturesRemaining >= m_maxLayersPerPass)
			{
				m_engine->SetPixelShader(m_pixelShaders_1_1[m_maxLayersPerPass]);
			}
			else
			{
				m_engine->SetPixelShader(m_pixelShaders_1_1[numTexturesRemaining]);
			}
		}
	}

	// Set shader constants
	m_engine->GetD3DDevice()->SetVertexShaderConstantF(0, m_shaderConstants, m_numBaseConstants);
	m_engine->GetD3DDevice()->SetPixelShaderConstantF(0, m_pixelShaderConstants, m_numBasePixelShaderConstants);

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

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

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

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

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

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

	if(passNumber == 0)
	{
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
	}
	else
	{
		if(isFogPass)
		{
			m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
			m_engine->SetRenderState(D3DRS_ALPHAREF, 0xFF);
			m_engine->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_LESS);

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

			m_engine->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		}
		else
		{
			m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
			m_engine->SetRenderState(D3DRS_ALPHAREF, 0x00);
			m_engine->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);

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

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

	m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
}

void CRuShader_Terrain::EndPass(INT32 passNumber)
{
}

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

	CRuShader_Terrain_Base::SetParameters(paramCache);

	if(paramCache->GetParameter(ruPARAMTYPE_SPLAT_ALPHAUVMODIFIER, param))
	{
		if(param)
		{
			INT32 uvModifierConstantsOffset = 27 * 4;
			float *uvModifier = (float *) param;

			m_shaderConstants[uvModifierConstantsOffset++] = uvModifier[0];
			m_shaderConstants[uvModifierConstantsOffset++] = uvModifier[1];
			m_shaderConstants[uvModifierConstantsOffset++] = uvModifier[2];
			m_shaderConstants[uvModifierConstantsOffset++] = uvModifier[3];
		}
	}

	if(paramCache->GetParameter(ruPARAMTYPE_SPLAT_LAYERCOUNT, param))
	{
		// Set the number of texture layers to blend
		m_numTextureLayers = param;

		if(m_numTextureLayers == 0)
		{
			m_numPasses = 1;
		}
		else
		{
			// If the number of texture layers requested exceeds the maximum allowed, cap it
			if(m_numTextureLayers > m_maxTextureLayers)
			{
				m_numTextureLayers = m_maxTextureLayers;
			}

			// Calculate the number of passes
			m_numPasses = (m_numTextureLayers / m_maxLayersPerPass) + ((m_numTextureLayers % m_maxLayersPerPass) ? 1 : 0);

			// Pixel Shader 1.1 has one extra fog pass
			if(m_maxLayersPerPass == 3)
			{
				m_numPasses += 1;
			}
		}
	}
}

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

CRuShader_Terrain_Highlight::CRuShader_Terrain_Highlight(CRuEngineD3D *engine)
:	CRuShader_Terrain_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_color			v2											; Declare diffuse								\n\
	dcl_texcoord0		v5											; Declare input texcoord 0						\n\
																													\n\
	mov					r1,			c20.yyyy																		\n\
	mov					r2,			c20.yyyy																		\n\
	m4x3				r1.xyz,		v0,			c3					; Transform vertex to view space				\n\
	m3x3				r2.xyz,		v1,			c3					; Transform normal to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	mov					oD0,		c26								; Copy global diffuse to output					\n\
	mov					oFog,		c20.yyyy																		\n\
	";

	char *psSource = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	mov					r0,			v0								; Move diffuse color into output				\n\
	";

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

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

	// Overrides
	m_override_ZWrite = TRUE;
}

CRuShader_Terrain_Highlight::~CRuShader_Terrain_Highlight()
{
}

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

	m_vertexDecl->Select();
	m_engine->SetVertexShader(m_vertexShader);
	m_engine->SetPixelShader(m_pixelShader);

	// Set shader constants
	m_engine->GetD3DDevice()->SetVertexShaderConstantF(0, m_shaderConstants, m_numBaseConstants);
	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_LESSEQUAL);
}

void CRuShader_Terrain_Highlight::EndPass(INT32 passNumber)
{
}

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

/*!
	SHADER CONSTANTS
	----------------
	[ 27 -  27] (brush x, brush z, radius, strength)
*/
CRuShader_Terrain_Brush::CRuShader_Terrain_Brush(CRuEngineD3D *engine)
:	CRuShader_Terrain_Base(engine)
{
	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
																													\n\
	mov					r1,			c20.yyyy																		\n\
	mov					r2,			c20.yyyy																		\n\
	m4x3				r1.xyz,		v0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	sub					r2.xy,		v0.xz,		c27.xy				; Make brush center the origin					\n\
	add					r2.xy,		r2.xy,		c27.z				; Offset origin by radius						\n\
	rcp					r3.x,		c27.z																			\n\
	mul					r3.x,		r3.x,		c20.z																\n\
	mul					oT0.xy,		r2.xy,		r3.x				; Transform into UV space						\n\
																													\n\
	mov					r0,			c20.yyyy						; Copy 0xFFFFFFFF to r0							\n\
	mul					r0.yz,		r0,			c27.w				; Modulate GB channels by strength				\n\
	mov					oD0,		r0																				\n\
	mov					oFog,		c20.yyyy																		\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_Terrain_Brush::~CRuShader_Terrain_Brush()
{
}

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

	m_vertexDecl->Select();
	m_engine->SetVertexShader(m_vertexShader);
	m_engine->SetPixelShader(m_pixelShader);

	// Set shader constants
	m_engine->GetD3DDevice()->SetVertexShaderConstantF(0, m_shaderConstants, m_numBaseConstants);
	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_LESSEQUAL);

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

	m_engine->SetSamplerState(0, D3DSAMP_MIPMAPLODBIAS, -2);
}

void CRuShader_Terrain_Brush::EndPass(INT32 passNumber)
{
	m_engine->SetSamplerState(0, D3DSAMP_MIPMAPLODBIAS, 0);
}

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

	CRuShader_Terrain_Base::SetParameters(paramCache);

	if(paramCache->GetParameter(ruPARAMTYPE_CUSTOM_0, param))
	{
		if(param)
		{
			INT32 brushParamConstantsOffset = 27 * 4;
			CRuVector3 *brushOrigin = (CRuVector3 *) param;

			m_shaderConstants[brushParamConstantsOffset++] = brushOrigin->x;
			m_shaderConstants[brushParamConstantsOffset++] = brushOrigin->z;
		}
	}

	if(paramCache->GetParameter(ruPARAMTYPE_CUSTOM_1, param))
	{
		if(param)
		{
			INT32 brushParamConstantsOffset = 27 * 4;
			float brushRadius = RuCastDWORDToFloat(param);

			m_shaderConstants[brushParamConstantsOffset + 2] = brushRadius;
		}
	}

	if(paramCache->GetParameter(ruPARAMTYPE_CUSTOM_2, param))
	{
		if(param)
		{
			INT32 brushParamConstantsOffset = 27 * 4;
			float brushStrength = RuCastDWORDToFloat(param);

			m_shaderConstants[brushParamConstantsOffset + 3] = brushStrength;
		}
	}
}

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

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

	// Overrides
	m_override_ZWrite = TRUE;
}

CRuShader_Terrain_Packed_Base::~CRuShader_Terrain_Packed_Base()
{
}

void CRuShader_Terrain_Packed_Base::Instance(INT32 streamIndex, IRuMesh *mesh, UINT32 morphTargetIndex, void *buffer) const
{
	if(streamIndex == 0)
	{
		CRuVertex_Terrain_Packed *vertices = (CRuVertex_Terrain_Packed *) 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];
				}
			}
		}
	}
}

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

CRuShader_Terrain_Packed::CRuShader_Terrain_Packed(CRuEngineD3D *engine)
:	CRuShader_Terrain_Packed_Base(engine),
	m_maxLayersPerPass(6),
	m_maxTextureLayers(12),
	m_numTextureLayers(0)
{
	m_override_Fog = FALSE;
	m_override_AlphaTest = TRUE;
	m_override_AlphaBlend = TRUE;

	char *vsSource_Simple = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_color			v2											; Declare diffuse (0xAAXXYYZZ)					\n\
																													\n\
	mov					r1,			c20.yyyy																		\n\
	m4x3				r1.xyz,		v0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	; Fog factor... optimize this																					\n\
	sub					r2,			c25.z,		c25.y																\n\
	rcp					r0,			r2																				\n\
	sub					r3,			r1.z,		c25.y																\n\
	mul					r0,			r3,			r0																	\n\
	sub					r0,			c20.y,		r0																	\n\
	max					r0,			r0.x,		c20.w																\n\
	min					r0,			r0.x,		c20.y																\n\
	mov					oD0.w,		r0.x							; output fog factor to diffuse alpha			\n\
	mov					oFog,		c20.y							; Output fog factor (disable it)				\n\
																													\n\
	; Color																											\n\
	mov					oD0,		c20.y							; Set diffuse to full bright					\n\
	mov					oD1,		c20.y							; Set specular to full bright					\n\
	";


	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_color			v2											; Declare diffuse (0xAAXXYYZZ)					\n\
																													\n\
	mov					r1,			c20.yyyy																		\n\
	mov					r7,			c20.yyyy																		\n\
	m4x3				r7.xyz,		v0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r7,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	; Unpack normal into r1																							\n\
	mov					r1,			v2								; Get packed data into r1						\n\
	sub					r1,			r1,			c20.z				; Bias by -0.5 to move into [-0.5, 0.5]			\n\
	rcp					r2,			c20.z							; Get 2.0 into r2								\n\
	mul					r1,			r1,			r2					; Multiply to move into [-1.0, 1.0]				\n\
																													\n\
	; Fog factor... optimize this																					\n\
	sub					r2,			c25.z,		c25.y																\n\
	rcp					r0,			r2																				\n\
	sub					r3,			r7.z,		c25.y																\n\
	mul					r0,			r3,			r0																	\n\
	sub					r0,			c20.y,		r0																	\n\
	max					r0,			r0.x,		c20.w																\n\
	min					r0,			r0.x,		c20.y																\n\
	mov					oD0.w,		r0.x							; output fog factor to diffuse alpha			\n\
	mov					oFog,		c20.y							; Output fog factor (disable it)				\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,		r1.x,		r4		; 1st-order terms								\n\
	mad					r4,			c13,		r1.y,		r4														\n\
	mad					r4,			c14,		r1.z,		r4														\n\
	mul					r5.x,		r1.x,		r1.z				; X * Z											\n\
	mul					r5.y,		r1.z,		r1.y				; Z * Y											\n\
	mul					r5.z,		r1.y,		r1.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,		r1,			r1																	\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\
	; Unpack diffuse into r0																						\n\
	mov					r0,			c20.y							; Move 1.0 into r0								\n\
	mov					r0.w,		v2.w							; Move alpha into r0.w							\n\
																													\n\
	; Diffuse color																									\n\
	mul					oD0.xyz,	r4,			r0					; Set diffuse									\n"
	"																												\n\
	; Specular color																								\n\
	m3x3				r2.xyz,		r1,			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,		r7					; 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					r4.xyz,		c21.xyz,	v0.xyz				; Calculate L									\n\
	m3x3				r3.xyz,		r4,			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,			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\
	; Calculate alpha texture UV																					\n\
	sub					r0,			v0.xz,		c27.xy				; Subtract origin from position					\n\
	mul					r0,			r0,			c27.zzzz			; Scale into [0, 1]								\n\
																													\n\
	mov					oT0.xy,		r0								; Copy alpha 0 uv to T0							\n\
	mul					oT1.xy,		r0,			c28					; Copy splat 0 uv to T1							\n\
	mul					oT2.xy,		r0,			c28					; Copy splat 1 uv to T2							\n\
	mul					oT3.xy,		r0,			c28					; Copy splat 2 uv to T3							\n\
	";

	char *psSource0_1_1 = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Fog																											\n\
	mov					r0,			c1								; Move fog color to output						\n\
	mov					r0.w,		v0.w							; Move fog factor to output alpha				\n\
	";

	char *psSource1_1_1 = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	def					c1,			1.0, 0.0, 0.0, 0.0																\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample alpha 0								\n\
	tex					t1											; Sample splat 0								\n\
																													\n\
	; Arithmetic ops																								\n\
	dp3					r1,			t0,			c1					; Get RED into r1								\n\
	mul_sat				r0,			t1,			r1					; Modulate layer 0								\n\
																													\n\
	; Fog and diffuse color																							\n\
	mul					r0.xyz,		r0,			v0					; Modulate base texture with diffuse into r0	\n\
	";

	char *psSource2_1_1 = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	def					c1,			1.0, 0.0, 0.0, 0.0																\n\
	def					c2,			0.0, 1.0, 0.0, 0.0																\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample alpha 0								\n\
	tex					t1											; Sample splat 0								\n\
	tex					t2											; Sample splat 1								\n\
																													\n\
	; Arithmetic ops																								\n\
	dp3					r1,			t0,			c1					; Get RED into r1								\n\
	mul_sat				r0,			t1,			r1					; Modulate layer 0								\n\
																													\n\
	dp3					r1,			t0,			c2					; Get BLUE into r1								\n\
	mad_sat				r0,			t2,			r1,			r0		; Modulate layer 1								\n\
																													\n\
	; Fog and diffuse color																							\n\
	mul					r0.xyz,		r0,			v0					; Modulate base texture with diffuse into r0	\n\
	";

	char *psSource3_1_1 = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	def					c1,			1.0, 0.0, 0.0, 0.0																\n\
	def					c2,			0.0, 1.0, 0.0, 0.0																\n\
	def					c3,			0.0, 0.0, 1.0, 0.0																\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample alpha 0								\n\
	tex					t1											; Sample splat 0								\n\
	tex					t2											; Sample splat 1								\n\
	tex					t3											; Sample splat 2								\n\
																													\n\
	; Arithmetic ops																								\n\
	dp3					r1,			t0,			c1					; Get RED into r1								\n\
	mul_sat				r0,			t1,			r1					; Modulate layer 0								\n\
																													\n\
	dp3					r1,			t0,			c2					; Get BLUE into r1								\n\
	mad_sat				r0,			t2,			r1,			r0		; Modulate layer 1								\n\
																													\n\
	dp3					r1,			t0,			c3					; Get GREEN into r1								\n\
	mad_sat				r0,			t3,			r1,			r0		; Modulate layer 2								\n\
																													\n\
	mul					r0.xyz,		r0,			v0					; Modulate base texture with diffuse into r0	\n\
	";

	char *psSourceFog_1_1 = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Fog																											\n\
	mov					r0,			c1								; Move fog color to output						\n\
	mov					r0.w,		v0.w							; Move fog factor to output alpha				\n\
	";

	char *psSource1_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n"
	"																												\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
																													\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
																													\n\
	; Accumulate alpha factor into r9																				\n\
	dp3_pp				r9.x,		r0,			c0.x				; Combine alpha factor from ALPHA_0 into r9.x	\n\
																													\n\
	; Calculate base color * diffuse * fog																			\n\
	mul_pp				r7,			c1,			r9.x				; Modulate fog color by alpha factor into r7	\n\
	mul_pp				r8,			r8,			v0					; Modulate base texture with diffuse into r8	\n\
	lrp_pp				r0,			v0.w,		r8,			r7		; Linearly interpolate between fog and diffuse	\n\
																													\n\
	mad_pp				r0.xyz,		v1,			r8.w,		r0		; Modulate specular by alpha channel (*)		\n\
	mov_pp				r0.w,		r9.x							; Copy alpha factor into diffuse channel alpha	\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r0								; Move result into output						\n\
	";

	char *psSource2_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
	dcl_2d				s2											; LAYER_1										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n"
	"																												\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
	texld_pp			r2,			t1,			s2					; Sample layer 1								\n\
																													\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
	mad_pp				r8,			r2,			r0.y,		r8		; Multiply layer 1 by its factor into R8		\n\
																													\n\
	; Accumulate alpha factor into r9																				\n\
	dp3_pp				r9.x,		r0,			c0.x				; Combine alpha factor from ALPHA_0 into r9.x	\n\
																													\n\
	; Calculate base color * diffuse * fog																			\n\
	mul_pp				r7,			c1,			r9.x				; Modulate fog color by alpha factor into r7	\n\
	mul_pp				r8,			r8,			v0					; Modulate base texture with diffuse into r8	\n\
	lrp_pp				r0,			v0.w,		r8,			r7		; Linearly interpolate between fog and diffuse	\n\
																													\n\
	mad_pp				r0.xyz,		v1,			r8.w,		r0		; Modulate specular by alpha channel (*)		\n\
	mov_pp				r0.w,		r9.x							; Copy alpha factor into diffuse channel alpha	\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r0								; Move result into output						\n\
	";

	char *psSource3_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
	dcl_2d				s2											; LAYER_1										\n\
	dcl_2d				s3											; LAYER_2										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n"
	"																												\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
	texld_pp			r2,			t1,			s2					; Sample layer 1								\n\
	texld_pp			r3,			t1,			s3					; Sample layer 2								\n\
																													\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
	mad_pp				r8,			r2,			r0.y,		r8		; Multiply layer 1 by its factor into R8		\n\
	mad_pp				r8,			r3,			r0.z,		r8		; Multiply layer 2 by its factor into R8		\n\
																													\n\
	; Accumulate alpha factor into r9																				\n\
	dp3_pp				r9.x,		r0,			c0.x				; Combine alpha factor from ALPHA_0 into r9.x	\n\
																													\n\
	; Calculate base color * diffuse * fog																			\n\
	mul_pp				r7,			c1,			r9.x				; Modulate fog color by alpha factor into r7	\n\
	mul_pp				r8,			r8,			v0					; Modulate base texture with diffuse into r8	\n\
	lrp_pp				r0,			v0.w,		r8,			r7		; Linearly interpolate between fog and diffuse	\n\
																													\n\
	mad_pp				r0.xyz,		v1,			r8.w,		r0		; Modulate specular by alpha channel (*)		\n\
	mov_pp				r0.w,		r9.x							; Copy alpha factor into diffuse channel alpha	\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r0								; Move result into output						\n\
	";

	char *psSource4_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
	dcl_2d				s2											; LAYER_1										\n\
	dcl_2d				s3											; LAYER_2										\n\
	dcl_2d				s4											; ALPHA_1										\n\
	dcl_2d				s5											; LAYER_3										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n"
	"																												\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
	texld_pp			r2,			t1,			s2					; Sample layer 1								\n\
	texld_pp			r3,			t1,			s3					; Sample layer 2								\n\
	texld_pp			r4,			t0,			s4					; Sample ALPHA_1 into R2						\n\
	texld_pp			r5,			t1,			s5					; Sample layer 3								\n\
																													\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
	mad_pp				r8,			r2,			r0.y,		r8		; Multiply layer 1 by its factor into R8		\n\
	mad_pp				r8,			r3,			r0.z,		r8		; Multiply layer 2 by its factor into R8		\n\
	mad_pp				r8,			r5,			r4.x,		r8		; Multiply layer 3 by its factor into R8		\n\
																													\n\
	; Accumulate alpha factor into r9																				\n\
	dp3_pp				r9.x,		r0,			c0.x				; Combine alpha factor from ALPHA_0 into r9.x	\n\
	dp3_pp				r9.y,		r4,			c0.x				; Combine alpha factor from ALPHA_1 into r9.y	\n\
	add_pp				r9.x,		r9.x,		r9.y				; Combine alpha factor from both textures		\n\
																													\n\
	; Calculate base color * diffuse * fog																			\n\
	mul_pp				r7,			c1,			r9.x				; Modulate fog color by alpha factor into r7	\n\
	mul_pp				r8,			r8,			v0					; Modulate base texture with diffuse into r8	\n\
	lrp_pp				r0,			v0.w,		r8,			r7		; Linearly interpolate between fog and diffuse	\n\
																													\n\
	mad_pp				r0.xyz,		v1,			r8.w,		r0		; Modulate specular by alpha channel (*)		\n\
	mov_pp				r0.w,		r9.x							; Copy alpha factor into diffuse channel alpha	\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r0								; Move result into output						\n\
	";

	char *psSource5_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
	dcl_2d				s2											; LAYER_1										\n\
	dcl_2d				s3											; LAYER_2										\n\
	dcl_2d				s4											; ALPHA_1										\n\
	dcl_2d				s5											; LAYER_3										\n\
	dcl_2d				s6											; LAYER_4										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n"
	"																												\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
	texld_pp			r2,			t1,			s2					; Sample layer 1								\n\
	texld_pp			r3,			t1,			s3					; Sample layer 2								\n\
	texld_pp			r4,			t0,			s4					; Sample ALPHA_1 into R2						\n\
	texld_pp			r5,			t1,			s5					; Sample layer 3								\n\
	texld_pp			r6,			t1,			s6					; Sample layer 4								\n\
																													\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
	mad_pp				r8,			r2,			r0.y,		r8		; Multiply layer 1 by its factor into R8		\n\
	mad_pp				r8,			r3,			r0.z,		r8		; Multiply layer 2 by its factor into R8		\n\
	mad_pp				r8,			r5,			r4.x,		r8		; Multiply layer 3 by its factor into R8		\n\
	mad_pp				r8,			r6,			r4.y,		r8		; Multiply layer 4 by its factor into R8		\n\
																													\n\
	; Accumulate alpha factor into r9																				\n\
	dp3_pp				r9.x,		r0,			c0.x				; Combine alpha factor from ALPHA_0 into r9.x	\n\
	dp3_pp				r9.y,		r4,			c0.x				; Combine alpha factor from ALPHA_1 into r9.y	\n\
	add_pp				r9.x,		r9.x,		r9.y				; Combine alpha factor from both textures		\n\
																													\n\
	; Calculate base color * diffuse * fog																			\n\
	mul_pp				r7,			c1,			r9.x				; Modulate fog color by alpha factor into r7	\n\
	mul_pp				r8,			r8,			v0					; Modulate base texture with diffuse into r8	\n\
	lrp_pp				r0,			v0.w,		r8,			r7		; Linearly interpolate between fog and diffuse	\n\
																													\n\
	mad_pp				r0.xyz,		v1,			r8.w,		r0		; Modulate specular by alpha channel (*)		\n\
	mov_pp				r0.w,		r9.x							; Copy alpha factor into diffuse channel alpha	\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r0								; Move result into output						\n\
	";

	char *psSource6_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
	dcl_2d				s2											; LAYER_1										\n\
	dcl_2d				s3											; LAYER_2										\n\
	dcl_2d				s4											; ALPHA_1										\n\
	dcl_2d				s5											; LAYER_3										\n\
	dcl_2d				s6											; LAYER_4										\n\
	dcl_2d				s7											; LAYER_5										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n\
																													\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
	texld_pp			r2,			t1,			s2					; Sample layer 1								\n\
	texld_pp			r3,			t1,			s3					; Sample layer 2								\n\
	texld_pp			r4,			t0,			s4					; Sample ALPHA_1 into R2						\n\
	texld_pp			r5,			t1,			s5					; Sample layer 3								\n\
	texld_pp			r6,			t1,			s6					; Sample layer 4								\n\
	texld_pp			r7,			t1,			s7					; Sample layer 5								\n"
	"																												\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
	mad_pp				r8,			r2,			r0.y,		r8		; Multiply layer 1 by its factor into R8		\n\
	mad_pp				r8,			r3,			r0.z,		r8		; Multiply layer 2 by its factor into R8		\n\
	mad_pp				r8,			r5,			r4.x,		r8		; Multiply layer 3 by its factor into R8		\n\
	mad_pp				r8,			r6,			r4.y,		r8		; Multiply layer 4 by its factor into R8		\n\
	mad_pp				r8,			r7,			r4.z,		r8		; Multiply layer 5 by its factor into R8		\n\
																													\n\
	; Accumulate alpha factor into r9																				\n\
	dp3_pp				r9.x,		r0,			c0.x				; Combine alpha factor from ALPHA_0 into r9.x	\n\
	dp3_pp				r9.y,		r4,			c0.x				; Combine alpha factor from ALPHA_1 into r9.y	\n\
	add_pp				r9.x,		r9.x,		r9.y				; Combine alpha factor from both textures		\n\
																													\n\
	; Calculate base color * diffuse * fog																			\n\
	mul_pp				r7,			c1,			r9.x				; Modulate fog color by alpha factor into r7	\n\
	mul_pp				r8,			r8,			v0					; Modulate base texture with diffuse into r8	\n\
	lrp_pp				r0,			v0.w,		r8,			r7		; Linearly interpolate between fog and diffuse	\n\
																													\n\
	mad_pp				r0.xyz,		v1,			r8.w,		r0		; Modulate specular by alpha channel (*)		\n\
	mov_pp				r0.w,		r9.x							; Copy alpha factor into diffuse channel alpha	\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r0								; Move result into output						\n\
	";

	char *psSources_1_1[] = { psSource0_1_1, psSource1_1_1, psSource2_1_1, psSource3_1_1, psSourceFog_1_1 };
	char *psSources_2_0[] = { psSource0_1_1, psSource1_2_0, psSource2_2_0, psSource3_2_0, psSource4_2_0, psSource5_2_0, psSource6_2_0 };

	// Assemble vertex shader
//	m_vertexShader = RuD3DAssembleVertexShader(vsSource);
	m_vertexShaders[0] = RuD3DAssembleVertexShader(vsSource_Simple);
	m_vertexShaders[1] = RuD3DAssembleVertexShader(vsSource);

	// Assemble pixel shaders (1.1)
	for(INT32 i = 0; i < 5; ++i)
	{
		m_pixelShaders_1_1[i] = RuD3DAssemblePixelShader(psSources_1_1[i]);

		if(m_pixelShaders_1_1[i] == NULL)
		{
			// Massive error, no pixel-shading capabilities
			m_maxLayersPerPass = 0;
		}
	}

	// Assemble pixel shaders (2.0)
	for(INT32 i = 0; i < 7; ++i)
	{
		m_pixelShaders_2_0[i] = RuD3DAssemblePixelShader(psSources_2_0[i]);

		if(m_pixelShaders_2_0[i] == NULL)
		{
			m_maxLayersPerPass = 3;
		}
	}
}

CRuShader_Terrain_Packed::~CRuShader_Terrain_Packed()
{
	for(INT32 i = 0; i < 2; ++i)
	{
		if(m_vertexShaders[i])
		{
			m_vertexShaders[i]->Release();
		}
	}
}

void CRuShader_Terrain_Packed::BeginPass(INT32 passNumber)
{
	BOOL isFogPass = ((passNumber == m_numPasses - 1) && (m_maxLayersPerPass == 3)) ? TRUE : FALSE;

	// Call base BeginPass to perform any additional setup
	CRuShader_Terrain_Packed_Base::BeginPass(passNumber);

	// Common
	INT32 uvStretchModifierConstantsOffset = 28 * 4;
	m_shaderConstants[uvStretchModifierConstantsOffset++] = 24.0f;
	m_shaderConstants[uvStretchModifierConstantsOffset++] = -24.0f;
	m_shaderConstants[uvStretchModifierConstantsOffset++] = 4.0f;
	m_shaderConstants[uvStretchModifierConstantsOffset++] = 4.0f;

	m_vertexDecl->Select();

	if(m_numTextureLayers == 0)
	{
		m_engine->SetVertexShader(m_vertexShaders[0]);
	}
	else
	{
		m_engine->SetVertexShader(m_vertexShaders[1]);
	}

	INT32 numTexturesRemaining = m_numTextureLayers - (passNumber * m_maxLayersPerPass);

	if(m_maxLayersPerPass == 6)
	{
		// If the number of textures remaining is greater than the maximum number of layers per pass, then ...
		if(numTexturesRemaining >= m_maxLayersPerPass)
		{
			m_engine->SetPixelShader(m_pixelShaders_2_0[m_maxLayersPerPass]);
		}
		else
		{
			m_engine->SetPixelShader(m_pixelShaders_2_0[numTexturesRemaining]);
		}
	}
	else
	{
		// Fog pass - no samplers
		if(isFogPass)
		{
			m_engine->SetPixelShader(m_pixelShaders_1_1[4]);
		}
		else
		{
			// If the number of textures remaining is greater than the maximum number of layers per pass, then ...
			if(numTexturesRemaining >= m_maxLayersPerPass)
			{
				m_engine->SetPixelShader(m_pixelShaders_1_1[m_maxLayersPerPass]);
			}
			else
			{
				m_engine->SetPixelShader(m_pixelShaders_1_1[numTexturesRemaining]);
			}
		}
	}

	// Set shader constants
	m_engine->GetD3DDevice()->SetVertexShaderConstantF(0, m_shaderConstants, m_numBaseConstants);
	m_engine->GetD3DDevice()->SetPixelShaderConstantF(0, m_pixelShaderConstants, m_numBasePixelShaderConstants);

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

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

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

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

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

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

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

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

	if(passNumber == 0)
	{
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
	}
	else
	{
		if(isFogPass)
		{
			m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
			m_engine->SetRenderState(D3DRS_ALPHAREF, 0xFF);
			m_engine->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_LESS);

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

			m_engine->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		}
		else
		{
			m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
			m_engine->SetRenderState(D3DRS_ALPHAREF, 0x00);
			m_engine->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);

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

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

	m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
}

void CRuShader_Terrain_Packed::EndPass(INT32 passNumber)
{
}

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

	CRuShader_Terrain_Packed_Base::SetParameters(paramCache);

	if(paramCache->GetParameter(ruPARAMTYPE_SPLAT_ALPHAUVMODIFIER, param))
	{
		if(param)
		{
			INT32 uvModifierConstantsOffset = 27 * 4;
			float *uvModifier = (float *) param;

			m_shaderConstants[uvModifierConstantsOffset++] = uvModifier[0];
			m_shaderConstants[uvModifierConstantsOffset++] = uvModifier[1];
			m_shaderConstants[uvModifierConstantsOffset++] = uvModifier[2];
			m_shaderConstants[uvModifierConstantsOffset++] = uvModifier[3];
		}
	}

	if(paramCache->GetParameter(ruPARAMTYPE_SPLAT_LAYERCOUNT, param))
	{
		// Set the number of texture layers to blend
		m_numTextureLayers = param;

		if(m_numTextureLayers == 0)
		{
			m_numPasses = 1;
		}
		else
		{
			// If the number of texture layers requested exceeds the maximum allowed, cap it
			if(m_numTextureLayers > m_maxTextureLayers)
			{
				m_numTextureLayers = m_maxTextureLayers;
			}

			// Calculate the number of passes
			m_numPasses = (m_numTextureLayers / m_maxLayersPerPass) + ((m_numTextureLayers % m_maxLayersPerPass) ? 1 : 0);

			// Pixel Shader 1.1 has one extra fog pass
			if(m_maxLayersPerPass == 3)
			{
				m_numPasses += 1;
			}
		}
	}
}

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

CRuShader_Terrain_Packed_Flat::CRuShader_Terrain_Packed_Flat(CRuEngineD3D *engine)
:	CRuShader_Terrain_Packed_Base(engine),
	m_maxLayersPerPass(6),
	m_maxTextureLayers(12),
	m_numTextureLayers(0)
{
	m_override_Fog = FALSE;
	m_override_AlphaTest = TRUE;
	m_override_AlphaBlend = TRUE;

	char *vsSource_Simple = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_color			v2											; Declare diffuse (0xAAXXYYZZ)					\n\
																													\n\
	mov					r1,			c20.yyyy																		\n\
	m4x3				r1.xyz,		v0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	; Fog factor... optimize this																					\n\
	sub					r2,			c25.z,		c25.y																\n\
	rcp					r0,			r2																				\n\
	sub					r3,			r1.z,		c25.y																\n\
	mul					r0,			r3,			r0																	\n\
	sub					r0,			c20.y,		r0																	\n\
	max					r0,			r0.x,		c20.w																\n\
	min					r0,			r0.x,		c20.y																\n\
	mov					oD0.w,		r0.x							; output fog factor to diffuse alpha			\n\
	mov					oFog,		c20.y							; Output fog factor (disable it)				\n\
																													\n\
	; Color																											\n\
	mov					oD0,		c20.y							; Set diffuse to full bright					\n\
	mov					oD1,		c20.y							; Set specular to full bright					\n\
	";


	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_color			v2											; Declare diffuse (0xAAXXYYZZ)					\n\
																													\n\
	mov					r1,			c20.yyyy																		\n\
	mov					r7,			c20.yyyy																		\n\
	m4x3				r7.xyz,		v0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r7,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	mov					oD0,		c20.y							; Output constant diffuse						\n\
	mov					oFog,		c20.y							; Output fog factor (disable it)				\n\
																													\n\
	; Calculate alpha texture UV																					\n\
	sub					r0,			v0.xz,		c27.xy				; Subtract origin from position					\n\
	mul					r0,			r0,			c27.zzzz			; Scale into [0, 1]								\n\
																													\n\
	mov					oT0.xy,		r0								; Copy alpha 0 uv to T0							\n\
	mul					oT1.xy,		r0,			c28					; Copy splat 0 uv to T1							\n\
	mul					oT2.xy,		r0,			c28					; Copy splat 1 uv to T2							\n\
	mul					oT3.xy,		r0,			c28					; Copy splat 2 uv to T3							\n\
	";

	char *psSource0_1_1 = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Fog																											\n\
	mov					r0,			c1								; Move fog color to output						\n\
	mov					r0.w,		v0.w							; Move fog factor to output alpha				\n\
	";

	char *psSource1_1_1 = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	def					c1,			1.0, 0.0, 0.0, 0.0																\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample alpha 0								\n\
	tex					t1											; Sample splat 0								\n\
																													\n\
	; Arithmetic ops																								\n\
	dp3					r1,			t0,			c1					; Get RED into r1								\n\
	mul_sat				r0,			t1,			r1					; Modulate layer 0								\n\
																													\n\
	; Fog and diffuse color																							\n\
	mul					r0.xyz,		r0,			v0					; Modulate base texture with diffuse into r0	\n\
	";

	char *psSource2_1_1 = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	def					c1,			1.0, 0.0, 0.0, 0.0																\n\
	def					c2,			0.0, 1.0, 0.0, 0.0																\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample alpha 0								\n\
	tex					t1											; Sample splat 0								\n\
	tex					t2											; Sample splat 1								\n\
																													\n\
	; Arithmetic ops																								\n\
	dp3					r1,			t0,			c1					; Get RED into r1								\n\
	mul_sat				r0,			t1,			r1					; Modulate layer 0								\n\
																													\n\
	dp3					r1,			t0,			c2					; Get BLUE into r1								\n\
	mad_sat				r0,			t2,			r1,			r0		; Modulate layer 1								\n\
																													\n\
	; Fog and diffuse color																							\n\
	mul					r0.xyz,		r0,			v0					; Modulate base texture with diffuse into r0	\n\
	";

	char *psSource3_1_1 = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	def					c1,			1.0, 0.0, 0.0, 0.0																\n\
	def					c2,			0.0, 1.0, 0.0, 0.0																\n\
	def					c3,			0.0, 0.0, 1.0, 0.0																\n\
																													\n\
	; Texture sampling																								\n\
	tex					t0											; Sample alpha 0								\n\
	tex					t1											; Sample splat 0								\n\
	tex					t2											; Sample splat 1								\n\
	tex					t3											; Sample splat 2								\n\
																													\n\
	; Arithmetic ops																								\n\
	dp3					r1,			t0,			c1					; Get RED into r1								\n\
	mul_sat				r0,			t1,			r1					; Modulate layer 0								\n\
																													\n\
	dp3					r1,			t0,			c2					; Get BLUE into r1								\n\
	mad_sat				r0,			t2,			r1,			r0		; Modulate layer 1								\n\
																													\n\
	dp3					r1,			t0,			c3					; Get GREEN into r1								\n\
	mad_sat				r0,			t3,			r1,			r0		; Modulate layer 2								\n\
																													\n\
	mul					r0.xyz,		r0,			v0					; Modulate base texture with diffuse into r0	\n\
	";

	char *psSourceFog_1_1 = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Fog																											\n\
	mov					r0,			c1								; Move fog color to output						\n\
	mov					r0.w,		v0.w							; Move fog factor to output alpha				\n\
	";

	char *psSource1_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n"
	"																												\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
																													\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r8								; Move result into output						\n\
	";

	char *psSource2_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
	dcl_2d				s2											; LAYER_1										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n"
	"																												\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
	texld_pp			r2,			t1,			s2					; Sample layer 1								\n\
																													\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
	mad_pp				r8,			r2,			r0.y,		r8		; Multiply layer 1 by its factor into R8		\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r8								; Move result into output						\n\
	";

	char *psSource3_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
	dcl_2d				s2											; LAYER_1										\n\
	dcl_2d				s3											; LAYER_2										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n"
	"																												\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
	texld_pp			r2,			t1,			s2					; Sample layer 1								\n\
	texld_pp			r3,			t1,			s3					; Sample layer 2								\n\
																													\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
	mad_pp				r8,			r2,			r0.y,		r8		; Multiply layer 1 by its factor into R8		\n\
	mad_pp				r8,			r3,			r0.z,		r8		; Multiply layer 2 by its factor into R8		\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r8								; Move result into output						\n\
	";

	char *psSource4_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
	dcl_2d				s2											; LAYER_1										\n\
	dcl_2d				s3											; LAYER_2										\n\
	dcl_2d				s4											; ALPHA_1										\n\
	dcl_2d				s5											; LAYER_3										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n"
	"																												\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
	texld_pp			r2,			t1,			s2					; Sample layer 1								\n\
	texld_pp			r3,			t1,			s3					; Sample layer 2								\n\
	texld_pp			r4,			t0,			s4					; Sample ALPHA_1 into R2						\n\
	texld_pp			r5,			t1,			s5					; Sample layer 3								\n\
																													\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
	mad_pp				r8,			r2,			r0.y,		r8		; Multiply layer 1 by its factor into R8		\n\
	mad_pp				r8,			r3,			r0.z,		r8		; Multiply layer 2 by its factor into R8		\n\
	mad_pp				r8,			r5,			r4.x,		r8		; Multiply layer 3 by its factor into R8		\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r8								; Move result into output						\n\
	";

	char *psSource5_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
	dcl_2d				s2											; LAYER_1										\n\
	dcl_2d				s3											; LAYER_2										\n\
	dcl_2d				s4											; ALPHA_1										\n\
	dcl_2d				s5											; LAYER_3										\n\
	dcl_2d				s6											; LAYER_4										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n"
	"																												\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
	texld_pp			r2,			t1,			s2					; Sample layer 1								\n\
	texld_pp			r3,			t1,			s3					; Sample layer 2								\n\
	texld_pp			r4,			t0,			s4					; Sample ALPHA_1 into R2						\n\
	texld_pp			r5,			t1,			s5					; Sample layer 3								\n\
	texld_pp			r6,			t1,			s6					; Sample layer 4								\n\
																													\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
	mad_pp				r8,			r2,			r0.y,		r8		; Multiply layer 1 by its factor into R8		\n\
	mad_pp				r8,			r3,			r0.z,		r8		; Multiply layer 2 by its factor into R8		\n\
	mad_pp				r8,			r5,			r4.x,		r8		; Multiply layer 3 by its factor into R8		\n\
	mad_pp				r8,			r6,			r4.y,		r8		; Multiply layer 4 by its factor into R8		\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r8								; Move result into output						\n\
	";

	char *psSource6_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; ALPHA_0										\n\
	dcl_2d				s1											; LAYER_0										\n\
	dcl_2d				s2											; LAYER_1										\n\
	dcl_2d				s3											; LAYER_2										\n\
	dcl_2d				s4											; ALPHA_1										\n\
	dcl_2d				s5											; LAYER_3										\n\
	dcl_2d				s6											; LAYER_4										\n\
	dcl_2d				s7											; LAYER_5										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
	dcl					t1.xy																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n\
																													\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample ALPHA_0 into R1						\n\
	texld_pp			r1,			t1,			s1					; Sample layer 0								\n\
	texld_pp			r2,			t1,			s2					; Sample layer 1								\n\
	texld_pp			r3,			t1,			s3					; Sample layer 2								\n\
	texld_pp			r4,			t0,			s4					; Sample ALPHA_1 into R2						\n\
	texld_pp			r5,			t1,			s5					; Sample layer 3								\n\
	texld_pp			r6,			t1,			s6					; Sample layer 4								\n\
	texld_pp			r7,			t1,			s7					; Sample layer 5								\n"
	"																												\n\
	; Accumulate base color into r8																					\n\
	mul_pp				r8,			r1,			r0.x				; Multiply layer 0 by its factor into R8		\n\
	mad_pp				r8,			r2,			r0.y,		r8		; Multiply layer 1 by its factor into R8		\n\
	mad_pp				r8,			r3,			r0.z,		r8		; Multiply layer 2 by its factor into R8		\n\
	mad_pp				r8,			r5,			r4.x,		r8		; Multiply layer 3 by its factor into R8		\n\
	mad_pp				r8,			r6,			r4.y,		r8		; Multiply layer 4 by its factor into R8		\n\
	mad_pp				r8,			r7,			r4.z,		r8		; Multiply layer 5 by its factor into R8		\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r8								; Move result into output						\n\
	";

	char *psSources_1_1[] = { psSource0_1_1, psSource1_1_1, psSource2_1_1, psSource3_1_1, psSourceFog_1_1 };
	char *psSources_2_0[] = { psSource0_1_1, psSource1_2_0, psSource2_2_0, psSource3_2_0, psSource4_2_0, psSource5_2_0, psSource6_2_0 };

	// Assemble vertex shader
//	m_vertexShader = RuD3DAssembleVertexShader(vsSource);
	m_vertexShaders[0] = RuD3DAssembleVertexShader(vsSource_Simple);
	m_vertexShaders[1] = RuD3DAssembleVertexShader(vsSource);

	// Assemble pixel shaders (1.1)
	for(INT32 i = 0; i < 5; ++i)
	{
		m_pixelShaders_1_1[i] = RuD3DAssemblePixelShader(psSources_1_1[i]);

		if(m_pixelShaders_1_1[i] == NULL)
		{
			// Massive error, no pixel-shading capabilities
			m_maxLayersPerPass = 0;
		}
	}

	// Assemble pixel shaders (2.0)
	for(INT32 i = 0; i < 7; ++i)
	{
		m_pixelShaders_2_0[i] = RuD3DAssemblePixelShader(psSources_2_0[i]);

		if(m_pixelShaders_2_0[i] == NULL)
		{
			m_maxLayersPerPass = 3;
		}
	}
}

CRuShader_Terrain_Packed_Flat::~CRuShader_Terrain_Packed_Flat()
{
	for(INT32 i = 0; i < 2; ++i)
	{
		if(m_vertexShaders[i])
		{
			m_vertexShaders[i]->Release();
		}
	}
}

void CRuShader_Terrain_Packed_Flat::BeginPass(INT32 passNumber)
{
	BOOL isFogPass = ((passNumber == m_numPasses - 1) && (m_maxLayersPerPass == 3)) ? TRUE : FALSE;

	// Call base BeginPass to perform any additional setup
	CRuShader_Terrain_Packed_Base::BeginPass(passNumber);

	// Common
	INT32 uvStretchModifierConstantsOffset = 28 * 4;
	m_shaderConstants[uvStretchModifierConstantsOffset++] = 24.0f;
	m_shaderConstants[uvStretchModifierConstantsOffset++] = -24.0f;
	m_shaderConstants[uvStretchModifierConstantsOffset++] = 4.0f;
	m_shaderConstants[uvStretchModifierConstantsOffset++] = 4.0f;

	m_vertexDecl->Select();

	if(m_numTextureLayers == 0)
	{
		m_engine->SetVertexShader(m_vertexShaders[0]);
	}
	else
	{
		m_engine->SetVertexShader(m_vertexShaders[1]);
	}

	INT32 numTexturesRemaining = m_numTextureLayers - (passNumber * m_maxLayersPerPass);

	if(m_maxLayersPerPass == 6)
	{
		// If the number of textures remaining is greater than the maximum number of layers per pass, then ...
		if(numTexturesRemaining >= m_maxLayersPerPass)
		{
			m_engine->SetPixelShader(m_pixelShaders_2_0[m_maxLayersPerPass]);
		}
		else
		{
			m_engine->SetPixelShader(m_pixelShaders_2_0[numTexturesRemaining]);
		}
	}
	else
	{
		// Fog pass - no samplers
		if(isFogPass)
		{
			m_engine->SetPixelShader(m_pixelShaders_1_1[4]);
		}
		else
		{
			// If the number of textures remaining is greater than the maximum number of layers per pass, then ...
			if(numTexturesRemaining >= m_maxLayersPerPass)
			{
				m_engine->SetPixelShader(m_pixelShaders_1_1[m_maxLayersPerPass]);
			}
			else
			{
				m_engine->SetPixelShader(m_pixelShaders_1_1[numTexturesRemaining]);
			}
		}
	}

	// Set shader constants
	m_engine->GetD3DDevice()->SetVertexShaderConstantF(0, m_shaderConstants, m_numBaseConstants);
	m_engine->GetD3DDevice()->SetPixelShaderConstantF(0, m_pixelShaderConstants, m_numBasePixelShaderConstants);

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

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

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

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

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

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

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

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

	if(passNumber == 0)
	{
		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
	}
	else
	{
		if(isFogPass)
		{
			m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
			m_engine->SetRenderState(D3DRS_ALPHAREF, 0xFF);
			m_engine->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_LESS);

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

			m_engine->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
		}
		else
		{
			m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
			m_engine->SetRenderState(D3DRS_ALPHAREF, 0x00);
			m_engine->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);

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

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

	m_engine->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);
}

void CRuShader_Terrain_Packed_Flat::EndPass(INT32 passNumber)
{
}

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

	CRuShader_Terrain_Packed_Base::SetParameters(paramCache);

	if(paramCache->GetParameter(ruPARAMTYPE_SPLAT_ALPHAUVMODIFIER, param))
	{
		if(param)
		{
			INT32 uvModifierConstantsOffset = 27 * 4;
			float *uvModifier = (float *) param;

			m_shaderConstants[uvModifierConstantsOffset++] = uvModifier[0];
			m_shaderConstants[uvModifierConstantsOffset++] = uvModifier[1];
			m_shaderConstants[uvModifierConstantsOffset++] = uvModifier[2];
			m_shaderConstants[uvModifierConstantsOffset++] = uvModifier[3];
		}
	}

	if(paramCache->GetParameter(ruPARAMTYPE_SPLAT_LAYERCOUNT, param))
	{
		// Set the number of texture layers to blend
		m_numTextureLayers = param;

		if(m_numTextureLayers == 0)
		{
			m_numPasses = 1;
		}
		else
		{
			// If the number of texture layers requested exceeds the maximum allowed, cap it
			if(m_numTextureLayers > m_maxTextureLayers)
			{
				m_numTextureLayers = m_maxTextureLayers;
			}

			// Calculate the number of passes
			m_numPasses = (m_numTextureLayers / m_maxLayersPerPass) + ((m_numTextureLayers % m_maxLayersPerPass) ? 1 : 0);

			// Pixel Shader 1.1 has one extra fog pass
			if(m_maxLayersPerPass == 3)
			{
				m_numPasses += 1;
			}
		}
	}
}

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

CRuShader_Terrain_Packed_Projection::CRuShader_Terrain_Packed_Projection(CRuEngineD3D *engine)
:	CRuShader_Terrain_Packed_Base(engine)
{
	m_override_Fog = FALSE;
	m_override_AlphaTest = TRUE;
	m_override_AlphaBlend = TRUE;

	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_color			v2											; Declare diffuse (0xAAXXYYZZ)					\n\
																													\n\
	mov					r1,			c20.yyyy																		\n\
	mov					r7,			c20.yyyy																		\n\
	m4x3				r7.xyz,		v0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r7,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	; Unpack normal into r1																							\n\
	mov					r1,			v2								; Get packed data into r1						\n\
	sub					r1,			r1,			c20.z				; Bias by -0.5 to move into [-0.5, 0.5]			\n\
	rcp					r2,			c20.z							; Get 2.0 into r2								\n\
	mul					r1,			r1,			r2					; Multiply to move into [-1.0, 1.0]				\n\
																													\n\
	; Fog factor... optimize this																					\n\
	sub					r2,			c25.z,		c25.y																\n\
	rcp					r0,			r2																				\n\
	sub					r3,			r7.z,		c25.y																\n\
	mul					r0,			r3,			r0																	\n\
	sub					r0,			c20.y,		r0																	\n\
	max					r0,			r0.x,		c20.w																\n\
	min					r0,			r0.x,		c20.y																\n\
	mov					oD0.w,		r0.x							; output fog factor to diffuse alpha			\n\
	mov					oFog,		c20.y							; Output fog factor (disable it)				\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,		r1.x,		r4		; 1st-order terms								\n\
	mad					r4,			c13,		r1.y,		r4														\n\
	mad					r4,			c14,		r1.z,		r4														\n\
	mul					r5.x,		r1.x,		r1.z				; X * Z											\n\
	mul					r5.y,		r1.z,		r1.y				; Z * Y											\n\
	mul					r5.z,		r1.y,		r1.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,		r1,			r1																	\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\
	; Unpack diffuse into r0																						\n\
	mov					r0,			c20.y							; Move 1.0 into r0								\n\
	mov					r0.w,		v2.w							; Move alpha into r0.w							\n\
																													\n\
	; Diffuse color																									\n\
	mul					oD0.xyz,	r4,			r0					; Set diffuse									\n"
	"																												\n\
	; Specular color																								\n\
	m3x3				r2.xyz,		r1,			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,		r7					; 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					r4.xyz,		c21.xyz,	v0.xyz				; Calculate L									\n\
	m3x3				r3.xyz,		r4,			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,			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\
	; Calculate projected texture UV																				\n\
	m4x4				oT0.xyzw,	r7,			c27					; Transform from view space to UV space			\n\
	";

	char *psSource_2_0 = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; PROJECTION									\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xyzw																						\n\
																													\n\
	dcl					v0.xyzw																						\n\
																													\n\
	; Divide texture coordinates by their z component																\n\
	rcp					r3,			t0.w																			\n\
	mul					r2,			t0,			r3																	\n\
																													\n\
	; Texture sampling																								\n\
	texld				r0,			r2,			s0					; Sample PROJECTION								\n\
																													\n\
	mul					r3,			r0,			v0					; Multiply by diffuse color						\n\
	mov					r3.w,		v0.w																			\n\
																													\n\
	mov					oC0,		r0								; Move result into output						\n\
	";

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

	// Assemble pixel shader (1.1)
	m_pixelShader = RuD3DAssemblePixelShader(psSource_2_0);
}

CRuShader_Terrain_Packed_Projection::~CRuShader_Terrain_Packed_Projection()
{
}

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

		m_engine->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);

		m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);

		m_engine->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
		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_Terrain_Packed_Projection::EndPass(INT32 passNumber)
{
}

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

	CRuShader_Terrain_Packed_Base::SetParameters(paramCache);

	if(paramCache->GetParameter(ruPARAMTYPE_TRANSFORM_PROJECTION, param))
	{
		// Setup uv projection
		CRuMatrix4x4 texTransform = *((CRuMatrix4x4 *) param);

		texTransform._11 *= 0.5f;
		texTransform._22 *= -0.5f;
		texTransform._31 += 0.5f;
		texTransform._32 += 0.5f;

		INT32 uvTransformOffset = 27 * 4;

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

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

CRuShader_Terrain_Packed_Backdrop::CRuShader_Terrain_Packed_Backdrop(CRuEngineD3D *engine)
:	CRuShader_Terrain_Packed_Base(engine)
{
	m_override_Fog = FALSE;
	m_override_AlphaTest = TRUE;
	m_override_AlphaBlend = TRUE;

	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_color			v2											; Declare diffuse (0xAAXXYYZZ)					\n\
																													\n\
	mov					r1,			c20.yyyy																		\n\
	m4x3				r1.xyz,		v0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
	";

	char *psSource = "\
																													\n\
	ps_1_1																											\n\
																													\n\
	; Fog																											\n\
	mov					r0,			c1								; Move fog color to output						\n\
	";


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

	m_pixelShader = RuD3DAssemblePixelShader(psSource);
}

CRuShader_Terrain_Packed_Backdrop::~CRuShader_Terrain_Packed_Backdrop()
{
}

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


	m_engine->SetVertexShader(m_vertexShader);
	m_engine->SetPixelShader(m_pixelShader);

	// Set shader constants
	m_engine->GetD3DDevice()->SetVertexShaderConstantF(0, m_shaderConstants, m_numBaseConstants);
	m_engine->GetD3DDevice()->SetPixelShaderConstantF(0, m_pixelShaderConstants, m_numBasePixelShaderConstants);

	m_engine->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);

	m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);

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

void CRuShader_Terrain_Packed_Backdrop::EndPass(INT32 passNumber)
{
}

void CRuShader_Terrain_Packed_Backdrop::SetParameters(const CRuParameterCache *paramCache)
{
	CRuShader_Terrain_Packed_Base::SetParameters(paramCache);
}

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

#pragma managed
