www.pudn.com > 3DRPG.rar > SkinMesh.cpp


// SkinMesh.cpp: implementation of the CSkinMesh class. 
// 
////////////////////////////////////////////////////////////////////// 
#include "stdafx.h" 
#include "SkinMesh.h" 
 
//----------------------------------------------------------------------------- 
// Name: AllocateName() 
// Desc: Allocates memory for a string to hold the name of a frame or mesh 
//----------------------------------------------------------------------------- 
HRESULT AllocateName( LPCTSTR Name, LPTSTR *pNewName ) 
{ 
    UINT cbLength; 
	 
    if (Name != NULL) 
    { 
        cbLength = lstrlen(Name) + 1; 
        *pNewName = new TCHAR[cbLength]; 
        if (*pNewName == NULL) 
            return E_OUTOFMEMORY; 
        memcpy(*pNewName, Name, cbLength*sizeof(TCHAR)); 
    } 
    else 
    { 
        *pNewName = NULL; 
    } 
	 
    return S_OK; 
} 
 
//----------------------------------------------------------------------------- 
// Name: CAllocateHierarchy::CreateFrame() 
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CAllocateHierarchy::CreateFrame(LPCTSTR 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; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name: CAllocateHierarchy::CreateMeshContainer() 
// Desc:  
//----------------------------------------------------------------------------- 
 
 
#if (D3D_SDK_VERSION &31)	//这里是Directx9.0b的 
 
HRESULT CAllocateHierarchy::CreateMeshContainer( 
	LPCTSTR Name,  
	LPD3DXMESHDATA pMeshData, 
	LPD3DXMATERIAL pMaterials,  
	LPD3DXEFFECTINSTANCE pEffectInstances,  
	DWORD NumMaterials,  
	DWORD *pAdjacency,  
	LPD3DXSKININFO pSkinInfo,  
	LPD3DXMESHCONTAINER *ppNewMeshContainer)  
#else						//Direct9.0c 
	LRESULT CAllocateHierarchy::CreateMeshContainer( 
		LPCTSTR Name,  
		CONST D3DXMESHDATA *pMeshData, 
		CONST D3DXMATERIAL *pMaterials,  
		CONST D3DXEFFECTINSTANCE *pEffectInstances,  
		DWORD NumMaterials,  
		CONST DWORD *pAdjacency,  
		LPD3DXSKININFO pSkinInfo,  
		LPD3DXMESHCONTAINER *ppNewMeshContainer)  
#endif 
{ 
    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) 
            { 
//                TCHAR strTexturePath[MAX_PATH] = _T(""); 
//                DXUtil_FindMediaFileCb( strTexturePath, sizeof(strTexturePath), pMeshContainer->pMaterials[iMaterial].pTextureFilename ); 
                 
				if( FAILED( D3DXCreateTextureFromFile( pd3dDevice, pMeshContainer->pMaterials[iMaterial].pTextureFilename,  
					&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 = m_pSkinMesh->GenerateSkinnedMesh(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; 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name: CAllocateHierarchy::DestroyFrame() 
// Desc:  
//----------------------------------------------------------------------------- 
HRESULT CAllocateHierarchy::DestroyFrame(LPD3DXFRAME pFrameToFree)  
{ 
    SAFE_DELETE_ARRAY( pFrameToFree->Name ); 
    SAFE_DELETE( pFrameToFree ); 
    return S_OK;  
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name: CAllocateHierarchy::DestroyMeshContainer() 
// Desc:  
//----------------------------------------------------------------------------- 
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; 
} 
 
 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CSkinMesh::CSkinMesh(LPDIRECT3DDEVICE9 pD3DDevice) 
:m_vMax(0,0,0),m_vMin(0,0,0)   
{ 
	m_pD3DDevice=pD3DDevice; 
	m_fElapsedTime=0.0f; 
	m_pD3DDevice->GetDeviceCaps( &m_d3dCaps ); 
	m_bMoving=TRUE; 
    m_pAnimController = NULL; 
    m_pFrameRoot = NULL; 
    m_SkinningMethod = D3DINDEXED; 
    m_pBoneMatrices = NULL; 
    m_NumBoneMatricesMax = 0; 
} 
 
CSkinMesh::~CSkinMesh() 
{ 
	CAllocateHierarchy Alloc(this); 
	D3DXFrameDestroy(m_pFrameRoot, &Alloc); 
	 
    SAFE_RELEASE(m_pAnimController); 
	 
} 
 
 
HRESULT CSkinMesh::LoadFromXFile(char *strFileName) 
{ 
    HRESULT    hr; 
	CAllocateHierarchy Alloc(this); 
	 
    hr = D3DXLoadMeshHierarchyFromX(strFileName, D3DXMESH_MANAGED, m_pD3DDevice, &Alloc, NULL, &m_pFrameRoot, &m_pAnimController); 
    if (FAILED(hr)) 
        return hr; 
	 
    hr = SetupBoneMatrixPointers(m_pFrameRoot); 
    if (FAILED(hr)) 
        return hr; 
	 
    hr = D3DXFrameCalculateBoundingSphere(m_pFrameRoot, &m_vObjectCenter, &m_fObjectRadius); 
    if (FAILED(hr)) 
        return hr; 
	if(m_pFrameRoot) 
	CalculateBondingBox(m_pFrameRoot,&m_vMin,&m_vMax);   
	  
	return S_OK; 
} 
 
//----------------------------------------------------------------------------- 
// Name: GenerateSkinnedMesh() 
// Desc: Called either by CreateMeshContainer when loading a skin mesh, or when  
//       changing methods.  This function uses the pSkinInfo of the mesh  
//       container to generate the desired drawable mesh and bone combination  
//       table. 
//----------------------------------------------------------------------------- 
HRESULT CSkinMesh::GenerateSkinnedMesh(D3DXMESHCONTAINER_DERIVED *pMeshContainer) 
{ 
    HRESULT hr = S_OK; 
 
    if (pMeshContainer->pSkinInfo == NULL) 
        return hr; 
 
    SAFE_RELEASE( pMeshContainer->MeshData.pMesh ); 
    SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf ); 
 
    // if non-indexed skinning mode selected, use ConvertToBlendedMesh to generate drawable mesh 
    if (m_SkinningMethod == D3DNONINDEXED) 
    { 
 
        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(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 > m_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(), 
                                                m_pD3DDevice, &pMeshTmp); 
            if (FAILED(hr)) 
            { 
                goto e_Exit; 
            } 
 
            pMeshContainer->MeshData.pMesh->Release(); 
            pMeshContainer->MeshData.pMesh = pMeshTmp; 
            pMeshTmp = NULL; 
        } 
    } 
    // if indexed skinning mode selected, use ConvertToIndexedsBlendedMesh to generate drawable mesh 
    else if (m_SkinningMethod == D3DINDEXED) 
    { 
        DWORD NumMaxFaceInfl; 
        DWORD Flags = D3DXMESHOPT_VERTEXCACHE; 
 
        LPDIRECT3DINDEXBUFFER9 pIB; 
        hr = pMeshContainer->pOrigMesh->GetIndexBuffer(&pIB); 
        if (FAILED(hr)) 
            goto e_Exit; 
 
        hr = pMeshContainer->pSkinInfo->GetMaxFaceInfluences(pIB, pMeshContainer->pOrigMesh->GetNumFaces(), &NumMaxFaceInfl); 
        pIB->Release(); 
        if (FAILED(hr)) 
            goto e_Exit; 
 
        // 12 entry palette guarantees that any triangle (4 independent influences per vertex of a tri) 
        // can be handled 
        NumMaxFaceInfl = min(NumMaxFaceInfl, 12); 
 
        if (m_d3dCaps.MaxVertexBlendMatrixIndex + 1 < NumMaxFaceInfl) 
        { 
            // HW does not support indexed vertex blending. Use SW instead 
            pMeshContainer->NumPaletteEntries = min(256, pMeshContainer->pSkinInfo->GetNumBones()); 
            pMeshContainer->UseSoftwareVP = true; 
            Flags |= D3DXMESH_SYSTEMMEM; 
        } 
        else 
        { 
            // using hardware - determine palette size from caps and number of bones 
            // If normals are present in the vertex data that needs to be blended for lighting, then  
            // the number of matrices is half the number specified by MaxVertexBlendMatrixIndex. 
            pMeshContainer->NumPaletteEntries = min( ( m_d3dCaps.MaxVertexBlendMatrixIndex + 1 ) / 2,  
                                                     pMeshContainer->pSkinInfo->GetNumBones() ); 
            pMeshContainer->UseSoftwareVP = false; 
            Flags |= D3DXMESH_MANAGED; 
        } 
 
        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)) 
            goto e_Exit; 
    } 
     // if software skinning selected, use GenerateSkinnedMesh to create a mesh that can be used with UpdateSkinnedMesh 
    else if (m_SkinningMethod == SOFTWARE) 
    { 
        hr = pMeshContainer->pOrigMesh->CloneMeshFVF(D3DXMESH_MANAGED, pMeshContainer->pOrigMesh->GetFVF(), 
                                              m_pD3DDevice, &pMeshContainer->MeshData.pMesh); 
        if (FAILED(hr)) 
            goto e_Exit; 
 
        hr = pMeshContainer->MeshData.pMesh->GetAttributeTable(NULL, &pMeshContainer->NumAttributeGroups); 
        if (FAILED(hr)) 
            goto e_Exit; 
 
        delete[] pMeshContainer->pAttributeTable; 
        pMeshContainer->pAttributeTable  = new D3DXATTRIBUTERANGE[pMeshContainer->NumAttributeGroups]; 
        if (pMeshContainer->pAttributeTable == NULL) 
        { 
            hr = E_OUTOFMEMORY; 
            goto e_Exit; 
        } 
 
        hr = pMeshContainer->MeshData.pMesh->GetAttributeTable(pMeshContainer->pAttributeTable, NULL); 
        if (FAILED(hr)) 
            goto e_Exit; 
 
        // allocate a buffer for bone matrices, but only if another mesh has not allocated one of the same size or larger 
        if (m_NumBoneMatricesMax < pMeshContainer->pSkinInfo->GetNumBones()) 
        { 
            m_NumBoneMatricesMax = pMeshContainer->pSkinInfo->GetNumBones(); 
 
            // Allocate space for blend matrices 
            delete []m_pBoneMatrices;  
            m_pBoneMatrices  = new D3DXMATRIXA16[m_NumBoneMatricesMax]; 
            if (m_pBoneMatrices == NULL) 
            { 
                hr = E_OUTOFMEMORY; 
                goto e_Exit; 
            } 
        } 
    } 
    else  // invalid m_SkinningMethod value 
    {         
        // return failure due to invalid skinning method value 
        hr = E_INVALIDARG; 
        goto e_Exit; 
    } 
 
e_Exit: 
    return hr; 
} 
 
 
 
HRESULT CSkinMesh::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; 
} 
 
HRESULT CSkinMesh::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; 
} 
void CSkinMesh::Translation(POSITION ppos) 
	{ 
 
 
     
	D3DXMATRIX matRotation,matTranslate; 
	D3DXMatrixRotationY(&matRotation,-D3DX_PI/180*(ppos.a-90.0f)); 
	D3DXMatrixTranslation(&matTranslate,ppos.x,ppos.y+65.0f,ppos.z); 
	D3DXMatrixMultiply(&matWorld,&matRotation,&matTranslate); 
	m_pD3DDevice->SetTransform(D3DTS_WORLD,&matWorld); 
 
 
	} 
VOID CSkinMesh::Render(float fElapsedAppTime,D3DXVECTOR3 vPos,float angle,float scale) 
{ 
	 
	// Get the app's time, in seconds. Skip rendering if no time elapsed 
//    FLOAT fElapsedAppTime = DXUtil_Timer( TIMER_GETELAPSEDTIME ); 
	 
    if( 0.00f == fElapsedAppTime )    return; 
	m_fElapsedTime = fElapsedAppTime; 
	 
	// Setup world matrix 
    D3DXMATRIXA16 matWorld,matWorld2; 
 
	D3DXMatrixRotationY(&matWorld2,angle); 
	D3DXMatrixScaling(&matWorld,scale,scale,scale); 
 
	D3DXMatrixMultiply(&matWorld,&matWorld,&matWorld2); 
 
    D3DXMatrixTranslation( &matWorld2, vPos.x, vPos.y,vPos.z ); 
 
	D3DXMatrixMultiply(&matWorld,&matWorld,&matWorld2); 
 
 
 
  //  m_pD3DDevice->SetTransform( D3DTS_WORLD, &matWorld ); 
	if(m_pAnimController) 
	{ 
		if (m_bMoving) 
 
#if (D3D_SDK_VERSION &31) 
			m_pAnimController->SetTime(m_pAnimController->GetTime()-2);//m_fElapsedTime 
		else 
			m_pAnimController->SetTime(0); 
			 
#else  
			m_pAnimController->AdvanceTime(m_fElapsedTime,NULL);  
		else 
			m_pAnimController->ResetTime(); 
#endif 
 
	} 
	 
    UpdateFrameMatrices(m_pFrameRoot, &matWorld); 
	 
	DrawFrame(m_pFrameRoot); 
} 
 
 
 
 
VOID CSkinMesh::DrawFrame(LPD3DXFRAME pFrame) 
{ 
    LPD3DXMESHCONTAINER pMeshContainer; 
	  
    pMeshContainer = pFrame->pMeshContainer; 
    while (pMeshContainer != NULL) 
    { 
        DrawMeshContainer(pMeshContainer, pFrame); 
        pMeshContainer = pMeshContainer->pNextMeshContainer; 
    } 
	 
    if (pFrame->pFrameSibling != NULL) 
    { 
        DrawFrame(pFrame->pFrameSibling); 
    } 
	 
    if (pFrame->pFrameFirstChild != NULL) 
    { 
        DrawFrame(pFrame->pFrameFirstChild); 
    } 
   
} 
 
//----------------------------------------------------------------------------- 
// Name: DrawMeshContainer() 
// Desc: Called to render a mesh in the hierarchy 
//----------------------------------------------------------------------------- 
VOID CSkinMesh::DrawMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase, LPD3DXFRAME pFrameBase) 
{ 
    D3DXMESHCONTAINER_DERIVED *pMeshContainer = (D3DXMESHCONTAINER_DERIVED*)pMeshContainerBase; 
    D3DXFRAME_DERIVED *pFrame = (D3DXFRAME_DERIVED*)pFrameBase; 
    UINT iMaterial; 
    UINT NumBlend; 
    UINT iAttrib; 
    DWORD AttribIdPrev; 
    LPD3DXBONECOMBINATION pBoneComb; 
 
    UINT iMatrixIndex; 
    UINT iPaletteEntry; 
    D3DXMATRIXA16 matTemp; 
 
    // first check for skinning 
    if (pMeshContainer->pSkinInfo != NULL) 
    { 
        if (m_SkinningMethod == D3DNONINDEXED) 
        { 
            AttribIdPrev = UNUSED32;  
            pBoneComb = reinterpret_cast(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 (m_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] ); 
                            m_pD3DDevice->SetTransform( D3DTS_WORLDMATRIX( i ), &matTemp ); 
                        } 
                    } 
 
                    m_pD3DDevice->SetRenderState(D3DRS_VERTEXBLEND, NumBlend); 
 
                    // lookup the material used for this subset of faces 
                    if ((AttribIdPrev != pBoneComb[iAttrib].AttribId) || (AttribIdPrev == UNUSED32)) 
                    { 
                        m_pD3DDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D ); 
                        m_pD3DDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ); 
                        AttribIdPrev = pBoneComb[iAttrib].AttribId; 
                    } 
 
                    // draw the subset now that the correct material and matrices are loaded 
                    pMeshContainer->MeshData.pMesh->DrawSubset(iAttrib); 
                } 
            } 
 
            // If necessary, draw parts that HW could not handle using SW 
            if (pMeshContainer->iAttributeSW < pMeshContainer->NumAttributeGroups) 
            { 
                AttribIdPrev = UNUSED32;  
                m_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 (m_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] ); 
                                m_pD3DDevice->SetTransform( D3DTS_WORLDMATRIX( i ), &matTemp ); 
                            } 
                        } 
 
                        m_pD3DDevice->SetRenderState(D3DRS_VERTEXBLEND, NumBlend); 
 
                        // lookup the material used for this subset of faces 
                        if ((AttribIdPrev != pBoneComb[iAttrib].AttribId) || (AttribIdPrev == UNUSED32)) 
                        { 
                            m_pD3DDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D ); 
                            m_pD3DDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ); 
                            AttribIdPrev = pBoneComb[iAttrib].AttribId; 
                        } 
 
                        // draw the subset now that the correct material and matrices are loaded 
                        pMeshContainer->MeshData.pMesh->DrawSubset(iAttrib); 
                    } 
                } 
                m_pD3DDevice->SetSoftwareVertexProcessing(FALSE); 
            } 
 
            m_pD3DDevice->SetRenderState(D3DRS_VERTEXBLEND, 0); 
        } 
        else if (m_SkinningMethod == D3DINDEXED) 
        { 
            // if hw doesn't support indexed vertex processing, switch to software vertex processing 
            if (pMeshContainer->UseSoftwareVP) 
            { 
                m_pD3DDevice->SetSoftwareVertexProcessing(TRUE); 
            } 
 
            // set the number of vertex blend indices to be blended 
            if (pMeshContainer->NumInfl == 1) 
                m_pD3DDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_0WEIGHTS); 
            else 
                m_pD3DDevice->SetRenderState(D3DRS_VERTEXBLEND, pMeshContainer->NumInfl - 1); 
 
            if (pMeshContainer->NumInfl) 
                m_pD3DDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE); 
 
            // for each attribute group in the mesh, calculate the set of matrices in the palette and then draw the mesh subset 
            pBoneComb = reinterpret_cast(pMeshContainer->pBoneCombinationBuf->GetBufferPointer()); 
            for (iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++) 
            { 
                // first calculate all the world matrices 
                for (iPaletteEntry = 0; iPaletteEntry < pMeshContainer->NumPaletteEntries; ++iPaletteEntry) 
                { 
                    iMatrixIndex = pBoneComb[iAttrib].BoneId[iPaletteEntry]; 
                    if (iMatrixIndex != UINT_MAX) 
                    { 
                        D3DXMatrixMultiply( &matTemp, &pMeshContainer->pBoneOffsetMatrices[iMatrixIndex], pMeshContainer->ppBoneMatrixPtrs[iMatrixIndex] ); 
                        m_pD3DDevice->SetTransform( D3DTS_WORLDMATRIX( iPaletteEntry ), &matTemp ); 
                    } 
                } 
                 
                // setup the material of the mesh subset - REMEMBER to use the original pre-skinning attribute id to get the correct material id 
                m_pD3DDevice->SetMaterial( &pMeshContainer->pMaterials[pBoneComb[iAttrib].AttribId].MatD3D ); 
                m_pD3DDevice->SetTexture( 0, pMeshContainer->ppTextures[pBoneComb[iAttrib].AttribId] ); 
 
                // finally draw the subset with the current world matrix palette and material state 
                pMeshContainer->MeshData.pMesh->DrawSubset( iAttrib ); 
            } 
 
            // reset blending state 
            m_pD3DDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE); 
            m_pD3DDevice->SetRenderState(D3DRS_VERTEXBLEND, 0); 
 
            // remember to reset back to hw vertex processing if software was required 
            if (pMeshContainer->UseSoftwareVP) 
            { 
                m_pD3DDevice->SetSoftwareVertexProcessing(FALSE); 
            } 
        } 
        else if (m_SkinningMethod == SOFTWARE) 
        { 
            D3DXMATRIX  Identity; 
            DWORD       cBones  = pMeshContainer->pSkinInfo->GetNumBones(); 
            DWORD       iBone; 
            PBYTE       pbVerticesSrc; 
            PBYTE       pbVerticesDest; 
 
            // set up bone transforms 
            for (iBone = 0; iBone < cBones; ++iBone) 
            { 
                D3DXMatrixMultiply 
                ( 
                    &m_pBoneMatrices[iBone],                 // output 
                    &pMeshContainer->pBoneOffsetMatrices[iBone],  
                    pMeshContainer->ppBoneMatrixPtrs[iBone] 
                ); 
            } 
 
            // set world transform 
            D3DXMatrixIdentity(&Identity); 
            m_pD3DDevice->SetTransform(D3DTS_WORLD, &Identity); 
 
            pMeshContainer->pOrigMesh->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&pbVerticesSrc); 
            pMeshContainer->MeshData.pMesh->LockVertexBuffer(0, (LPVOID*)&pbVerticesDest); 
 
            // generate skinned mesh 
            pMeshContainer->pSkinInfo->UpdateSkinnedMesh(m_pBoneMatrices, NULL, pbVerticesSrc, pbVerticesDest); 
 
            pMeshContainer->pOrigMesh->UnlockVertexBuffer(); 
            pMeshContainer->MeshData.pMesh->UnlockVertexBuffer(); 
 
            for (iAttrib = 0; iAttrib < pMeshContainer->NumAttributeGroups; iAttrib++) 
            { 
                m_pD3DDevice->SetMaterial(&(pMeshContainer->pMaterials[pMeshContainer->pAttributeTable[iAttrib].AttribId].MatD3D)); 
                m_pD3DDevice->SetTexture(0, pMeshContainer->ppTextures[pMeshContainer->pAttributeTable[iAttrib].AttribId]); 
                pMeshContainer->MeshData.pMesh->DrawSubset(pMeshContainer->pAttributeTable[iAttrib].AttribId); 
            } 
        } 
        else // bug out as unsupported mode 
        { 
            return; 
        } 
    } 
    else  // standard mesh, just draw it after setting material properties 
    { 
        m_pD3DDevice->SetTransform(D3DTS_WORLD, &pFrame->CombinedTransformationMatrix); 
 
        for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++) 
        { 
            m_pD3DDevice->SetMaterial( &pMeshContainer->pMaterials[iMaterial].MatD3D ); 
            m_pD3DDevice->SetTexture( 0, pMeshContainer->ppTextures[iMaterial] ); 
            pMeshContainer->MeshData.pMesh->DrawSubset(iMaterial); 
        } 
    } 
} 
 
 
VOID CSkinMesh::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 CSkinMesh::SetAnim(BOOL bAnim) 
	{ 
		m_bMoving=bAnim; 
		if(!m_bMoving && m_pAnimController) 
		{	 
#if (D3D_SDK_VERSION & 32)		 
			m_pAnimController->ResetTime(); 
#else		m_pAnimController->SetTime(0); 
#endif 
		} 
	} 
 
	BOOL CSkinMesh::SetAnimationName(char *strAnimName) 
	{ 
		if(!m_bMoving || !m_pAnimController  ) return FALSE; 
		DWORD nAnimSet; 
		char strTempName[256]; 
		nAnimSet=m_pAnimController->GetNumAnimationSets(); 
		LPD3DXANIMATIONSET pAnimSet; 
		 
		for(DWORD i=0;iGetAnimationSet(i,&pAnimSet); 
			strcpy(strTempName,	pAnimSet->GetName()); 
			if(strcmp(strAnimName,strTempName)==0)  
			{ 
				m_pAnimController->SetTrackAnimationSet(0,pAnimSet); 
			  
				return TRUE; 
			 
			} 
 
		} 
		return FALSE; 
	 
	}; 
 
	 
//----------------------------------------- 
//Name:Intersect 
//Desc:使用索引和顶点缓冲区,求Mesh和射线交点 
//2006/6/27 JohnsonFeng 
//Use: IntersectIndexBuffer 
//----------------------------------------- 
BOOL CSkinMesh::InterSect( D3DVECTOR *pRayOrig, 
		 D3DVECTOR *pRayDir,D3DVECTOR* pVRet) 
{ 
	return S_OK; 
}