X文件的动画类及基本使用方法
------------------------------Animation.h--------------------------------------没有Animation.cpp-----------
#ifndef __AnimationH__
#define __AnimationH__
#include <d3d9.h>
#include <d3dx9.h>
//struct D3DXFRAME_DERIVED & D3DXMESHCONTAINER_DERIVED
struct D3DXFRAME_DERIVED : public D3DXFRAME
{
D3DXMATRIXA16 CombinedTransformationMatrix;
};
struct D3DXMESHCONTAINER_DERIVED : public D3DXMESHCONTAINER
{
LPDIRECT3DTEXTURE9* ppTextures; // array of textures, entries are NULL if no texture specified
// SkinMesh info
LPD3DXMESH pOrigMesh;
LPD3DXATTRIBUTERANGE pAttributeTable;
DWORD NumAttributeGroups;
DWORD NumInfl;
LPD3DXBUFFER pBoneCombinationBuf;
D3DXMATRIX** ppBoneMatrixPtrs;
D3DXMATRIX* pBoneOffsetMatrices;
DWORD NumPaletteEntries;
bool UseSoftwareVP;
DWORD iAttributeSW; // used to denote the split between SW and HW if necessary for non-indexed skinning
};
//class CAllocateHierarchy
class CAllocateHierarchy : public ID3DXAllocateHierarchy
{
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 );
HRESULT AllocateName( LPCSTR Name, LPSTR* pNewName );
HRESULT GenerateSkinnedMesh( IDirect3DDevice9* pd3dDevice, D3DXMESHCONTAINER_DERIVED* pMeshContainer );
CAllocateHierarchy()
{
}
};
HRESULT CAllocateHierarchy::CreateFrame( LPCSTR Name, LPD3DXFRAME* ppNewFrame )
{
HRESULT hr = S_OK;
D3DXFRAME_DERIVED* pFrame;
*ppNewFrame = NULL;
pFrame = new D3DXFRAME_DERIVED;
if( pFrame == NULL )
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
hr = AllocateName( Name, &pFrame->Name );
if( FAILED( hr ) )
goto e_Exit;
// initialize other data members of the frame
D3DXMatrixIdentity( &pFrame->TransformationMatrix );
D3DXMatrixIdentity( &pFrame->CombinedTransformationMatrix );
pFrame->pMeshContainer = NULL;
pFrame->pFrameSibling = NULL;
pFrame->pFrameFirstChild = NULL;
*ppNewFrame = pFrame;
pFrame = NULL;
e_Exit:
delete pFrame;
return hr;
}
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 iBone, cBones;
LPDIRECT3DDEVICE9 pd3dDevice = NULL;
LPD3DXMESH pMesh = NULL;
*ppNewMeshContainer = NULL;
// this sample does not handle patch meshes, so fail when one is found
if( pMeshData->Type != D3DXMESHTYPE_MESH )
{
hr = E_FAIL;
goto e_Exit;
}
// get the pMesh interface pointer out of the mesh data structure
pMesh = pMeshData->pMesh;
// this sample does not FVF compatible meshes, so fail when one is found
if( pMesh->GetFVF() == 0 )
{
hr = E_FAIL;
goto e_Exit;
}
// allocate the overloaded structure to return as a D3DXMESHCONTAINER
pMeshContainer = new D3DXMESHCONTAINER_DERIVED;
if( pMeshContainer == NULL )
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
memset( pMeshContainer, 0, sizeof( D3DXMESHCONTAINER_DERIVED ) );
// make sure and copy the name. All memory as input belongs to caller, interfaces can be addref'd though
hr = AllocateName( Name, &pMeshContainer->Name );
if( FAILED( hr ) )
goto e_Exit;
pMesh->GetDevice( &pd3dDevice );
NumFaces = pMesh->GetNumFaces();
// if no normals are in the mesh, add them
if( !( pMesh->GetFVF() & D3DFVF_NORMAL ) )
{
pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;
// clone the mesh to make room for the normals
hr = pMesh->CloneMeshFVF( pMesh->GetOptions(),
pMesh->GetFVF() | D3DFVF_NORMAL,
pd3dDevice, &pMeshContainer->MeshData.pMesh );
if( FAILED( hr ) )
goto e_Exit;
// get the new pMesh pointer back out of the mesh container to use
// NOTE: we do not release pMesh because we do not have a reference to it yet
pMesh = pMeshContainer->MeshData.pMesh;
// now generate the normals for the pmesh
D3DXComputeNormals( pMesh, NULL );
}
else // if no normals, just add a reference to the mesh for the mesh container
{
pMeshContainer->MeshData.pMesh = pMesh;
pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH;
pMesh->AddRef();
}
// allocate memory to contain the material information. This sample uses
// the D3D9 materials and texture names instead of the EffectInstance style materials
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 ) )
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
memcpy( pMeshContainer->pAdjacency, pAdjacency, sizeof( DWORD ) * NumFaces*3 );
memset( pMeshContainer->ppTextures, 0, sizeof( LPDIRECT3DTEXTURE9 ) * pMeshContainer->NumMaterials );
// if materials provided, copy them
if( NumMaterials > 0 )
{
memcpy( pMeshContainer->pMaterials, pMaterials, sizeof( D3DXMATERIAL ) * NumMaterials );
for( iMaterial = 0; iMaterial < NumMaterials; iMaterial++ )
{
if( pMeshContainer->pMaterials[iMaterial].pTextureFilename != NULL )
{
WCHAR strTexturePath[MAX_PATH];
MultiByteToWideChar( CP_ACP, 0, pMeshContainer->pMaterials[iMaterial].pTextureFilename, -1, strTexturePath, MAX_PATH );
strTexturePath[MAX_PATH - 1] = L'\0';
if( FAILED( D3DXCreateTextureFromFile( pd3dDevice, strTexturePath,
&pMeshContainer->ppTextures[iMaterial] ) ) )
pMeshContainer->ppTextures[iMaterial] = NULL;
// don't remember a pointer into the dynamic memory, just forget the name after loading
pMeshContainer->pMaterials[iMaterial].pTextureFilename = NULL;
}
}
}
else // if no materials provided, use a default one
{
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 there is skinning information, save off the required data and then setup for HW skinning
if( pSkinInfo != NULL )
{
// first save off the SkinInfo and original mesh data
pMeshContainer->pSkinInfo = pSkinInfo;
pSkinInfo->AddRef();
pMeshContainer->pOrigMesh = pMesh;
pMesh->AddRef();
// Will need an array of offset matrices to move the vertices from the figure space to the bone's space
cBones = pSkinInfo->GetNumBones();
pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[cBones];
if( pMeshContainer->pBoneOffsetMatrices == NULL )
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
// get each of the bone offset matrices so that we don't need to get them later
for( iBone = 0; iBone < cBones; iBone++ )
{
pMeshContainer->pBoneOffsetMatrices[iBone] = *( pMeshContainer->pSkinInfo->GetBoneOffsetMatrix( iBone ) );
}
// GenerateSkinnedMesh will take the general skinning information and transform it to a HW friendly version
hr = GenerateSkinnedMesh( pd3dDevice, pMeshContainer );
if( FAILED( hr ) )
goto e_Exit;
}
*ppNewMeshContainer = pMeshContainer;
pMeshContainer = NULL;
e_Exit:
SAFE_RELEASE( pd3dDevice );
// call Destroy function to properly clean up the memory allocated
if( pMeshContainer != NULL )
{
DestroyMeshContainer( pMeshContainer );
}
return hr;
}
HRESULT CAllocateHierarchy::DestroyFrame( LPD3DXFRAME pFrameToFree )
{
SAFE_DELETE_ARRAY( pFrameToFree->Name );
SAFE_DELETE( pFrameToFree );
return S_OK;
}
HRESULT CAllocateHierarchy::DestroyMeshContainer( LPD3DXMESHCONTAINER pMeshContainerBase )
{
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 );
// release all the allocated textures
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;
}
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;
}
HRESULT CAllocateHierarchy::GenerateSkinnedMesh( IDirect3DDevice9* pd3dDevice, D3DXMESHCONTAINER_DERIVED* pMeshContainer )
{
HRESULT hr = S_OK;
D3DCAPS9 d3dCaps;
pd3dDevice->GetDeviceCaps( &d3dCaps );
if( pMeshContainer->pSkinInfo == NULL )
return hr;
SAFE_RELEASE( pMeshContainer->MeshData.pMesh );
SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf );
hr = pMeshContainer->pSkinInfo->ConvertToBlendedMesh
(
pMeshContainer->pOrigMesh,
D3DXMESH_MANAGED | D3DXMESHOPT_VERTEXCACHE,
pMeshContainer->pAdjacency,
NULL, NULL, NULL,
&pMeshContainer->NumInfl,
&pMeshContainer->NumAttributeGroups,
&pMeshContainer->pBoneCombinationBuf,
&pMeshContainer->MeshData.pMesh
);
if( FAILED( hr ) )
goto e_Exit;
// If the device can only do 2 matrix blends, ConvertToBlendedMesh cannot approximate all meshes to it
// Thus we split the mesh in two parts: The part that uses at most 2 matrices and the rest. The first is
// drawn using the device's HW vertex processing and the rest is drawn using SW vertex processing.
LPD3DXBONECOMBINATION rgBoneCombinations = reinterpret_cast<LPD3DXBONECOMBINATION>(
pMeshContainer->pBoneCombinationBuf->GetBufferPointer() );
// look for any set of bone combinations that do not fit the caps
for( pMeshContainer->iAttributeSW = 0; pMeshContainer->iAttributeSW < pMeshContainer->NumAttributeGroups;
pMeshContainer->iAttributeSW++ )
{
DWORD cInfl = 0;
for( DWORD iInfl = 0; iInfl < pMeshContainer->NumInfl; iInfl++ )
{
if( rgBoneCombinations[pMeshContainer->iAttributeSW].BoneId[iInfl] != UINT_MAX )
{
++cInfl;
}
}
if( cInfl > d3dCaps.MaxVertexBlendMatrices )
{
break;
}
}
// if there is both HW and SW, add the Software Processing flag
if( pMeshContainer->iAttributeSW < pMeshContainer->NumAttributeGroups )
{
LPD3DXMESH pMeshTmp;
hr = pMeshContainer->MeshData.pMesh->CloneMeshFVF( D3DXMESH_SOFTWAREPROCESSING |
pMeshContainer->MeshData.pMesh->GetOptions(),
pMeshContainer->MeshData.pMesh->GetFVF(),
pd3dDevice, &pMeshTmp );
if( FAILED( hr ) )
{
goto e_Exit;
}
pMeshContainer->MeshData.pMesh->Release();
pMeshContainer->MeshData.pMesh = pMeshTmp;
pMeshTmp = NULL;
}
e_Exit:
return hr;
}
//class CAnimation
class CAnimation
{
private:
IDirect3DDevice9* m_pDevice;
LPD3DXFRAME m_pFrameRoot;
ID3DXAnimationController* m_pAnimController;
D3DXVECTOR3 m_vObjectCenter;
FLOAT m_fObjectRadius;
private:
HRESULT SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainerBase );
HRESULT SetupBoneMatrixPointers(LPD3DXFRAME pFrame);
void UpdateFrameMatrices( LPD3DXFRAME pFrameBase, LPD3DXMATRIX pParentMatrix );
void DrawMeshContainer( IDirect3DDevice9* pd3dDevice, LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameBase );
void DrawFrame( IDirect3DDevice9* pd3dDevice, LPD3DXFRAME pFrame );
public:
friend class CAllocateHierarchy;
void Init(IDirect3DDevice9* pDevice, char* sFileName);
void Logic(float fElapsedTime);
void Render(float fElapsedTime);
};
void CAnimation::Init(IDirect3DDevice9* pDevice, char* sFileName)
{
m_pDevice = pDevice;
CAllocateHierarchy Alloc;
D3DXLoadMeshHierarchyFromXA( sFileName, D3DXMESH_MANAGED, m_pDevice,
&Alloc, NULL, &m_pFrameRoot, &m_pAnimController );
SetupBoneMatrixPointers( m_pFrameRoot );
D3DXFrameCalculateBoundingSphere( m_pFrameRoot, &m_vObjectCenter, &m_fObjectRadius );
}
void CAnimation::Logic(float fElapsedTime)
{
m_pAnimController->AdvanceTime(fElapsedTime, 0);
D3DXMATRIX matWorld;
D3DXMatrixScaling(&matWorld, 0.01f, 0.01f, 0.01f);
UpdateFrameMatrices(m_pFrameRoot, &matWorld);
}
void CAnimation::Render(float fElapsedTime)
{
DrawFrame(m_pDevice, m_pFrameRoot);
}
HRESULT CAnimation::SetupBoneMatrixPointersOnMesh( LPD3DXMESHCONTAINER pMeshContainerBase )
{
UINT iBone, cBones;
D3DXFRAME_DERIVED* pFrame;
D3DXMESHCONTAINER_DERIVED* pMeshContainer = ( D3DXMESHCONTAINER_DERIVED* )pMeshContainerBase;
// if there is a skinmesh, then setup the bone matrices
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( m_pFrameRoot,
pMeshContainer->pSkinInfo->GetBoneName( iBone ) );
if( pFrame == NULL )
return E_FAIL;
pMeshContainer->ppBoneMatrixPtrs[iBone] = &pFrame->CombinedTransformationMatrix;
}
}
return S_OK;
}
HRESULT CAnimation::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;
}
void CAnimation::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 );
}
}
void CAnimation::DrawMeshContainer( IDirect3DDevice9* pd3dDevice, LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameBase )
{
HRESULT hr;
D3DXMESHCONTAINER_DERIVED* pMeshContainer = ( D3DXMESHCONTAINER_DERIVED* )pMeshContainerBase;
D3DXFRAME_DERIVED* pFrame = ( D3DXFRAME_DERIVED* )pFrameBase;
UINT iMaterial;
UINT NumBlend;
UINT iAttrib;
DWORD AttribIdPrev;
LPD3DXBONECOMBINATION pBoneComb;
UINT iMatrixIndex;
D3DXMATRIXA16 matTemp;
D3DCAPS9 d3dCaps;
pd3dDevice->GetDeviceCaps( &d3dCaps );
// first check for skinning
if( pMeshContainer->pSkinInfo != NULL )
{
AttribIdPrev = UNUSED32;
pBoneComb = reinterpret_cast<LPD3DXBONECOMBINATION>( pMeshContainer->pBoneCombinationBuf->GetBufferPointer
() );
// Draw using default vtx processing of the device (typically HW)
for( iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++ )
{
NumBlend = 0;
for( DWORD i = 0; i < pMeshContainer->NumInfl; ++i )
{
if( pBoneComb[iAttrib].BoneId[i] != UINT_MAX )
{
NumBlend = i;
}
}
if( d3dCaps.MaxVertexBlendMatrices >= NumBlend + 1 )
{
// first calculate the world matrices for the current set of blend weights and get the accurate count of the number of blends
for( DWORD i = 0; i < pMeshContainer->NumInfl; ++i )
{
iMatrixIndex = pBoneComb[iAttrib].BoneId[i];
if( iMatrixIndex != UINT_MAX )
{
D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );
V( pd3dDevice->SetTransform( D3DTS_WORLDMATRIX( i ), &matTemp ) );
}
}
V( pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND, NumBlend ) );
// lookup the material used for this subset of faces
if( ( AttribIdPrev != pBoneComb[iAttrib].AttribId ) || ( AttribIdPrev == UNUSED32 ) )
{
V( pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D )
);
V( pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );
AttribIdPrev = pBoneComb[iAttrib].AttribId;
}
// draw the subset now that the correct material and matrices are loaded
V( pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib ) );
}
}
// If necessary, draw parts that HW could not handle using SW
if( pMeshContainer->iAttributeSW < pMeshContainer->NumAttributeGroups )
{
AttribIdPrev = UNUSED32;
V( pd3dDevice->SetSoftwareVertexProcessing( TRUE ) );
for( iAttrib = pMeshContainer->iAttributeSW; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++ )
{
NumBlend = 0;
for( DWORD i = 0; i < pMeshContainer->NumInfl; ++i )
{
if( pBoneComb[iAttrib].BoneId[i] != UINT_MAX )
{
NumBlend = i;
}
}
if( d3dCaps.MaxVertexBlendMatrices < NumBlend + 1 )
{
// first calculate the world matrices for the current set of blend weights and get the accurate count of the number of blends
for( DWORD i = 0; i < pMeshContainer->NumInfl; ++i )
{
iMatrixIndex = pBoneComb[iAttrib].BoneId[i];
if( iMatrixIndex != UINT_MAX )
{
D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex],
pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] );
V( pd3dDevice->SetTransform( D3DTS_WORLDMATRIX( i ), &matTemp ) );
}
}
V( pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND, NumBlend ) );
// lookup the material used for this subset of faces
if( ( AttribIdPrev != pBoneComb[iAttrib].AttribId ) || ( AttribIdPrev == UNUSED32 ) )
{
V( pd3dDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D
) );
V( pd3dDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ) );
AttribIdPrev = pBoneComb[iAttrib].AttribId;
}
// draw the subset now that the correct material and matrices are loaded
V( pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib ) );
}
}
V( pd3dDevice->SetSoftwareVertexProcessing( FALSE ) );
}
V( pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND, 0 ) );
}
else // standard mesh, just draw it after setting material properties
{
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 CAnimation::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 );
}
}
#endif
//使用方法
//CAnimation Animation;
//Animation.Init(g_pDevice, "sFileName"); -->添加到游戏的初始化中
//Animation.Logic(fElaspedTime); -->添加到游戏的逻辑更新中
//Animation.Render(fElapsedTime); -->添加到游戏的绘制中
//对于其中Logic的具体实现可以更改