//
// Asura_D3D_VS_Skin_Order2SH_LowEnd.cpp
//
// Created by VGP - 27Mar2006 (based on Asura_D3D_VS_Skin_Order2SH.cpp)
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

// This file's header.
#include "Rendering/Asura_Direct3D_Shaders.h"

static Direct3D_VertexElement g_axCharacter_Vertex_Decl[] = 
{
	{0,  0,  D3DDECLTYPE_FLOAT3,	D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION,		0},
	{0,  12, D3DDECLTYPE_FLOAT3,	D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,			0},
	{0,  24, D3DDECLTYPE_FLOAT2,	D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD,		0},
	{0,  32, D3DDECLTYPE_FLOAT4,	D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDINDICES,	0},
	{0,	 48, D3DDECLTYPE_FLOAT4,	D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT,	0},

	D3DDECL_END()
};


static char* g_szVertexShader =
{
	"vs.1.1 \n"

	"dcl_position		v0 \n"
	"dcl_normal			v1 \n"
	"dcl_texcoord		v2 \n"
	"dcl_blendindices	v3 \n"
	"dcl_blendweight	v4 \n"

	// rotate and translate the vertex by the first bone's transform
	"mov a0.x, v3.x \n"
	"dp4 r1.x, c[a0.x+12], v0 \n"
	"dp4 r1.y, c[a0.x+13], v0 \n"
	"dp4 r1.z, c[a0.x+14], v0 \n"
	// scale the result by the weighting
	"mul r1.xyz, r1, v4.x \n"

	// now rotate the normal by the first bone (ignore translation)
	"dp3 r3.x, c[a0.x+12], v1 \n"
	"dp3 r3.y, c[a0.x+13], v1 \n"
	"dp3 r3.z, c[a0.x+14], v1 \n"
	// set r3.w to 1.0f to allow for dp4 processing
	"mov r3.w, v0.w	\n"
				
	// rotate and translate the vertex by the second bone's transform,
	// then accumulate result taking weighting into account
	"mov a0.x, v3.y \n"
	"dp4 r2.x, c[a0.x+12], v0 \n"
	"dp4 r2.y, c[a0.x+13], v0 \n"
	"dp4 r2.z, c[a0.x+14], v0 \n"
	"mad r1.xyz, r2, v4.y, r1 \n"
												
	// rotate and translate the vertex by the third bone's transform,
	// then accumulate result taking weighting into account
	"mov a0.x, v3.z \n"
	"dp4 r2.x, c[a0.x+12], v0 \n"
	"dp4 r2.y, c[a0.x+13], v0 \n"
	"dp4 r2.z, c[a0.x+14], v0 \n"
	"mad r1.xyz, r2, v4.z, r1 \n"
												
	// rotate and translate the vertex by the forth bone's transform,
	// then accumulate result taking weighting into account
	"mov a0.x, v3.w \n"
	"dp4 r2.x, c[a0.x+12], v0 \n"
	"dp4 r2.y, c[a0.x+13], v0 \n"
	"dp4 r2.z, c[a0.x+14], v0 \n"
	"mad r1.xyz, r2, v4.w, r1 \n"

	// touch up r1.w so it's 1.0f
	"mov r1.w, v0.w \n"

	// lighting
	// calculate colour from harmonic, and drag across alpha value
	"dp4 oD0.x, r3, c[4] \n"
	"dp4 oD0.y, r3, c[5] \n"
	"dp4 oD0.z, r3, c[6] \n"
	"mov oD0.w, c[7].w \n"

	// fog
	"mov oFog, c[7].y \n"

	// output uv co-ords (applying UV offsets)
	"add oT0, v2, c11 \n"
	"add oT1, v2, c11 \n"

    // Transform to screen space and write to output position register.
    "m4x4 oPos, r1, c0 \n"
};

static Asura_Direct3D_VertexShader xShader(
	ASURA_D3D_VS_SKIN_ORDER2SH_4BONES_VS1, 
	g_szVertexShader, 
	g_axCharacter_Vertex_Decl);

static char* g_szReflectiveVertexShader =
{
	"vs.1.1 \n"

	"dcl_position		v0 \n"
	"dcl_normal			v1 \n"
	"dcl_texcoord		v2 \n"
	"dcl_blendindices	v3 \n"
	"dcl_blendweight	v4 \n"

	// rotate and translate the vertex by the first bone's transform
	"mov a0.x, v3.x \n"
	"dp4 r1.x, c[a0.x+12], v0 \n"
	"dp4 r1.y, c[a0.x+13], v0 \n"
	"dp4 r1.z, c[a0.x+14], v0 \n"
	// scale the result by the weighting
	"mul r1.xyz, r1, v4.x \n"

	// now rotate the normal by the first bone (ignore translation)
	"dp3 r3.x, c[a0.x+12], v1 \n"
	"dp3 r3.y, c[a0.x+13], v1 \n"
	"dp3 r3.z, c[a0.x+14], v1 \n"
	// set r3.w to 1.0f to allow for dp4 processing
	"mov r3.w, v0.w	\n"
				
	// rotate and translate the vertex by the second bone's transform,
	// then accumulate result taking weighting into account
	"mov a0.x, v3.y \n"
	"dp4 r2.x, c[a0.x+12], v0 \n"
	"dp4 r2.y, c[a0.x+13], v0 \n"
	"dp4 r2.z, c[a0.x+14], v0 \n"
	"mad r1.xyz, r2, v4.y, r1 \n"
												
	// rotate and translate the vertex by the third bone's transform,
	// then accumulate result taking weighting into account
	"mov a0.x, v3.z \n"
	"dp4 r2.x, c[a0.x+12], v0 \n"
	"dp4 r2.y, c[a0.x+13], v0 \n"
	"dp4 r2.z, c[a0.x+14], v0 \n"
	"mad r1.xyz, r2, v4.z, r1 \n"
												
	// rotate and translate the vertex by the forth bone's transform,
	// then accumulate result taking weighting into account
	"mov a0.x, v3.w \n"
	"dp4 r2.x, c[a0.x+12], v0 \n"
	"dp4 r2.y, c[a0.x+13], v0 \n"
	"dp4 r2.z, c[a0.x+14], v0 \n"
	"mad r1.xyz, r2, v4.w, r1 \n"

	// touch up r1.w so it's 1.0f
	"mov r1.w, v0.w \n"

	// lighting
	// calculate colour from harmonic, and drag across alpha value
	"dp4 oD0.x, r3, c[4] \n"
	"dp4 oD0.y, r3, c[5] \n"
	"dp4 oD0.z, r3, c[6] \n"
	"mov oD0.w, c[7].w \n"

	// fog
	"mov oFog, c[7].y \n"

	// output uv co-ords (applying UV offsets)
	"add oT0, v2, c11 \n"

    // Transform to screen space and write to output position register.
    "m4x4 oPos, r1, c0 \n"

	// Reflection map coordinates
	// push vertex through view matrix and normalise to get cameraspace camera->vertex vector
	"m4x4 r5, r1, c[8] \n"
//DeadCode VGP 27/03/2006 	"nrm r2, r5 \n"
	"dp4 r2.w, r5, r5 \n"
	"rsq r2.w, r2.w   \n"
	"mul r2, r2.w, r5 \n"

	// push vertex normal through into cameraspace as well
	"m3x3 r5.xyz, r3, c[8] \n"
//DeadCode VGP 27/03/2006 	"nrm r4, r5 \n"
	"dp3 r4.w, r5, r5 \n"
	"rsq r4.w, r4.w   \n"
	"mul r4, r4.w, r5 \n"

	// reflection vector is D - 2(D.N)N
	"dp3 r5.x, r2.xyz, r4.xyz \n"		// D.N
	"add r5.x, r5.x, r5.x \n"   // 2(D.N)
	"mul r5.xyz, r4.xyz, r5.xxx \n" // 2(D.N)N
	"sub r5.xyz, r2.xyz, r5.xyz \n" // D - 2(D.N)N

	// fix up the w component to be 1
	"mov r5.w, v0.w \n"

	// push it through the transform matrix
	"dp4 oT1.x, r5, c[12] \n"
	"dp4 oT1.y, r5, c[13] \n"
};

static Asura_Direct3D_VertexShader xReflectiveShader(
	ASURA_D3D_VS_SKIN_ORDER2SH_4BONES_REFLECTIVE_VS1,
	g_szReflectiveVertexShader,
	g_axCharacter_Vertex_Decl);


static char* g_szSpecularVertexShader =
{
	"vs.1.1 \n"

	"dcl_position		v0 \n"
	"dcl_normal			v1 \n"
	"dcl_texcoord		v2 \n"
	"dcl_blendindices	v3 \n"
	"dcl_blendweight	v4 \n"

	// rotate and translate the vertex by the first bone's transform
	"mov a0.x, v3.x \n"
	"dp4 r1.x, c[a0.x+12], v0 \n"
	"dp4 r1.y, c[a0.x+13], v0 \n"
	"dp4 r1.z, c[a0.x+14], v0 \n"
	// scale the result by the weighting
	"mul r1.xyz, r1, v4.x \n"

	// now rotate the normal by the first bone (ignore translation)
	"dp3 r3.x, c[a0.x+12], v1 \n"
	"dp3 r3.y, c[a0.x+13], v1 \n"
	"dp3 r3.z, c[a0.x+14], v1 \n"
	// set r3.w to 1.0f to allow for dp4 processing
	"mov r3.w, v0.w	\n"
				
	// rotate and translate the vertex by the second bone's transform,
	// then accumulate result taking weighting into account
	"mov a0.x, v3.y \n"
	"dp4 r2.x, c[a0.x+12], v0 \n"
	"dp4 r2.y, c[a0.x+13], v0 \n"
	"dp4 r2.z, c[a0.x+14], v0 \n"
	"mad r1.xyz, r2, v4.y, r1 \n"
												
	// rotate and translate the vertex by the third bone's transform,
	// then accumulate result taking weighting into account
	"mov a0.x, v3.z \n"
	"dp4 r2.x, c[a0.x+12], v0 \n"
	"dp4 r2.y, c[a0.x+13], v0 \n"
	"dp4 r2.z, c[a0.x+14], v0 \n"
	"mad r1.xyz, r2, v4.z, r1 \n"
												
	// rotate and translate the vertex by the forth bone's transform,
	// then accumulate result taking weighting into account
	"mov a0.x, v3.w \n"
	"dp4 r2.x, c[a0.x+12], v0 \n"
	"dp4 r2.y, c[a0.x+13], v0 \n"
	"dp4 r2.z, c[a0.x+14], v0 \n"
	"mad r1.xyz, r2, v4.w, r1 \n"

	// touch up r1.w so it's 1.0f
	"mov r1.w, v0.w \n"

	// lighting
	// calculate colour from harmonic, and drag across alpha value
	"dp4 oD0.x, r3, c[4] \n"
	"dp4 oD0.y, r3, c[5] \n"
	"dp4 oD0.z, r3, c[6] \n"
	"mov oD0.w, c[7].w \n"

	// fog
	"mov oFog, c[7].y \n"

	// output uv co-ords (applying UV offsets)
	"add oT0, v2, c11 \n"

    // Transform to screen space and write to output position register.
    "m4x4 oPos, r1, c0 \n"

	// Output camera direction into tex coords for iteration
	"sub r2, c[8], r1 \n"					// Put camera pos - vertex pos (world space) in r0
	"dp3 r2.w, r2, r2 \n"					// r2.w = magnitude squared
	"rsq r2.w, r2.w \n"						// r2.w = 1 / magnitude
	"mul r2, r2, r2.w \n"					// r2 = camera dir / camera dir magnitude = V

	// Need to unscale and unbias vectors, since texcoord in ps clamps result to [0,1]
	"mad oT1.xyz, r2, c[8].w, c[8].w \n"	// oT1 = V*0.5 + 0.5

	// Copy world-space normal into oT2
	"mad oT2.xyz, r3, c[8].w, c[8].w \n"
};

static Asura_Direct3D_VertexShader xSpecularShader(
	ASURA_D3D_VS_SKIN_ORDER2SH_4BONES_SPECULAR_VS1,
	g_szSpecularVertexShader,
	g_axCharacter_Vertex_Decl);

