#include "../../../Direct3D/Shader/SM10/RuShader_SM10_Doodad.h"

#pragma managed(push, off)

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

CRuShader_SM10_Particle_Doodad::CRuShader_SM10_Particle_Doodad(CRuEngineD3D *engine)
:	CRuShader_SM10_Base(engine)
{
	// Overrides
	m_override_Fog = FALSE;
	m_override_AlphaTest = FALSE;
	m_override_AlphaBlend = TRUE;
	m_override_ZWrite = FALSE;

	// 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_RUCOLOR,		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);

	// Vertex shader source
	char *vsSource = "\
																													\n\
	vs_1_1															; Vertex shader version 1.1						\n\
																													\n\
	dcl_position0		v0											; Declare position								\n\
	dcl_normal0			v1											; Declare normal								\n\
	dcl_color			v2											; Declare diffuse								\n\
	dcl_texcoord0		v5											; Declare input texcoord 0						\n\
																													\n\
	; Generate sin(c27.z)																							\n\
	mov					r1.x,		c27.z							; Move t into r1.x								\n\
	mad					r0.x,		r1.x,		c30.w,		c30.y	; Bring argument into [-PI, PI]					\n\
	expp				r0.y,		r0.x																			\n\
	mad					r0.x,		r0.y,		c30.z,		-c30.x													\n\
	dst					r2.xy,		r0.x,		r0.x				; Generate 1, (r0.x)^2, ..., (r0.x)^6			\n\
	mul					r2.z,		r2.y,		r2.y																\n\
	mul					r2.w,		r2.y,		r2.z																\n\
	mul					r0,			r2,			r0.x				; Generate r0.x, (r0.x)^3, .., (r0.x)^7			\n\
	dp4					r3.x,		r0,			c32					; Compute sin(r0.x)								\n\
																													\n\
	; Calculate index to instance data																				\n\
	mul					r2.x,		v2.w,		c28.x				; Scale diffuse alpha by 256 to get an integer	\n\
	mad					r2.x,		r2.x,		c28.y,		c28.z	; Calculate address index for row 0 in r2.x		\n\
	add					r2.y,		r2.x,		c20.y				; Calculate address index for row 1 in r2.y		\n\
	add					r2.z,		r2.y,		c20.y				; Calculate address index for row 2 in r2.z		\n\
																													\n\
	; Initial setup work																							\n\
	mov					r0,			c20.yyyy						; Move 1 into r0								\n\
	mov					r1,			c20.yyyy						; Move 1 into r1								\n\
	mov					r8,			c20.yyyy						; Move 1 into r8								\n\
																													\n\
	; Calculate position																							\n\
	mov					a0.x,		r2.y							; Copy row 1 index to index register			\n\
	mov					r3,			c[a0.x]							; Copy rotation quaternion into r3				\n\
	mov					a0.x,		r2.x							; Copy row 0 index to index register			\n\
	mul					r0.xyz,		v0,			c[a0.x].w			; Scale											\n\
	dp3					r1.x,		r3.xyz,		r0.xyz				; V . P											\n\
	mul					r4,			r0.yzxw,	r3.zxyw				; P x V											\n\
	mad					r4,			-r3.yzxw,	r0.zxyw,	r4		;												\n\
	mul					r1.xyz,		r1.x,		r3.xyz				; (V . P) * V									\n\
	mul					r4.xyz,		r4.xyz,		r3.w				; (P x V) * W									\n\
	add					r1.xyz,		r1.xyz,		r4.xyz				; [(V . P) * V] + [(P x V) * W]					\n\
	rcp					r5.x,		c20.z							; 1 / 0.5 = 2									\n\
	mul					r1.xyz,		r1.xyz,		r5.x				; 2 * [(V . P) * V] + [(P x V) * W]				\n\
	mul					r5.y,		r3.w,		r3.w				; W^2											\n\
	mul					r5.y,		r5.y,		r5.x				; 2 * W^2										\n\
	sub					r5.y,		r5.y,		c20.y				; 2 * W^2 - 1									\n\
	mul					r5.xyz,		r0.xyz,		r5.y				; (2 * W^2 - 1) * P								\n\
	add					r0.xyz,		r1.xyz,		r5.xyz				; (2 * W^2 - 1) * P + 2 * [(V . P) * V] + [(P x V) * W]		\n\
	add					r0.xyz,		r0,			c[a0.x]				; Translate										\n\
	;mov					a0.x,		r2.z							; Copy row 2 index to index register			\n\
	;mul					r1.xz,		r3.x,		c[a0.x].zw			; Calculate sway offset							\n\
	;mul					r1.xz,		r1.xz,		v2.z				; Multiply offset by y modifier					\n\
	;add					r0.xz,		r1.xz,		r0.xz				; Add to position								\n"
	"																												\n\
	m4x3				r1,			r0,			c3					; Transform vertex to view space				\n\
	m4x4				oPos,		r1,			c6					; Transform vertex to homogeneous space			\n\
																													\n\
	; Fog factor																									\n\
	sub					r3.x,		c25.z,		c25.y				; Fog End - Fog Start into r3.x					\n\
	rcp					r3.x,		r3.x							; Reciprocal of fog range into r0.x				\n\
	sub					r4.x,		r1.z,		c25.y				; Offset vertex z by fog start into r3.x		\n\
	mul					r3.x,		r4.x,		r3.x				; Divide z by fog range into r0					\n\
	max					r3.x,		r3.x,		c20.w				; Clamp to [0, oo]								\n\
	add					r3.x,		r3.x,		c25.x				; Add constant fog term							\n\
	max					r3.x,		r3.x,		c20.w				; Clamp to [0, 1]								\n\
	min					r3.x,		r3.x,		c20.y																\n\
	sub					r3.x,		c20.y,		r3.x				; Invert fog factor								\n\
	mov					oFog,		r3.x							; Output fog factor								\n"
	"																												\n\
	; Normal into r3																								\n\
	mov					r3,			v1																				\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,		r3.x,		r4		; 1st-order terms								\n\
	mad					r4,			c13,		r3.y,		r4														\n\
	mad					r4,			c14,		r3.z,		r4														\n\
	mul					r5.x,		r3.x,		r3.z				; X * Z											\n\
	mul					r5.y,		r3.z,		r3.y				; Z * Y											\n\
	mul					r5.z,		r3.y,		r3.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,		r3,			r3																	\n\
	mul					r5.z,		r5.z,		c20.x																\n\
	sub					r5.z,		r5.z,		c20.y																\n\
	mad					r4,			c18,		r5.z,		r4														\n\
	sub					r5.x,		r5.x,		r5.y																\n\
	mad					r4,			c19,		r5.x,		r4														\n"
	"																												\n\
	; Diffuse color																									\n\
	mul					r4.w,		r1.z,		c28.w				; Divide z by fade distance into r4.w			\n\
	sub					r4.w,		c20.y,		r4.w				; Invert										\n\
	max					r4.w,		r4.w,		c20.w				; Clamp to [0, 1]								\n\
	min					r4.w,		r4.w,		c20.y																\n\
	mul					r4,			r4,			c26					; Multiply diffuse by global diffuse			\n\
	mov					oD0,		r4								; Set diffuse									\n\
																													\n\
	; Calculate texture coordinates																					\n\
	mov					a0.x,		r2.z							; Copy row 2 index to index register			\n\
	mov					r3.xy,		c27.xy							; Move uv increments into r3					\n\
	mul					r1.xy,		c[a0.x].xy,	r3.xy				; Calculate subtexture uv origin				\n\
	mad					r0.xy,		v5.xy,		r3.xy,		r1.xy													\n\
	mov					oT0,		r0																				\n\
	";

	char *psSource = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; DIFFUSE										\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xyzw										; Diffuse texture UV							\n\
	dcl					t1.xyzw										; Grass particle widget center					\n\
																													\n\
	dcl					v0.xyzw																						\n\
																													\n\
	texld				r0,			t0,			s0					; Sample DIFFUSE into r0						\n\
	mul					r0,			r0,			v0					; Modulate with diffuse color					\n\
	mov					oC0,		r0								; Move result into output						\n\
																													\n\
	; Modify output depth																							\n\
	;mov					oDepth,		t1.z																			\n\
	";

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

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

CRuShader_SM10_Particle_Doodad::~CRuShader_SM10_Particle_Doodad()
{
}

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

	if(passNumber == 0)
	{
		m_vertexDecl->Select();
		m_engine->SetVertexShader(m_vertexShader);
		m_engine->SetPixelShader(m_pixelShader);

		m_engine->SetVertexShaderConstants(0, m_shaderConstants, m_numConstantRows);
		m_engine->SetPixelShaderConstants(0, m_pixelShaderConstants, m_numBasePixelShaderConstants);

		m_engine->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);

		m_engine->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
		m_engine->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);

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

		m_engine->SetRenderState(D3DRS_ALPHAREF, 10);

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

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

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

void CRuShader_SM10_Particle_Doodad::EndPass(INT32 passNumber)
{
	CRuShader_SM10_Base::EndPass(passNumber);
}

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

	CRuShader_SM10_Base::SetParameters(paramCache);

	if(paramCache->GetParameter(ruPARAMTYPE_GEOINSTANCE_S_COUNT, param))
	{
		m_numInstances = (UINT32) param;
		CRuMatrix4x4 *transform = (CRuMatrix4x4 *) param;

	}

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

		// Number of constants = instance dataset + 24 constants for the per-draw data
		INT32 numConstants = 24 + m_numInstances * 12;
		INT32 constantOffset = 27 * 4;

		m_numConstantRows = (constantOffset + numConstants) / 4;

		RuMemcpy(&m_shaderConstants[constantOffset], instanceData, sizeof(float) * numConstants);
	}
}

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

#pragma managed(pop)
