//
// Skinned Mesh Effect file 
//

float4 MaterialAmbient : MATERIALAMBIENT = {0.1f, 0.1f, 0.1f, 1.0f};
float4 MaterialDiffuse : MATERIALDIFFUSE = {0.8f, 0.8f, 0.8f, 1.0f};
float4 MaterialSpecular : MATERIALSPECULAR = {1.0f, 1.0f, 1.0f, 7.0f};
float4x3 TransformMatrix;
float4x4 ProjectionMatrix;

// Matrix Pallette
static const int MAX_MATRICES = 26;
float4x3    mWorldMatrixArray[MAX_MATRICES] : WORLDMATRIXARRAY;
float4x4    mViewProj : VIEWPROJECTION;

// lighting information
vector		LightVector;
vector		LightPos;
vector		EyePos;
float4		LightColor;

// direction of light from sky (view space)
float3 DirFromSky < string UIDirectional = "Direction from Sky"; > = { 0.0f, -1.0f, 0.0f };            

// light intensity
float4 I_a = { 0.5f, 0.5f, 0.5f, 1.0f };    // ambient
float4 I_b = { 0.0f, 0.0f, 0.0f, 1.0f };    // ground
float4 I_c = { 1.0f, 1.0f, 1.0f, 1.0f };    // sky

int    power   = 8;

///////////////////////////////////////////////////////
struct VS_INPUT
{
    float4  Pos             : POSITION;
    float4  BlendWeights    : BLENDWEIGHT;
    float4  BlendIndices    : BLENDINDICES;
    float3  Normal          : NORMAL;
    float3  Tex0            : TEXCOORD0;
};

struct VS_OUTPUT
{
    float4  Pos      : POSITION;
    float4  Diffuse  : COLOR0;
    float4  Specular : COLOR1;
    float2  Tex0     : TEXCOORD0;
};


VS_OUTPUT VShade(VS_INPUT i, uniform int NumBones)
{
    VS_OUTPUT   o;
    float3      Pos = 0.0f;
    float3      Normal = 0.0f;    
    float       LastWeight = 0.0f;
     
    // Compensate for lack of UBYTE4 on Geforce3
    int4 IndexVector = D3DCOLORtoUBYTE4(i.BlendIndices);

    // cast the vectors to arrays for use in the for loop below
    float BlendWeightsArray[4] = (float[4])i.BlendWeights;
    int   IndexArray[4]        = (int[4])IndexVector;
    
    // calculate the pos/normal using the "normal" weights 
    //        and accumulate the weights to calculate the last weight
    for (int iBone = 0; iBone < NumBones-1; iBone++)
    {
        LastWeight = LastWeight + BlendWeightsArray[iBone];
        
        Pos += mul(i.Pos, mWorldMatrixArray[IndexArray[iBone]]) * BlendWeightsArray[iBone];
        Normal += mul(i.Normal, mWorldMatrixArray[IndexArray[iBone]]) * BlendWeightsArray[iBone];
    }
    LastWeight = 1.0f - LastWeight; 

    // Now that we have the calculated weight, add in the final influence
    Pos += (mul(i.Pos, mWorldMatrixArray[IndexArray[NumBones-1]]) * LastWeight);
    Normal += (mul(i.Normal, mWorldMatrixArray[IndexArray[NumBones-1]]) * LastWeight); 
    
    // transform position from world space into view and then projection space
    o.Pos = mul(float4(Pos.xyz, 1.0f), mViewProj);

    // normalize normals
    Normal = normalize(Normal);

    // perform lighting
    float3 P = mul(i.Pos, (float4x3)TransformMatrix);
    float3 L = -LightVector;                                // diffuse direction
    float3 Y = -DirFromSky;                                 // hemisphere up axis
    //DEL float3 N = normalize(mul(i.Normal, (float3x3)TransformMatrix));   // normal (view space)
    float3 N = i.Normal;
    float3 R = normalize(2 * dot(N, L) * N - L);            // reflection vector (view space)
    float3 V = -normalize(P);                               // view direction (view space)

    float4 Amb  = MaterialAmbient * I_a;
    float4 Hemi = MaterialAmbient * lerp(I_b, I_c, (dot(N, Y) + 1) / 2);
    float  temp = 1 - max(0, dot(N, L));
    float4 Diff = MaterialDiffuse * LightColor * (1 - temp * temp);
    float4 Spec = MaterialSpecular * MaterialSpecular * pow(max(0, dot(R, V)), power);

    o.Diffuse = Diff + Hemi + Amb;            // diffuse + ambient/hemisphere
    o.Specular = Spec;                        // specular

	// copy the input texture coordinate through
    o.Tex0  = i.Tex0.xy;

    return o;
}

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


//////////////////////////////////////
// Techniques specs follow
//////////////////////////////////////
technique t0
{
    pass p0
    {
        VertexShader = (vsArray[CurNumBones]);
    }
}
