//--------------------------------------------------------------------
// Skinned Mesh Effect with per pixel specular
// Author: Ben Smith
// Date  : November 30th, 2005
//--------------------------------------------------------------------

#include "Effects/StdFunctions.fx"

//--------------------------------------------------------------------
// Global Variables
//--------------------------------------------------------------------
#ifndef MATRIX_PALETTE_SIZE
#define MATRIX_PALETTE_SIZE 22
#endif

float	 NumInfluences;
float4x3 BonePalette[MATRIX_PALETTE_SIZE];
float4x4 World : WORLD;

struct VS_IN
{
	float4 Pos : POSITION;
	float3 BlendWeights : BLENDWEIGHT;
	float4 BlendIndices : BLENDINDICES;
	float3 Normal : NORMAL;
	float3 TexCoord : TEXCOORD0;
};

struct VS_OUT
{
	float4 Pos : POSITION;
	float2 TexCoord : TEXCOORD0;
	float3 Normal : TEXCOORD1;
	float4 MPos : TEXCOORD2;
};

struct SKIN_OUT
{
	float4 Pos;
	float3 Normal;
};

SKIN_OUT Skin(float4 Pos, float3 BlendWeights, float4 BlendIndices, float3 Normal, int NumInfluences)
{
	SKIN_OUT Output = (SKIN_OUT)0;
	
	float LastWeight = 1.0f;
	float Weight;
	float BWArray[3] = (float[3])BlendWeights;
	int BIArray[4] =  (int[4])(BlendIndices);
	for (int boneIndex = 0; (boneIndex < 3) && (boneIndex < NumInfluences+1); ++boneIndex)
	{
		Weight = BlendWeights[boneIndex];
		LastWeight -= Weight;
		Output.Pos.xyz += mul(Pos, BonePalette[BlendIndices[boneIndex]])*Weight;
		Output.Normal += mul(Normal, BonePalette[BlendIndices[boneIndex]])*Weight;
	}
	Output.Pos.xyz += mul(Pos, BonePalette[BlendIndices[NumInfluences-1]])*LastWeight;
	Output.Normal += mul(Normal, BonePalette[BlendIndices[NumInfluences-1]])*LastWeight;
	
	return Output;
}

VS_OUT VSSkin(VS_IN Input, uniform int NumInfluences)
{
	VS_OUT Output = (VS_OUT)0;
	
	SKIN_OUT SkinOut = Skin(Input.Pos, Input.BlendWeights, Input.BlendIndices, Input.Normal, NumInfluences); 
	
	Output.Pos = mul(float4(SkinOut.Pos.xyz, 1.0f), ViewProjection);
	Output.Normal = normalize(SkinOut.Normal);
	Output.TexCoord = Input.TexCoord;
	Output.MPos = SkinOut.Pos;
	
	return Output;
}

sampler Sampler = sampler_state
{
    Texture = (Tex);
	MinFilter = Linear;
	MagFilter = Linear;
	MipFilter = Linear;
};

struct PS_OUT
{
	float4 Color : COLOR;
};

PS_OUT PSRenderScene(VS_OUT Input, uniform bool RenderTexture)
{
	PS_OUT Output;
    
	float3 phong = PhongVertexLighting(Input.MPos, Input.Normal, World, CameraEye,
								 LightDir, mDiffuse, mSpecular, mEmissive, mPower);
    
    if (RenderTexture)
		Output.Color.rgb = tex2D(Sampler, Input.TexCoord) * phong;
	else
		Output.Color.rgb = phong;
	
	Output.Color.a = mAlpha;
    
    return Output;
}

VertexShader vsArray[4] = {	compile vs_2_0 VSSkin(1),
							compile vs_2_0 VSSkin(2),
							compile vs_2_0 VSSkin(3),
							compile vs_2_0 VSSkin(4)};

technique RenderScene
{
	pass Skin
	{
		//Clockwise culling for RHW
		CULLMODE = CW;
		
		ZENABLE = true;
		ZWRITEENABLE = true;

        VertexShader = (vsArray[NumInfluences]);
        PixelShader  = compile ps_2_0 PSRenderScene(true);
	}
}

technique RenderScene_NoTexture
{
	pass Skin
	{
		//Clockwise culling for RHW
		CULLMODE = CW;
		
		ZENABLE = true;
		ZWRITEENABLE = true;

        VertexShader = (vsArray[NumInfluences]);
        PixelShader  = compile ps_2_0 PSRenderScene(false);
	}
}