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

#pragma unmanaged

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

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

	char *psSource = "\
																													\n\
	ps_2_0																											\n\
																													\n\
	def					c30,		0.125, 0.375, 0.625, 0.875		; Fixed constants used by combiner				\n\
	def					c31,		0.33333, 1.0, 0.0, 0.0			; Fixed constants used by combiner				\n\
																													\n\
	; Declare texture samplers																						\n\
	dcl_2d				s0											; Diffuse										\n\
	dcl_2d				s1											; Layer mask									\n\
	dcl_volume			s2											; Color map	(3D texture)						\n\
	dcl_2d				s3											; Gloss											\n\
																													\n\
	; Declare texture coordinate registers																			\n\
	dcl					t0.xy																						\n\
																													\n\
	; Declare color registers																						\n\
	dcl					v0.xyzw																						\n\
	dcl					v1.xyzw																						\n\
																													\n\
	; Texture sampling																								\n\
	texld_pp			r0,			t0,			s0					; Sample diffuse into r0						\n\
	texld_pp			r1,			t0,			s1					; Sample mask into r1							\n\
	texld_pp			r2,			t0,			s3					; Sample gloss into r2							\n\
																													\n\
	mov					r3.xy,		t0																				\n\
																													\n\
	; Sample layer 0 color from color map																			\n\
	mov					r3.z,		c30.x							; Select correct w coordinate					\n\
	texld_pp			r8,			r3,			s2					; Sample texture into r8						\n\
																													\n\
	; Sample layer 1 color from color map																			\n\
	mov					r3.z,		c30.y							; Select correct w coordinate					\n\
	texld_pp			r9,			r3,			s2					; Sample texture into r9						\n\
																													\n\
	; Sample layer 2 color from color map																			\n\
	mov					r3.z,		c30.z							; Select correct w coordinate					\n\
	texld_pp			r10,		r3,			s2					; Sample texture into r8						\n\
																													\n\
	; Sample layer 3 color from color map																			\n\
	mov					r3.z,		c30.w							; Select correct w coordinate					\n\
	texld_pp			r11,		r3,			s2					; Sample texture into r8						\n\
																													\n\
	; Arithmetic ops																								\n\
	mov					r5,			r0								; Copy diffuse to r5							\n\
	dp3					r3,			c31.y,		r0					; Convert diffuse to gray-scale					\n\
	mul					r3,			r3,			c31.x				; Store gray-scale in r3						\n\
																													\n\
	; Layer 0																										\n\
	mul					r4,			r3,			r8					; Remap layer 0 color							\n\
	lrp					r6,			r1.x,		r4,			r5														\n\
																													\n\
	; Layer 1																										\n\
	mul					r4,			r3,			r9					; Remap layer 1 color							\n\
	lrp					r5,			r1.y,		r4,			r6														\n\
																													\n\
	; Layer 2																										\n\
	mul					r4,			r3,			r10					; Remap layer 1 color							\n\
	lrp					r6,			r1.z,		r4,			r5														\n\
																													\n\
	; Layer 3																										\n\
	mul					r4,			r3,			r11					; Remap layer 1 color							\n\
	lrp					r5,			r1.w,		r4,			r6														\n\
																													\n\
	; Light color combining																							\n\
	mul					r0.xyz,		r5,			v0					; Modulate final texture with diffuse color		\n\
	mad					r0.xyz,		r2,			v1,			r0		; Modulate gloss texture with specular and add	\n\
																													\n\
	; Move final result to output																					\n\
	mov_pp				oC0,		r0								; Move result into output						\n\
	";

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

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

CRuShader_Paperdoll_SH9_Gloss::~CRuShader_Paperdoll_SH9_Gloss()
{
}

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

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

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

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

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

		m_engine->SetSamplerState(2, D3DSAMP_MINFILTER, D3DTEXF_POINT);
		m_engine->SetSamplerState(2, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
		m_engine->SetSamplerState(2, D3DSAMP_MIPFILTER, D3DTEXF_POINT);

		m_engine->SetSamplerState(2, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
		m_engine->SetSamplerState(2, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
		m_engine->SetSamplerState(2, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP);

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

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

void CRuShader_Paperdoll_SH9_Gloss::EndPass(INT32 passNumber)
{
}

void CRuShader_Paperdoll_SH9_Gloss::SetParameters(const CRuParameterCache *paramCache)
{
	// Chain to parent class
	CRuShader_Static_Base::SetParameters(paramCache);
}

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

#pragma managed
