//
// Skinned Mesh Effect file 
// Copyright (c) 2000-2002 Microsoft Corporation. All rights reserved.
//

///////////////////////////////////////////////////////----------------
//shader for Skinned Mesh
///////////////////////////////////////////////////////----------------
texture  g_MeshTexture;              // Color texture for mesh
bool     g_bFading;
bool     g_bAlpha;
float    g_fFadeRate;
float    g_fTime;
float4x4 g_mWorld;                  // World matrix for object
float4x4 g_mViewProjecton;

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

float g_fScaleRate;
int CurNumBones = 2;
//--------------------------------------------------------------------------------------
// Texture samplers
//--------------------------------------------------------------------------------------
sampler MeshTextureSampler = 
sampler_state
{
    Texture = <g_MeshTexture>;
    MipFilter = LINEAR;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
};

struct VS_SkinnedMesh_INPUT
{
    float4  Pos             : POSITION;
    float4  BlendWeights    : BLENDWEIGHT;
    float4  BlendIndices    : BLENDINDICES;
    float3  Tex0            : TEXCOORD0;
    float3  Offset          : NORMAL;
};

struct VS_OUTPUT
{
    float4 Position   : POSITION;   // vertex position 
    float2 TextureUV  : TEXCOORD0;  // vertex texture coords 
};

//--------------------------------------------------------------------------------------
// This shader computes standard transform and lighting
//--------------------------------------------------------------------------------------
VS_OUTPUT VShader( float4 vPos : POSITION,
                   float2 vTexCoord0 : TEXCOORD0)
{
    VS_OUTPUT Output;
    
    // Transform the position from object space to homogeneous projection space
    vPos = mul(vPos, g_mWorld);
    Output.Position = mul(vPos, g_mViewProjecton);

    Output.TextureUV = vTexCoord0; 
    
    return Output;    
}

VS_OUTPUT CandleVShader( float4 vPos : POSITION,
                   float2 vTexCoord0 : TEXCOORD0)
{
    VS_OUTPUT Output;
    
    vPos.x *= g_fScaleRate;
    vPos.y *= g_fScaleRate;
    // Transform the position from object space to homogeneous projection space
    vPos = mul(vPos, g_mWorld);
    Output.Position = mul(vPos, g_mViewProjecton);

    Output.TextureUV = vTexCoord0; 
    
    return Output;    
}

VS_OUTPUT VSkinnedMeshShade(VS_SkinnedMesh_INPUT i, uniform int NumBones, uniform bool bDistort)
{
    VS_OUTPUT   o;
    float3      Pos = 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];
    }
    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);
    
    // transform position from world space into view and then projection space
    if (bDistort)
        Pos += i.Offset;

    float4 vPos = mul(float4(Pos.xyz, 1.0f), g_mWorld);

    o.Position = mul(vPos, g_mViewProjecton);

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

    return o;
}

//--------------------------------------------------------------------------------------
// Pixel shader output structure
//--------------------------------------------------------------------------------------
struct PS_OUTPUT
{
    float4 RGBColor : COLOR0;  // Pixel color    
};

PS_OUTPUT PShader( VS_OUTPUT In) 
{ 
    PS_OUTPUT Output;
    float4 color = tex2D(MeshTextureSampler, In.TextureUV);

    //float fLunmen = mul(float4(0.2125f, 0.7154f, 0.0721f, 0), color);
    float fRate = 1.0f;
    if (g_bFading)
    {
        fRate = g_fFadeRate;
    }

    if (g_bAlpha)
    {
        color.w *= fRate;
    }
    else
    {
        color.x *= fRate; 
        color.y *= fRate; 
        color.z *= fRate;    
    }

    Output.RGBColor = color;
    return Output;
}

PS_OUTPUT CandlePShader( VS_OUTPUT In) 
{ 
    PS_OUTPUT Output;
    float4 color = tex2D(MeshTextureSampler, In.TextureUV);  

    if (g_fScaleRate > 1.6f)
    {
        float fScale = sin(g_fTime * 2.0f) + 1;
        if (fScale < 1)
        {
            color.w *= (2 - fScale);
        }
        else
        {
            float fGap = (1 - color.w) * fScale;
            color.w = 1 - fGap;
        }
    }

    color.w = max(0, min(0.95f, color.w));

    Output.RGBColor = color;
    return Output;
}

VertexShader vsDistortionArray[4] = { compile vs_2_0 VSkinnedMeshShade(1, true), 
                                      compile vs_2_0 VSkinnedMeshShade(2, true),
                                      compile vs_2_0 VSkinnedMeshShade(3, true),
                                      compile vs_2_0 VSkinnedMeshShade(4, true)
                                    };

VertexShader vsArray[4] = { compile vs_2_0 VSkinnedMeshShade(1, false), 
                            compile vs_2_0 VSkinnedMeshShade(2, false),
                            compile vs_2_0 VSkinnedMeshShade(3, false),
                            compile vs_2_0 VSkinnedMeshShade(4, false)
                          };
//--------------------------------------------------------------------------------------
// Renders scene to render target
//--------------------------------------------------------------------------------------
technique RenderSceneTexture
{
    pass P0
    {          
        ZEnable          = FALSE;
        AlphaBlendEnable = True;

        SrcBlend         = SRCALPHA;
        DestBlend        = INVSRCALPHA;
        BlendOp          = ADD;

        VertexShader = compile vs_2_0 VShader( );
        PixelShader  = compile ps_2_0 PShader( ); // trivial pixel shader (could use FF instead if desired)
    }
}

technique RenderSceneCandle
{
    pass P0
    {          
        ZEnable          = FALSE;
        AlphaBlendEnable = True;

        SrcBlend         = SRCALPHA;
        DestBlend        = INVSRCALPHA;
        BlendOp          = ADD;

        VertexShader = compile vs_2_0 CandleVShader( );
        PixelShader  = compile ps_2_0 CandlePShader( ); // trivial pixel shader (could use FF instead if desired)
    }
}

technique SkinnedMeshZEnable
{
    pass p0
    {
        ZEnable          = True;
        AlphaBlendEnable = True;

        SrcBlend         = SRCALPHA;
        DestBlend        = INVSRCALPHA;
        BlendOp          = ADD;

        VertexShader = (vsArray[CurNumBones]);
        PixelShader  = compile ps_2_0 PShader( ); 
    }
}

technique SkinnedMesh
{
    pass p0
    {
        ZEnable          = FALSE;
        AlphaBlendEnable = True;

        SrcBlend         = SRCALPHA;
        DestBlend        = INVSRCALPHA;
        BlendOp          = ADD;

        VertexShader = (vsArray[CurNumBones]);
        PixelShader  = compile ps_2_0 PShader( ); 
    }
}

technique DistortionSkinnedMesh
{
    pass p0
    {
        ZEnable          = TRUE;
        AlphaBlendEnable = True;

        SrcBlend         = SRCALPHA;
        DestBlend        = INVSRCALPHA;
        BlendOp          = ADD;

        VertexShader = (vsDistortionArray[CurNumBones]);
        PixelShader  = compile ps_2_0 PShader( ); 
    }
}
