HLSLSkinMesh.fx
//=========================================================
// Desc: 效果源代码
//=========================================================
//---------------------------------------------------------
// 全局变量
//---------------------------------------------------------
float4 lightDir = {0.0f, 0.0f, -1.0f, 1.0f};
float4 lightDiffuse = {0.6f, 0.6f, 0.6f, 1.0f}; 
float4 MaterialAmbient = {0.1f, 0.1f, 0.1f, 1.0f};
float4 MaterialDiffuse = {0.8f, 0.8f, 0.8f, 1.0f};
static const int MAX_MATRICES = 26;
float4x3    mWorldMatrixArray[MAX_MATRICES];  //骨骼调色板矩阵 
int         CurNumBones = 2;    //当前骨骼数量
float4x4    mProj;
//----------------------------------------------------------
// 顶点渲染器输入和输出结构
//----------------------------------------------------------
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 : COLOR;
    float2  Tex0    : TEXCOORD0;
};
//---------------------------------------------------------
// 子函数, 计算光照系数
//---------------------------------------------------------
float3 Diffuse(float3 Normal)
{
    float CosTheta;
    CosTheta = max(0.0f, dot(Normal, lightDir.xyz));
    return (CosTheta);
}
//---------------------------------------------------------
// 子函数, 完成顶点处理
//---------------------------------------------------------
VS_OUTPUT VShade(VS_INPUT i, uniform int NumBones)
{
    VS_OUTPUT   o;
    float3      Pos = 0.0f;
    float3      Normal = 0.0f;
    float       sumWeight  = 0.0f;
    float       LastWeight = 0.0f;
     
    //为Geforce3类型的显卡所做的补偿
    int4 IndexVector = D3DCOLORtoUBYTE4(i.BlendIndices);
    
    //将骨骼权重向量和骨骼索引向量变换至数组
    float BlendWeightsArray[4] = (float[4])i.BlendWeights;
    int   IndexArray[4]        = (int[4])IndexVector;
    //计算前NumBones-1个骨骼对于该顶点位置及法向量的影响
    for (int iBone = 0; iBone < NumBones-1; iBone++)
    {
        sumWeight = sumWeight + BlendWeightsArray[iBone];
        
        Pos += mul(i.Pos, mWorldMatrixArray[IndexArray[iBone]]) * BlendWeightsArray[iBone];
        Normal += mul(i.Normal, mWorldMatrixArray[IndexArray[iBone]]) * BlendWeightsArray[iBone];
    }
    LastWeight = 1.0f - sumWeight; 
    //计算最后一个骨骼对于顶点位置及法向量的影响
    Pos += (mul(i.Pos, mWorldMatrixArray[IndexArray[NumBones-1]]) * LastWeight);
    Normal += (mul(i.Normal, mWorldMatrixArray[IndexArray[NumBones-1]]) * LastWeight); 
    
    o.Pos = mul(float4(Pos.xyz, 1.0f), mProj);
    Normal = normalize(Normal);
    //计算光照
    o.Diffuse.xyz = MaterialAmbient.xyz + Diffuse(Normal) * MaterialDiffuse.xyz;
    o.Diffuse.w = 1.0f;
    //输出纹理坐标
    o.Tex0  = i.Tex0.xy;
    return o;
}
//---------------------------------------------------------
// 顶点渲染器
//---------------------------------------------------------
VertexShader vsArray[4] = {
                            compile vs_1_1 VShade(1), 
                            compile vs_1_1 VShade(2),
                            compile vs_1_1 VShade(3),
                            compile vs_1_1 VShade(4)
                          };
//---------------------------------------------------------
// 技术与通道
//---------------------------------------------------------
technique t0
{
    pass p0
    {
        VertexShader = (vsArray[CurNumBones]);
    }
}
//=============================================================================
// Desc: 主程序源文件
//=============================================================================
#include "dxstdafx.h"
#include "resource.h"
#pragma warning(disable: 4995)
//-----------------------------------------------------------------------------
// Desc: 继承自DXDXFRAME结构的结构
//-----------------------------------------------------------------------------
struct D3DXFRAME_DERIVED: public D3DXFRAME
{
    D3DXMATRIXA16        CombinedTransformationMatrix;
};
//-----------------------------------------------------------------------------
// Desc: 继承自D3DXMESHCONTAINER结构的结构
//-----------------------------------------------------------------------------
struct D3DXMESHCONTAINER_DERIVED: public D3DXMESHCONTAINER
{
    LPDIRECT3DTEXTURE9*  ppTextures;            //纹理数组
    LPD3DXMESH           pOrigMesh;             //原网格
    DWORD                NumAttributeGroups;    //骨骼数量
    DWORD                NumInfl;               //每个顶点最多可以影响多少骨骼
    LPD3DXBUFFER         pBoneCombinationBuf;   //骨骼结合表
    D3DXMATRIX**         ppBoneMatrixPtrs;      //存放骨骼的组合变换矩阵
    D3DXMATRIX*          pBoneOffsetMatrices;   //存放骨骼的初始变换矩阵
    DWORD                NumPaletteEntries;     //有多少骨骼可以使用(上限)
    bool                 UseSoftwareVP;         //标识是否使用软件顶点处理
};
//-----------------------------------------------------------------------------
// Desc: 该类用来从.X文件加载框架层次和网格模型数据
//-----------------------------------------------------------------------------
class CAllocateHierarchy: public ID3DXAllocateHierarchy
{
private:
    HRESULT GenerateSkinnedMesh(IDirect3DDevice9 *pd3dDevice, D3DXMESHCONTAINER_DERIVED *pMeshContainer);
    HRESULT AllocateName( LPCSTR Name, LPSTR *pNewName );
    void    RemovePathFromFileName(LPSTR fullPath, LPWSTR fileName);
public:
    STDMETHOD(CreateFrame)(THIS_ LPCSTR Name, LPD3DXFRAME *ppNewFrame);
    STDMETHOD(CreateMeshContainer)(THIS_ 
        LPCSTR Name, 
        CONST D3DXMESHDATA *pMeshData,
        CONST D3DXMATERIAL *pMaterials, 
        CONST D3DXEFFECTINSTANCE *pEffectInstances, 
        DWORD NumMaterials, 
        CONST DWORD *pAdjacency, 
        LPD3DXSKININFO pSkinInfo, 
        LPD3DXMESHCONTAINER *ppNewMeshContainer);
    STDMETHOD(DestroyFrame)(THIS_ LPD3DXFRAME pFrameToFree);
    STDMETHOD(DestroyMeshContainer)(THIS_ LPD3DXMESHCONTAINER pMeshContainerBase);
    CAllocateHierarchy() {}
};
//-----------------------------------------------------------------------------
// 全局变量
//-----------------------------------------------------------------------------
ID3DXFont*                 g_pFont = NULL;          //ID3DXFont字体对象
ID3DXSprite*               g_pTextSprite = NULL;    //ID3DXSprite文本精灵对象
bool                       g_bShowHelp = true;      //标识是否显示简单说明文本
CDXUTDialogResourceManager g_DialogResourceManager; //对话框资源管理器
CD3DSettingsDlg            g_SettingsDlg;           //Direct3D设备设置对话框
CDXUTDialog                g_HUD;                   //对话框
CDXUTDialog                g_SampleUI;              //对话框
ID3DXEffect*              g_pEffect = NULL;
LPD3DXFRAME               g_pFrameRoot = NULL;
ID3DXAnimationController* g_pAnimController = NULL;
D3DXMATRIXA16*            g_pBoneMatrices = NULL;
UINT                      g_NumBoneMatricesMax = 0;
D3DXMATRIXA16             g_matWorld;
D3DXMATRIXA16             g_matView;
D3DXMATRIXA16             g_matProj;
//-----------------------------------------------------------------------------
// 控件ID
//-----------------------------------------------------------------------------
#define IDC_TOGGLEFULLSCREEN      1
#define IDC_TOGGLEREF             2
#define IDC_CHANGEDEVICE          3
//-----------------------------------------------------------------------------
// Desc: 函数声明
//------------------------------------------------------------------------------
bool    CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext );
bool    CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps, void* pUserContext );
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext );
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext );
void    CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext );
void    CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext );
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing, void* pUserContext );
void    CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext );
void    CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext );
void    CALLBACK OnLostDevice( void* pUserContext );
void    CALLBACK OnDestroyDevice( void* pUserContext );
void    InitApp();
void    RenderText();
void    DrawMeshContainer( IDirect3DDevice9 *pd3dDevice, LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameBase );
void    DrawFrame( IDirect3DDevice9 *pd3dDevice, LPD3DXFRAME pFrame );
HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainer );
HRESULT SetupBoneMatrixPointers( LPD3DXFRAME pFrame );
void    UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix );
//-----------------------------------------------------------------------------
// Desc: 
//-----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::AllocateName( LPCSTR Name, LPSTR *pNewName )
{
    UINT cbLength;
    if( Name != NULL )
    {
        cbLength = (UINT)strlen(Name) + 1;
        *pNewName = new CHAR[cbLength];
        if (*pNewName == NULL)
            return E_OUTOFMEMORY;
        memcpy( *pNewName, Name, cbLength*sizeof(CHAR) );
    }
    else
    {
        *pNewName = NULL;
    }
    return S_OK;
}
//-----------------------------------------------------------------------------
// Desc: 从绝对路径中提取文件名
//-----------------------------------------------------------------------------
void CAllocateHierarchy::RemovePathFromFileName(LPSTR fullPath, LPWSTR fileName)
{
    //先将fullPath的类型变换为LPWSTR
    WCHAR wszBuf[MAX_PATH];
    MultiByteToWideChar( CP_ACP, 0, fullPath, -1, wszBuf, MAX_PATH );
    wszBuf[MAX_PATH-1] = L'\0';
    WCHAR* wszFullPath = wszBuf;
    //从绝对路径中提取文件名
    LPWSTR pch=wcsrchr(wszFullPath,'\\');
    if (pch)
        lstrcpy(fileName, ++pch);
    else
        lstrcpy(fileName, wszFullPath);
}
//-----------------------------------------------------------------------------
// Desc: 创建框架, 仅仅是分配内存和初始化,还没有对其成员赋予合适的值
//-----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::CreateFrame( LPCSTR Name, LPD3DXFRAME *ppNewFrame )
{
    HRESULT hr = S_OK;
    D3DXFRAME_DERIVED *pFrame;
    
    *ppNewFrame = NULL;
    
    pFrame = new D3DXFRAME_DERIVED;  //创建框架结构对象
    if (pFrame == NULL) 
    {
        return E_OUTOFMEMORY;
    }
    
    //为框架指定名称
    hr = AllocateName(Name, (LPSTR*)&pFrame->Name);
    if (FAILED(hr))
    {
        delete pFrame;
        return hr;
    }
    
    //初始化D3DXFRAME_DERIVED结构其它成员变量
    D3DXMatrixIdentity(&pFrame->TransformationMatrix);
    D3DXMatrixIdentity(&pFrame->CombinedTransformationMatrix);
    
    pFrame->pMeshContainer = NULL;
    pFrame->pFrameSibling = NULL;
    pFrame->pFrameFirstChild = NULL;
    
    *ppNewFrame = pFrame;
    pFrame = NULL;
    return hr;
}
//-----------------------------------------------------------------------------
// Desc: 在这里是调用了成员函数 GenerateSkinnedMesh(pMeshContainer);
//       是在这里加载了蒙皮信息
//-----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::CreateMeshContainer( LPCSTR Name, 
                                                 CONST D3DXMESHDATA *pMeshData,
                                                 CONST D3DXMATERIAL *pMaterials, 
                                                 CONST D3DXEFFECTINSTANCE *pEffectInstances, 
                                                 DWORD NumMaterials, 
                                                 CONST DWORD *pAdjacency, 
                                                 LPD3DXSKININFO pSkinInfo, 
                                                 LPD3DXMESHCONTAINER *ppNewMeshContainer) 
{
    HRESULT hr;
    D3DXMESHCONTAINER_DERIVED *pMeshContainer = NULL;
    UINT NumFaces;       //网格中的面数,在填充网格容器结构的邻接信息成员时使用
    UINT iMaterial;      //纹理操作时的循环变量
    UINT cBones;         //当前网格模型骨骼总数
    LPDIRECT3DDEVICE9 pd3dDevice = NULL;
    LPD3DXMESH pMesh    = NULL;
    *ppNewMeshContainer = NULL;
    if (pMeshData->Type != D3DXMESHTYPE_MESH)
    {
        return E_FAIL;
    }
    pMesh = pMeshData->pMesh;
    
    if (pMesh->GetFVF() == 0)
    {
        return E_FAIL;
    }
    //为网格容器分配内存
    pMeshContainer = new D3DXMESHCONTAINER_DERIVED;
    if (pMeshContainer == NULL)
    {
        return E_OUTOFMEMORY;
    }
    memset(pMeshContainer, 0, sizeof(D3DXMESHCONTAINER_DERIVED));
    //填充网格容器结构D3DXMESHCONTAINER_DERIVED的成员
    //为网格指定名称
    hr = AllocateName(Name, &pMeshContainer->Name);
    if (FAILED(hr))
    {
        DestroyMeshContainer(pMeshContainer);
        return hr;
    }      
    
    pMesh->GetDevice(&pd3dDevice);
    NumFaces = pMesh->GetNumFaces();
    //确保网格顶点包含法线
    if (!(pMesh->GetFVF() & D3DFVF_NORMAL))
    {
        pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;
        hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), 
                                  pMesh->GetFVF() | D3DFVF_NORMAL, 
                                  pd3dDevice, 
                                  &pMeshContainer->MeshData.pMesh );
        if (FAILED(hr))
        {
            SAFE_RELEASE(pd3dDevice);
            DestroyMeshContainer(pMeshContainer);
            return hr;
        }
        pMesh = pMeshContainer->MeshData.pMesh;
        D3DXComputeNormals( pMesh, NULL );
    }
    else 
    {
        pMeshContainer->MeshData.pMesh = pMesh;
        pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;
        pMesh->AddRef();
    }
    //为网格模型准备材质和纹理
    pMeshContainer->NumMaterials = max(1, NumMaterials); 
    pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials];
    pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials];
    pMeshContainer->pAdjacency = new DWORD[NumFaces*3];
    if ((pMeshContainer->pAdjacency == NULL) || (pMeshContainer->pMaterials == NULL)
        || (pMeshContainer->ppTextures == NULL))
    {
        hr = E_OUTOFMEMORY;
        SAFE_RELEASE(pd3dDevice);
        DestroyMeshContainer(pMeshContainer);
        return hr;
    }
    memcpy(pMeshContainer->pAdjacency, pAdjacency, sizeof(DWORD) * NumFaces*3);
    memset(pMeshContainer->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) * pMeshContainer->NumMaterials);
    if (NumMaterials > 0)            
    {
        //复制材质属性, 设置材质环境光属性
        memcpy(pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL) * NumMaterials); 
        pMeshContainer->pMaterials->MatD3D.Ambient = pMeshContainer->pMaterials->MatD3D.Diffuse;
        for (iMaterial = 0; iMaterial < NumMaterials; iMaterial++)
        {
            if (pMeshContainer->pMaterials[iMaterial].pTextureFilename != NULL)
            {
                WCHAR strTexturePath[MAX_PATH];
                WCHAR wszBuf[MAX_PATH];
                //从纹理文件路径提取纹理文件名
                RemovePathFromFileName(pMeshContainer->pMaterials[iMaterial].pTextureFilename, wszBuf);
                //根据纹理文件名从事先指定的路径查找纹理文件
                DXUTFindDXSDKMediaFileCch( strTexturePath, MAX_PATH, wszBuf );
                if( FAILED( D3DXCreateTextureFromFile( pd3dDevice, strTexturePath,
                                                        &pMeshContainer->ppTextures[iMaterial] ) ) )
                    pMeshContainer->ppTextures[iMaterial] = NULL;
                pMeshContainer->pMaterials[iMaterial].pTextureFilename = NULL;
            }
        }
    }
    else 
    {
        pMeshContainer->pMaterials[0].pTextureFilename = NULL;
        memset(&pMeshContainer->pMaterials[0].MatD3D, 0, sizeof(D3DMATERIAL9));
        pMeshContainer->pMaterials[0].MatD3D.Diffuse.r = 0.5f;
        pMeshContainer->pMaterials[0].MatD3D.Diffuse.g = 0.5f;
        pMeshContainer->pMaterials[0].MatD3D.Diffuse.b = 0.5f;
        pMeshContainer->pMaterials[0].MatD3D.Specular = pMeshContainer->pMaterials[0].MatD3D.Diffuse;
    }
     //如果当前网格包含蒙皮信息
    if (pSkinInfo != NULL)
    {
        //加载蒙皮网格信息
        pMeshContainer->pSkinInfo = pSkinInfo; 
        pSkinInfo->AddRef();
        //保留原网格信息
        pMeshContainer->pOrigMesh = pMesh;
        pMesh->AddRef();
        //获取骨骼数量
        cBones = pSkinInfo->GetNumBones();
        //为每块骨骼分配保存初始变换矩阵的内存空间
        pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[cBones];
        if (pMeshContainer->pBoneOffsetMatrices == NULL) 
        {
            hr = E_OUTOFMEMORY;
            DestroyMeshContainer(pMeshContainer);
            return hr;
        }
        //保存每块骨骼的初始变换矩阵
        for (UINT iBone = 0; iBone < cBones; iBone++)
        {
            pMeshContainer->pBoneOffsetMatrices[iBone] = *(pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(iBone));
        }
        //生成蒙皮网格模型
        hr = GenerateSkinnedMesh(pd3dDevice, pMeshContainer); 
        if (FAILED(hr))
        {
            DestroyMeshContainer(pMeshContainer);
            return hr;
        }
    }
    *ppNewMeshContainer = pMeshContainer;
    pMeshContainer = NULL;
    SAFE_RELEASE(pd3dDevice);
    return hr;
}
//-----------------------------------------------------------------------------
//Desc: 生成蒙皮网格模型(含有每个顶点的混合权重、索引和一个骨骼组合表)
//-----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::GenerateSkinnedMesh( IDirect3DDevice9 *pd3dDevice, 
                                                D3DXMESHCONTAINER_DERIVED *pMeshContainer )
{
    HRESULT hr = S_OK;
    if( pMeshContainer->pSkinInfo == NULL )
        return hr;
    SAFE_RELEASE( pMeshContainer->MeshData.pMesh );
    SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );
    //获取当前设备的能力
    D3DCAPS9 d3dCaps;
    pd3dDevice->GetDeviceCaps( &d3dCaps );
    pMeshContainer->NumPaletteEntries = min(26, pMeshContainer->pSkinInfo->GetNumBones());
    DWORD Flags = D3DXMESHOPT_VERTEXCACHE;
    if (d3dCaps.VertexShaderVersion >= D3DVS_VERSION(1, 1))
    {
        pMeshContainer->UseSoftwareVP = false;
        Flags |= D3DXMESH_MANAGED;
    }
    else
    {
        pMeshContainer->UseSoftwareVP = true;
        Flags |= D3DXMESH_SYSTEMMEM;
    }
    SAFE_RELEASE(pMeshContainer->MeshData.pMesh);
    hr = pMeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh 
                                                              ( pMeshContainer->pOrigMesh,
                                                                Flags, 
                                                                pMeshContainer->NumPaletteEntries, 
                                                                pMeshContainer->pAdjacency, 
                                                                NULL, NULL, NULL,             
                                                                &pMeshContainer->NumInfl,
                                                                &pMeshContainer->NumAttributeGroups, 
                                                                &pMeshContainer->pBoneCombinationBuf, 
                                                                &pMeshContainer->MeshData.pMesh);
    if (FAILED(hr))
        return hr;
    // FVF has to match our declarator. Vertex shaders are not as forgiving as FF pipeline
    DWORD NewFVF = (pMeshContainer->MeshData.pMesh->GetFVF() & D3DFVF_POSITION_MASK) | D3DFVF_NORMAL | D3DFVF_TEX1 | D3DFVF_LASTBETA_UBYTE4;
    if (NewFVF != pMeshContainer->MeshData.pMesh->GetFVF())
    {
        LPD3DXMESH pMesh;
        hr = pMeshContainer->MeshData.pMesh->CloneMeshFVF(pMeshContainer->MeshData.pMesh->GetOptions(), NewFVF, pd3dDevice, &pMesh);
        if (!FAILED(hr))
        {
            pMeshContainer->MeshData.pMesh->Release();
            pMeshContainer->MeshData.pMesh = pMesh;
            pMesh = NULL;
        }
    }
    D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE];
    LPD3DVERTEXELEMENT9 pDeclCur;
    hr = pMeshContainer->MeshData.pMesh->GetDeclaration(pDecl);
    if (FAILED(hr))
        return hr;
    pDeclCur = pDecl;
    while (pDeclCur->Stream != 0xff)
    {
        if ((pDeclCur->Usage == D3DDECLUSAGE_BLENDINDICES) && (pDeclCur->UsageIndex == 0))
            pDeclCur->Type = D3DDECLTYPE_D3DCOLOR;
        pDeclCur++;
    }
    hr = pMeshContainer->MeshData.pMesh->UpdateSemantics(pDecl);
    if (FAILED(hr))
        return hr;
    // allocate a buffer for bone matrices,
    if( g_NumBoneMatricesMax < pMeshContainer->pSkinInfo->GetNumBones() )
    {
        g_NumBoneMatricesMax = pMeshContainer->pSkinInfo->GetNumBones();
        // Allocate space for blend matrices
        delete[] g_pBoneMatrices; 
        g_pBoneMatrices  = new D3DXMATRIXA16[g_NumBoneMatricesMax];
        if( g_pBoneMatrices == NULL )
        {
            hr = E_OUTOFMEMORY;
            return hr;
        }
    }
    return hr;
}
//-----------------------------------------------------------------------------
// Desc: 释放框架
//-----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::DestroyFrame(LPD3DXFRAME pFrameToFree) 
{
    if(pFrameToFree != NULL)
    {
        SAFE_DELETE_ARRAY( pFrameToFree->Name );
        SAFE_DELETE( pFrameToFree );
    }
    return S_OK; 
}
//-----------------------------------------------------------------------------
// Desc: 释放网格容器
//-----------------------------------------------------------------------------
HRESULT CAllocateHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase)
{
    if(pMeshContainerBase == NULL)
        return S_OK;
    UINT iMaterial;
    // 先转为扩展型以免内存泄漏
    D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;
    
    SAFE_DELETE_ARRAY( pMeshContainer->Name );
    SAFE_DELETE_ARRAY( pMeshContainer->pAdjacency );
    SAFE_DELETE_ARRAY( pMeshContainer->pMaterials );
    SAFE_DELETE_ARRAY( pMeshContainer->pBoneOffsetMatrices );
    
    if (pMeshContainer->ppTextures != NULL)
    {
        for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++)
        {
            SAFE_RELEASE( pMeshContainer->ppTextures[iMaterial] );
        }
    }
    SAFE_DELETE_ARRAY( pMeshContainer->ppTextures );
    SAFE_DELETE_ARRAY( pMeshContainer->ppBoneMatrixPtrs );
    SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );
    SAFE_RELEASE( pMeshContainer->MeshData.pMesh );
    SAFE_RELEASE( pMeshContainer->pSkinInfo );
    SAFE_RELEASE( pMeshContainer->pOrigMesh );
    SAFE_DELETE( pMeshContainer );
    return S_OK;
}
//-----------------------------------------------------------------------------
// Desc: 入口函数
//-----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
    //为Debug配置启用运行时内存检查功能
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
    //设置回调函数
    DXUTSetCallbackDeviceCreated( OnCreateDevice );
    DXUTSetCallbackDeviceReset( OnResetDevice );
    DXUTSetCallbackDeviceLost( OnLostDevice );
    DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
    DXUTSetCallbackMsgProc( MsgProc );
    DXUTSetCallbackKeyboard( KeyboardProc );
    DXUTSetCallbackFrameRender( OnFrameRender );
    DXUTSetCallbackFrameMove( OnFrameMove );
    //应用程序相关的初始化
    InitApp();
    //初始化DXUT, 创建窗口, 创建Direct3D设备对象
    DXUTInit( true, true, true );
    DXUTSetCursorSettings( true, true );
    DXUTCreateWindow( L"HLSLSkinMesh" );
    DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, 
        IsDeviceAcceptable, ModifyDeviceSettings );
    //进入消息循环和场景渲染
    DXUTMainLoop();
    //在此进行应用程序相关的清除工作
    delete[] g_pBoneMatrices;
    return DXUTGetExitCode();
}
//-----------------------------------------------------------------------------
// Desc: 应用程序相关初始化
//-----------------------------------------------------------------------------
void InitApp()
{
    //初始化对话框
    g_SettingsDlg.Init( &g_DialogResourceManager );
    g_HUD.Init( &g_DialogResourceManager );
    g_SampleUI.Init( &g_DialogResourceManager );
    //为g_HUD对话框设置消息处理函数,添加控件
    g_HUD.SetCallback( OnGUIEvent ); int iY = 10; 
    g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
    g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22 );
    g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22, VK_F2 );
}
//-----------------------------------------------------------------------------
// Desc: 设备能力检查
//-----------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, 
                                  D3DFORMAT BackBufferFormat, bool bWindowed, 
                                  void* pUserContext )
{
    //检查后台缓冲区格式是否支持Alpha混合等操作(post pixel blending operations)
    IDirect3D9* pD3D = DXUTGetD3DObject(); 
    if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
                    AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, 
                    D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
        return false;
    //检查当前设备支持顶点渲染器版本是否符合要求
    if( pCaps->VertexShaderVersion < D3DVS_VERSION(1,1) )
        return FALSE;
    return true;
}
//-----------------------------------------------------------------------------
// Desc: 修改Direct3D渲染设备设置
//-----------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, 
                                    const D3DCAPS9* pCaps, void* pUserContext )
{
    //如果不支持硬件顶点处理则使用软件顶点处理
    if( (pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0)
    {
        pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
    }
    //如果使用纯硬件顶点处理模式则改为混合顶点处理模式
    if( pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING )
        pDeviceSettings->BehaviorFlags = D3DCREATE_MIXED_VERTEXPROCESSING;
    
    //调试顶点渲染器需要参考设备或软件顶点处理
#ifdef DEBUG_VS
    if( pDeviceSettings->DeviceType != D3DDEVTYPE_REF )
    {
        pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
        pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;
        pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
    }
#endif
    //调试像素渲染器需要参考设备
#ifdef DEBUG_PS
    pDeviceSettings->DeviceType = D3DDEVTYPE_REF;
#endif
    //如果使用参考设备,则弹出警告对话框
    static bool s_bFirstTime = true;
    if( s_bFirstTime )
    {
        s_bFirstTime = false;
        if( pDeviceSettings->DeviceType == D3DDEVTYPE_REF )
            DXUTDisplaySwitchingToREFWarning();
    }
    return true;
}
//-----------------------------------------------------------------------------
// Desc: 在此创建管理内存资源对象
//-----------------------------------------------------------------------------
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, 
                                const D3DSURFACE_DESC* pBackBufferSurfaceDesc, 
                                void* pUserContext )
{
    HRESULT hr;
    V_RETURN( g_DialogResourceManager.OnCreateDevice( pd3dDevice ) );
    V_RETURN( g_SettingsDlg.OnCreateDevice( pd3dDevice ) );
    
    //创建字体
    V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, 
                         OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, 
                         L"Arial", &g_pFont ) );
    //创建效果
    DWORD dwShaderFlags = D3DXFX_NOT_CLONEABLE;
    #ifdef DEBUG_VS
        dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
    #endif
    #ifdef DEBUG_PS
        dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
    #endif
    V_RETURN(D3DXCreateEffectFromFile( pd3dDevice, L"HLSLSkinMesh.fx", NULL, NULL, 
                                       dwShaderFlags, NULL, &g_pEffect, NULL ));
    //创建网格模型
    CAllocateHierarchy Alloc;
    V_RETURN(D3DXLoadMeshHierarchyFromX( L"tiny.x", D3DXMESH_MANAGED, pd3dDevice,
                                         &Alloc, NULL, &g_pFrameRoot, &g_pAnimController ));
    
    SetupBoneMatrixPointers( g_pFrameRoot );
    return S_OK;
}
//-----------------------------------------------------------------------------
// Desc: 在此创建默认内存类型资源对象
//-----------------------------------------------------------------------------
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, 
                                const D3DSURFACE_DESC* pBackBufferSurfaceDesc, 
                                void* pUserContext )
{
    HRESULT hr;
    V_RETURN( g_DialogResourceManager.OnResetDevice() );
    V_RETURN( g_SettingsDlg.OnResetDevice() );
    //设置对话框位置和尺寸
    g_HUD.SetLocation( pBackBufferSurfaceDesc->Width-170, 0 );
    g_HUD.SetSize( 170, 170 );
    g_SampleUI.SetLocation( pBackBufferSurfaceDesc->Width-170, 
                            pBackBufferSurfaceDesc->Height-350 );
    g_SampleUI.SetSize( 170, 300 );
    //恢复字体
    if( g_pFont )
        V_RETURN( g_pFont->OnResetDevice() );
   
    //创建ID3DXSprite接口对象
    V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pTextSprite ) );
    //恢复效果对象
    if( g_pEffect )
        V_RETURN( g_pEffect->OnResetDevice() );
    //构造世界矩阵
    D3DXMatrixTranslation( &g_matWorld, 0, 30, -100 );
    //构造观察矩阵
    D3DXVECTOR3 vEye( 0, 0, -1000 );
    D3DXVECTOR3 vAt( 0, 0, 0 );
    D3DXVECTOR3 vUp( 0, 1, 0 );
    D3DXMatrixLookAtLH( &g_matView, &vEye, &vAt, &vUp);
    //构造投影矩阵
    D3DXMATRIXA16 matProj;
    float fAspectRatio = (float)pBackBufferSurfaceDesc->Width / pBackBufferSurfaceDesc->Height;
    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspectRatio, 1.0f, 2000.0f );;
    //为效果设置影矩阵
    V( g_pEffect->SetMatrix( "mProj", &matProj ) );
    //为效果设置灯光方向
    D3DXVECTOR4 vLightDir( 0.0f, 1.0f, -1.0f, 0.0f );
    D3DXVec4Normalize( &vLightDir, &vLightDir );
    V( g_pEffect->SetVector( "lightDir", &vLightDir) );
    return S_OK;
}
//-----------------------------------------------------------------------------
// Desc: 更新场景
//-----------------------------------------------------------------------------
void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, 
                           float fElapsedTime, void* pUserContext )
{
}
//------------------------------------------------------------------------------
// Desc: 渲染网格模型
//------------------------------------------------------------------------------
void DrawMeshContainer( IDirect3DDevice9 *pd3dDevice, 
                       LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameBase )
{
    HRESULT hr;
    D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;
    D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;
    UINT iMaterial;
    UINT iAttrib;
    LPD3DXBONECOMBINATION pBoneComb;
    UINT iMatrixIndex;
    UINT iPaletteEntry;
    D3DXMATRIXA16 matTemp;
    D3DCAPS9 d3dCaps;
    pd3dDevice->GetDeviceCaps( &d3dCaps );
    //检查是否是蒙皮网格模型
    if (pMeshContainer->pSkinInfo != NULL)
    {
            if (pMeshContainer->UseSoftwareVP)
            {
                V( pd3dDevice->SetSoftwareVertexProcessing(TRUE) );
            }
            pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>(pMeshContainer->pBoneCombinationBuf->GetBufferPointer());
            for (iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++)
            { 
                for (iPaletteEntry = 0; iPaletteEntry < pMeshContainer->NumPaletteEntries; ++iPaletteEntry)
                {
                    iMatrixIndex = pBoneComb[iAttrib].BoneId[iPaletteEntry];
                    if (iMatrixIndex != UINT_MAX)
                    {
                        D3DXMatrixMultiply(&matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex]);
                        D3DXMatrixMultiply(&g_pBoneMatrices[iPaletteEntry], &matTemp, &g_matView);
                    }
                }
                V( g_pEffect->SetMatrixArray( "mWorldMatrixArray", g_pBoneMatrices, pMeshContainer->NumPaletteEntries) );
                D3DXCOLOR color1(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Ambient);
                D3DXCOLOR color2(0.25, 0.25, 0.25, 1.0);
                D3DXCOLOR ambEmm;
                D3DXColorModulate(&ambEmm, &color1, &color2);
                ambEmm += D3DXCOLOR(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Emissive);
                //设置材质属性
                V( g_pEffect->SetVector("MaterialDiffuse", (D3DXVECTOR4*)&(pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D.Diffuse)) );
                V( g_pEffect->SetVector("MaterialAmbient", (D3DXVECTOR4*)&ambEmm) );
                ///设置纹理
                V( pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );
                //设置当前骨骼数量
                V( g_pEffect->SetInt( "CurNumBones", pMeshContainer->NumInfl -1) );
                //使用效果渲染网格
                UINT numPasses;
                V( g_pEffect->Begin( &numPasses, D3DXFX_DONOTSAVESTATE ) );
                for( UINT iPass = 0; iPass < numPasses; iPass++ )
                {
                    V( g_pEffect->BeginPass( iPass ) );
                    V( pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib ) );
                    V( g_pEffect->EndPass() );
                }
                V( g_pEffect->End() );
                V( pd3dDevice->SetVertexShader(NULL) );
            }
            if (pMeshContainer->UseSoftwareVP)
            {
                V( pd3dDevice->SetSoftwareVertexProcessing(FALSE) );
            }
       
    }
    else
    {
        V( pd3dDevice->SetTransform(D3DTS_WORLD, &pFrame->CombinedTransformationMatrix) );
        for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++)
        {
            V( pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[iMaterial].MatD3D ) );
            V( pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[iMaterial] ) );
            V( pMeshContainer->MeshData.pMesh->DrawSubset(iMaterial) );
        }
    }
}
//--------------------------------------------------------------------------------------
// 渲染框架
//--------------------------------------------------------------------------------------
void DrawFrame( IDirect3DDevice9 *pd3dDevice, LPD3DXFRAME pFrame )
{
    LPD3DXMESHCONTAINER pMeshContainer;
    pMeshContainer = pFrame->pMeshContainer;
    while (pMeshContainer != NULL)
    {
        DrawMeshContainer( pd3dDevice, pMeshContainer, pFrame );
        pMeshContainer = pMeshContainer->pNextMeshContainer;
    }
    if (pFrame->pFrameSibling != NULL)
    {
        DrawFrame( pd3dDevice, pFrame->pFrameSibling);
    }
    if (pFrame->pFrameFirstChild != NULL)
    {
        DrawFrame( pd3dDevice, pFrame->pFrameFirstChild );
    }
}
//-----------------------------------------------------------------------------
// Desc: 渲染场景
//-----------------------------------------------------------------------------
void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, 
                            float fElapsedTime, void* pUserContext )
{
    HRESULT hr;
  
    //如果正在利用Direct3D设备设置对话框进行设置, 则不渲染场景
    if( g_SettingsDlg.IsActive() )
    {
        g_SettingsDlg.OnRender( fElapsedTime );
        return;
    }
    //清除后台颜色缓冲区和深度缓冲区
    V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 
                         D3DCOLOR_ARGB(0, 45, 50, 170), 1.0f, 0) );
    //渲染场景
    if( SUCCEEDED( pd3dDevice->BeginScene() ) )
    {
        //渲染网格模型
        if( g_pAnimController != NULL )
            g_pAnimController->AdvanceTime( fElapsedTime, NULL );
        UpdateFrameMatrices( g_pFrameRoot, &g_matWorld );
        DrawFrame( pd3dDevice, g_pFrameRoot );
        //渲染文本和控件
        DXUT_BeginPerfEvent( DXUT_PERFEVENTCOLOR, L"HUD / Stats" ); 
        RenderText();
        V( g_HUD.OnRender( fElapsedTime ) );
        V( g_SampleUI.OnRender( fElapsedTime ) );
        DXUT_EndPerfEvent();
        V( pd3dDevice->EndScene() );
    }
}
//-----------------------------------------------------------------------------
// Desc: 渲染文本
//-----------------------------------------------------------------------------
void RenderText()
{
    CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 );
    //显示当前Direct3D设备状态和渲染帧速率
    txtHelper.Begin();
    txtHelper.SetInsertionPos( 5, 5 );
    txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
    txtHelper.DrawTextLine( DXUTGetFrameStats(true) );
    txtHelper.DrawTextLine( DXUTGetDeviceStats() );
    //显示其他简要信息
    txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
    txtHelper.DrawTextLine( L"通过HLSL编程实现蒙皮骨骼动画" );
    
    //显示简单帮助文本
    const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
    if( g_bShowHelp )
    {
        txtHelper.SetInsertionPos( 10, pd3dsdBackBuffer->Height-15*6 );
        txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.75f, 0.0f, 1.0f ) );
        txtHelper.DrawTextLine( L"Controls (F1 to hide):" );
        txtHelper.SetInsertionPos( 40, pd3dsdBackBuffer->Height-15*5 );
        txtHelper.DrawTextLine( L"Quit: ESC" );
    }
    else
    {
        txtHelper.SetInsertionPos( 10, pd3dsdBackBuffer->Height-15*2 );
        txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
        txtHelper.DrawTextLine( L"Press F1 for help" );
    }
    txtHelper.End();
}
//-----------------------------------------------------------------------------
// Desc: 消息处理
//-----------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 
                         bool* pbNoFurtherProcessing, void* pUserContext )
{
    *pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
    if( *pbNoFurtherProcessing )
        return 0;
    if( g_SettingsDlg.IsActive() )
    {
        g_SettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam );
        return 0;
    }
    *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
    if( *pbNoFurtherProcessing )
        return 0;
   
    *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
    if( *pbNoFurtherProcessing )
        return 0;
    return 0;
}
//-----------------------------------------------------------------------------
// Desc: 键盘消息处理
//-----------------------------------------------------------------------------
void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext )
{
    if( bKeyDown )
    {
        switch( nChar )
        {
            case VK_F1: g_bShowHelp = !g_bShowHelp; break;
        }
    }
}
//-----------------------------------------------------------------------------
// Desc: 处理各种控件消息
//-----------------------------------------------------------------------------
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, 
                         void* pUserContext )
{
    switch( nControlID )
    {
        case IDC_TOGGLEFULLSCREEN:
            DXUTToggleFullScreen(); 
            break;
        case IDC_TOGGLEREF:
            DXUTToggleREF(); 
            break;
        case IDC_CHANGEDEVICE:
            g_SettingsDlg.SetActive( !g_SettingsDlg.IsActive() ); 
            break;
    }
}
//-----------------------------------------------------------------------------
// Desc: 释放在OnResetDevice()中创建的资源
//-----------------------------------------------------------------------------
void CALLBACK OnLostDevice( void* pUserContext )
{
    g_DialogResourceManager.OnLostDevice();
    g_SettingsDlg.OnLostDevice();
    if( g_pFont )
        g_pFont->OnLostDevice();
    SAFE_RELEASE( g_pTextSprite );
    if( g_pEffect )
        g_pEffect->OnLostDevice();
}
//------------------------------------------------------------------------------
// Desc: 释放在OnCreateDevice()中创建的资源
//------------------------------------------------------------------------------
void CALLBACK OnDestroyDevice( void* pUserContext )
{
    g_DialogResourceManager.OnDestroyDevice();
    g_SettingsDlg.OnDestroyDevice();
    SAFE_RELEASE( g_pFont );
    SAFE_RELEASE( g_pEffect );
    CAllocateHierarchy Alloc;
    D3DXFrameDestroy( g_pFrameRoot, &Alloc );
    SAFE_RELEASE( g_pAnimController );
}
//--------------------------------------------------------------------------------------
// Desc: 设置骨骼矩阵
//--------------------------------------------------------------------------------------
HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainerBase )
{
    UINT iBone, cBones;
    D3DXFRAME_DERIVED *pFrame;
    D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase;
    //设置骨骼矩阵
    if (pMeshContainer->pSkinInfo != NULL)
    {
        cBones = pMeshContainer->pSkinInfo->GetNumBones();
        pMeshContainer->ppBoneMatrixPtrs = new D3DXMATRIX*[cBones];
        if (pMeshContainer->ppBoneMatrixPtrs == NULL)
            return E_OUTOFMEMORY;
        for (iBone = 0; iBone < cBones; iBone++)
        {
            pFrame = (D3DXFRAME_DERIVED*)D3DXFrameFind( g_pFrameRoot, 
                                             pMeshContainer->pSkinInfo->GetBoneName(iBone) );
            if (pFrame == NULL)
                return E_FAIL;
            pMeshContainer->ppBoneMatrixPtrs[iBone] = &pFrame->CombinedTransformationMatrix;
        }
    }
    return S_OK;
}
//--------------------------------------------------------------------------------------
// Desc: 设置骨骼矩阵指针
//--------------------------------------------------------------------------------------
HRESULT SetupBoneMatrixPointers( LPD3DXFRAME pFrame )
{
    HRESULT hr;
    if (pFrame->pMeshContainer != NULL)
    {
        hr = SetupBoneMatrixPointersOnMesh(pFrame->pMeshContainer);
        if (FAILED(hr))
            return hr;
    }
    if (pFrame->pFrameSibling != NULL)
    {
        hr = SetupBoneMatrixPointers(pFrame->pFrameSibling);
        if (FAILED(hr))
            return hr;
    }
    if (pFrame->pFrameFirstChild != NULL)
    {
        hr = SetupBoneMatrixPointers(pFrame->pFrameFirstChild);
        if (FAILED(hr))
            return hr;
    }
    return S_OK;
}
//--------------------------------------------------------------------------------------
// update the frame matrices
//--------------------------------------------------------------------------------------
void UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix )
{
    D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase;
    if (pParentMatrix != NULL)
        D3DXMatrixMultiply(&pFrame->CombinedTransformationMatrix, &pFrame->TransformationMatrix, pParentMatrix);
    else
        pFrame->CombinedTransformationMatrix = pFrame->TransformationMatrix;
    if (pFrame->pFrameSibling != NULL)
    {
        UpdateFrameMatrices(pFrame->pFrameSibling, pParentMatrix);
    }
    if (pFrame->pFrameFirstChild != NULL)
    {
        UpdateFrameMatrices(pFrame->pFrameFirstChild, &pFrame->CombinedTransformationMatrix);
    }
}
	posted on 2008-04-16 11:01 
七星重剑 阅读(1321) 
评论(0)  编辑 收藏 引用  所属分类: 
Game Graphics