//----------------------------------------------------------------------------- // File: mload.cpp // // Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #include #include #include #include // _alloca #include #include #include #include "resource.h" #include "D3DApp.h" #include "D3DFont.h" #include "D3DUtil.h" #include "DXUtil.h" #include "D3DRes.h" #include "rmxfguid.h" #include "rmxftmpl.h" #include "dxutil.h" #include "SkinnedMesh.h" HRESULT CalculateSum(SFrame *pframe, D3DXMATRIX *pmatCur, D3DXVECTOR3 *pvCenter, UINT *pcVertices) { HRESULT hr = S_OK; PBYTE pbPoints = NULL; UINT cVerticesLocal = 0; PBYTE pbCur; D3DXVECTOR3 *pvCur; D3DXVECTOR3 vTransformedCur; UINT iPoint; SMeshContainer *pmcCur; SFrame *pframeCur; UINT cVertices; D3DXMATRIXA16 matLocal; D3DXMatrixMultiply(&matLocal, &pframe->matRot, pmatCur); pmcCur = pframe->pmcMesh; while (pmcCur != NULL) { DWORD fvfsize = D3DXGetFVFVertexSize(pmcCur->pMesh->GetFVF()); cVertices = pmcCur->pMesh->GetNumVertices(); hr = pmcCur->pMesh->LockVertexBuffer(0, &pbPoints); if (FAILED(hr)) goto e_Exit; for( iPoint=0, pbCur = pbPoints; iPoint < cVertices; iPoint++, pbCur += fvfsize) { pvCur = (D3DXVECTOR3*)pbCur; if ((pvCur->x != 0.0) || (pvCur->y != 0.0) || (pvCur->z != 0.0)) { cVerticesLocal++; D3DXVec3TransformCoord(&vTransformedCur, pvCur, &matLocal); pvCenter->x += vTransformedCur.x; pvCenter->y += vTransformedCur.y; pvCenter->z += vTransformedCur.z; } } pmcCur->pMesh->UnlockVertexBuffer(); pbPoints = NULL; pmcCur = pmcCur->pmcNext; } *pcVertices += cVerticesLocal; pframeCur = pframe->pframeFirstChild; while (pframeCur != NULL) { hr = CalculateSum(pframeCur, &matLocal, pvCenter, pcVertices); if (FAILED(hr)) goto e_Exit; pframeCur = pframeCur->pframeSibling; } e_Exit: if (pbPoints != NULL) { pmcCur->pMesh->UnlockVertexBuffer(); } return hr; } HRESULT CalculateRadius(SFrame *pframe, D3DXMATRIX *pmatCur, D3DXVECTOR3 *pvCenter, float *pfRadiusSq) { HRESULT hr = S_OK; PBYTE pbPoints = NULL; PBYTE pbCur; D3DXVECTOR3 *pvCur; D3DXVECTOR3 vDist;; UINT iPoint; UINT cVertices; SMeshContainer *pmcCur; SFrame *pframeCur; float fRadiusLocalSq; float fDistSq; D3DXMATRIXA16 matLocal; D3DXMatrixMultiply(&matLocal, &pframe->matRot, pmatCur); pmcCur = pframe->pmcMesh; fRadiusLocalSq = *pfRadiusSq; while (pmcCur != NULL) { DWORD fvfsize = D3DXGetFVFVertexSize(pmcCur->pMesh->GetFVF()); cVertices = pmcCur->pMesh->GetNumVertices(); hr = pmcCur->pMesh->LockVertexBuffer(0, &pbPoints); if (FAILED(hr)) goto e_Exit; for( iPoint=0, pbCur = pbPoints; iPoint < cVertices; iPoint++, pbCur += fvfsize ) { pvCur = (D3DXVECTOR3*)pbCur; if ((pvCur->x == 0.0) && (pvCur->y == 0.0) && (pvCur->z == 0.0)) continue; D3DXVec3TransformCoord(&vDist, pvCur, &matLocal); vDist -= *pvCenter; fDistSq = D3DXVec3LengthSq(&vDist); if( fDistSq > fRadiusLocalSq ) fRadiusLocalSq = fDistSq; } pmcCur->pMesh->UnlockVertexBuffer(); pbPoints = NULL; pmcCur = pmcCur->pmcNext; } *pfRadiusSq = fRadiusLocalSq; pframeCur = pframe->pframeFirstChild; while (pframeCur != NULL) { hr = CalculateRadius(pframeCur, &matLocal, pvCenter, pfRadiusSq); if (FAILED(hr)) goto e_Exit; pframeCur = pframeCur->pframeSibling; } e_Exit: if (pbPoints != NULL) { pmcCur->pMesh->UnlockVertexBuffer(); } return hr; } HRESULT CalculateBoundingSphere(SDrawElement *pdeCur) { HRESULT hr = S_OK; D3DXVECTOR3 vCenter(0,0,0); UINT cVertices = 0; float fRadiusSq = 0; D3DXMATRIXA16 matCur; D3DXMatrixIdentity(&matCur); hr = CalculateSum(pdeCur->pframeRoot, &matCur, &vCenter, &cVertices); if (FAILED(hr)) goto e_Exit; if (cVertices > 0) { vCenter /= (float)cVertices; D3DXMatrixIdentity(&matCur); hr = CalculateRadius(pdeCur->pframeRoot, &matCur, &vCenter, &fRadiusSq); if (FAILED(hr)) goto e_Exit; } pdeCur->fRadius = (float)sqrt((double)fRadiusSq);; pdeCur->vCenter = vCenter; e_Exit: return hr; } HRESULT CMyD3DApplication::FindBones(SFrame *pframeCur, SDrawElement *pde) { HRESULT hr = S_OK; SMeshContainer *pmcMesh; SFrame *pframeChild; pmcMesh = pframeCur->pmcMesh; while (pmcMesh != NULL) { if (pmcMesh->m_pSkinMesh) { char** pBoneName = static_cast(pmcMesh->m_pBoneNamesBuf->GetBufferPointer()); for (DWORD i = 0; i < pmcMesh->m_pSkinMesh->GetNumBones(); ++i) { SFrame* pFrame = pde->FindFrame(pBoneName[i]); pmcMesh->m_pBoneMatrix[i] = &(pFrame->matCombined); } } pmcMesh = pmcMesh->pmcNext; } pframeChild = pframeCur->pframeFirstChild; while (pframeChild != NULL) { hr = FindBones(pframeChild, pde); if (FAILED(hr)) return hr; pframeChild = pframeChild->pframeSibling; } return S_OK; } HRESULT CMyD3DApplication::LoadMeshHierarchy() { TCHAR* pszFile = m_szPath; SDrawElement *pdeMesh = NULL; HRESULT hr = S_OK; LPDIRECTXFILE pxofapi = NULL; LPDIRECTXFILEENUMOBJECT pxofenum = NULL; LPDIRECTXFILEDATA pxofobjCur = NULL; DWORD dwOptions; int cchFileName; if (pszFile == NULL) return E_INVALIDARG; pdeMesh = new SDrawElement(); delete pdeMesh->pframeRoot; pdeMesh->pframeAnimHead = NULL; pdeMesh->pframeRoot = new SFrame(); if (pdeMesh->pframeRoot == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } dwOptions = 0; cchFileName = strlen(pszFile); if (cchFileName < 2) { hr = E_FAIL; goto e_Exit; } hr = DirectXFileCreate(&pxofapi); if (FAILED(hr)) goto e_Exit; // Register templates for d3drm. hr = pxofapi->RegisterTemplates((LPVOID)D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES); if (FAILED(hr)) goto e_Exit; // Create enum object. hr = pxofapi->CreateEnumObject((LPVOID)pszFile, DXFILELOAD_FROMFILE, &pxofenum); if (FAILED(hr)) goto e_Exit; // Enumerate top level objects. // Top level objects are always data object. while (SUCCEEDED(pxofenum->GetNextDataObject(&pxofobjCur))) { hr = LoadFrames(pxofobjCur, pdeMesh, dwOptions, m_dwFVF, m_pd3dDevice, pdeMesh->pframeRoot); GXRELEASE(pxofobjCur); if (FAILED(hr)) goto e_Exit; } hr = FindBones(pdeMesh->pframeRoot, pdeMesh); if (FAILED(hr)) goto e_Exit; delete []pdeMesh->szName; pdeMesh->szName = new char[cchFileName+1]; if (pdeMesh->szName == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } memcpy(pdeMesh->szName, pszFile, cchFileName+1); // delete the current mesh, now that the load has succeeded DeleteSelectedMesh(); // link into the draw list pdeMesh->pdeNext = m_pdeHead; m_pdeHead = pdeMesh; m_pdeSelected = pdeMesh; m_pmcSelectedMesh = pdeMesh->pframeRoot->pmcMesh; m_pframeSelected = pdeMesh->pframeRoot; hr = CalculateBoundingSphere(pdeMesh); if (FAILED(hr)) goto e_Exit; SetProjectionMatrix(); m_pdeSelected->fCurTime = 0.0f; m_pdeSelected->fMaxTime = 200.0f; D3DXMatrixTranslation(&m_pdeSelected->pframeRoot->matRot, -pdeMesh->vCenter.x, -pdeMesh->vCenter.y, -pdeMesh->vCenter.z); m_pdeSelected->pframeRoot->matRotOrig = m_pdeSelected->pframeRoot->matRot; e_Exit: GXRELEASE(pxofobjCur); GXRELEASE(pxofenum); GXRELEASE(pxofapi); if (FAILED(hr)) { delete pdeMesh; } return hr; } HRESULT CMyD3DApplication::LoadAnimation(LPDIRECTXFILEDATA pxofobjCur, SDrawElement *pde, DWORD options, DWORD fvf, LPDIRECT3DDEVICE8 pD3DDevice, SFrame *pframeParent) { HRESULT hr = S_OK; SRotateKeyXFile *pFileRotateKey; SScaleKeyXFile *pFileScaleKey; SPositionKeyXFile *pFilePosKey; SMatrixKeyXFile *pFileMatrixKey; SFrame *pframeCur; LPDIRECTXFILEDATA pxofobjChild = NULL; LPDIRECTXFILEOBJECT pxofChild = NULL; LPDIRECTXFILEDATAREFERENCE pxofobjChildRef = NULL; const GUID *type; DWORD dwSize; PBYTE pData; DWORD dwKeyType; DWORD cKeys; DWORD iKey; DWORD cchName; char *szFrameName; pframeCur = new SFrame(); if (pframeCur == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } pframeCur->bAnimationFrame = true; pframeParent->AddFrame(pframeCur); pde->AddAnimationFrame(pframeCur); // Enumerate child objects. // Child object can be data, data reference or binary. // Use QueryInterface() to find what type of object a child is. while (SUCCEEDED(pxofobjCur->GetNextObject(&pxofChild))) { // Query the child for it's FileDataReference hr = pxofChild->QueryInterface(IID_IDirectXFileDataReference, (LPVOID *)&pxofobjChildRef); if (SUCCEEDED(hr)) { hr = pxofobjChildRef->Resolve(&pxofobjChild); if (SUCCEEDED(hr)) { hr = pxofobjChild->GetType(&type); if (FAILED(hr)) goto e_Exit; if( TID_D3DRMFrame == *type ) { if (pframeCur->pframeToAnimate != NULL) { hr = E_INVALIDARG; goto e_Exit; } hr = pxofobjChild->GetName(NULL, &cchName); if (FAILED(hr)) goto e_Exit; if (cchName == 0) { hr = E_INVALIDARG; goto e_Exit; } szFrameName = (char*)_alloca(cchName); if (szFrameName == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } hr = pxofobjChild->GetName(szFrameName, &cchName); if (FAILED(hr)) goto e_Exit; pframeCur->pframeToAnimate = pde->FindFrame(szFrameName); if (pframeCur->pframeToAnimate == NULL) { hr = E_INVALIDARG; goto e_Exit; } } GXRELEASE(pxofobjChild); } GXRELEASE(pxofobjChildRef); } else { // Query the child for it's FileData hr = pxofChild->QueryInterface(IID_IDirectXFileData, (LPVOID *)&pxofobjChild); if (SUCCEEDED(hr)) { hr = pxofobjChild->GetType(&type); if (FAILED(hr)) goto e_Exit; if ( TID_D3DRMFrame == *type ) { hr = LoadFrames(pxofobjChild, pde, options, fvf, pD3DDevice, pframeCur); if (FAILED(hr)) goto e_Exit; } else if ( TID_D3DRMAnimationOptions == *type ) { //ParseAnimOptions(pChildData,pParentFrame); //i=2; } else if ( TID_D3DRMAnimationKey == *type ) { hr = pxofobjChild->GetData( NULL, &dwSize, (PVOID*)&pData ); if (FAILED(hr)) goto e_Exit; dwKeyType = ((DWORD*)pData)[0]; cKeys = ((DWORD*)pData)[1]; if (dwKeyType == 0) { if (pframeCur->m_pRotateKeys != NULL) { hr = E_INVALIDARG; goto e_Exit; } pframeCur->m_pRotateKeys = new SRotateKey[cKeys]; if (pframeCur->m_pRotateKeys == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } pframeCur->m_cRotateKeys = cKeys; //NOTE x files are w x y z and QUATERNIONS are x y z w pFileRotateKey = (SRotateKeyXFile*)(pData + (sizeof(DWORD) * 2)); for (iKey = 0;iKey < cKeys; iKey++) { pframeCur->m_pRotateKeys[iKey].dwTime = pFileRotateKey->dwTime; pframeCur->m_pRotateKeys[iKey].quatRotate.x = pFileRotateKey->x; pframeCur->m_pRotateKeys[iKey].quatRotate.y = pFileRotateKey->y; pframeCur->m_pRotateKeys[iKey].quatRotate.z = pFileRotateKey->z; pframeCur->m_pRotateKeys[iKey].quatRotate.w = pFileRotateKey->w; pFileRotateKey += 1; } } else if (dwKeyType == 1) { if (pframeCur->m_pScaleKeys != NULL) { hr = E_INVALIDARG; goto e_Exit; } pframeCur->m_pScaleKeys = new SScaleKey[cKeys]; if (pframeCur->m_pScaleKeys == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } pframeCur->m_cScaleKeys = cKeys; pFileScaleKey = (SScaleKeyXFile*)(pData + (sizeof(DWORD) * 2)); for (iKey = 0;iKey < cKeys; iKey++) { pframeCur->m_pScaleKeys[iKey].dwTime = pFileScaleKey->dwTime; pframeCur->m_pScaleKeys[iKey].vScale = pFileScaleKey->vScale; pFileScaleKey += 1; } } else if (dwKeyType == 2) { if (pframeCur->m_pPositionKeys != NULL) { hr = E_INVALIDARG; goto e_Exit; } pframeCur->m_pPositionKeys = new SPositionKey[cKeys]; if (pframeCur->m_pPositionKeys == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } pframeCur->m_cPositionKeys = cKeys; pFilePosKey = (SPositionKeyXFile*)(pData + (sizeof(DWORD) * 2)); for (iKey = 0;iKey < cKeys; iKey++) { pframeCur->m_pPositionKeys[iKey].dwTime = pFilePosKey->dwTime; pframeCur->m_pPositionKeys[iKey].vPos = pFilePosKey->vPos; pFilePosKey += 1; } } else if (dwKeyType == 4) { if (pframeCur->m_pMatrixKeys != NULL) { hr = E_INVALIDARG; goto e_Exit; } pframeCur->m_pMatrixKeys = new SMatrixKey[cKeys]; if (pframeCur->m_pMatrixKeys == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } pframeCur->m_cMatrixKeys = cKeys; pFileMatrixKey = (SMatrixKeyXFile*)(pData + (sizeof(DWORD) * 2)); for (iKey = 0;iKey < cKeys; iKey++) { pframeCur->m_pMatrixKeys[iKey].dwTime = pFileMatrixKey->dwTime; pframeCur->m_pMatrixKeys[iKey].mat = pFileMatrixKey->mat; pFileMatrixKey += 1; } } else { hr = E_INVALIDARG; goto e_Exit; } } GXRELEASE(pxofobjChild); } } GXRELEASE(pxofChild); } e_Exit: GXRELEASE(pxofobjChild); GXRELEASE(pxofChild); GXRELEASE(pxofobjChildRef); return hr; } HRESULT CMyD3DApplication::LoadAnimationSet(LPDIRECTXFILEDATA pxofobjCur, SDrawElement *pde, DWORD options, DWORD fvf, LPDIRECT3DDEVICE8 pD3DDevice, SFrame *pframeParent) { SFrame *pframeCur; const GUID *type; HRESULT hr = S_OK; LPDIRECTXFILEDATA pxofobjChild = NULL; LPDIRECTXFILEOBJECT pxofChild = NULL; DWORD cchName; pframeCur = new SFrame(); if (pframeCur == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } pframeCur->bAnimationFrame = true; pframeParent->AddFrame(pframeCur); hr = pxofobjCur->GetName(NULL, &cchName); if (FAILED(hr)) goto e_Exit; if (cchName > 0) { pframeCur->szName = new char[cchName]; if (pframeCur->szName == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } hr = pxofobjCur->GetName(pframeCur->szName, &cchName); if (FAILED(hr)) goto e_Exit; } // Enumerate child objects. // Child object can be data, data reference or binary. // Use QueryInterface() to find what type of object a child is. while (SUCCEEDED(pxofobjCur->GetNextObject(&pxofChild))) { // Query the child for it's FileData hr = pxofChild->QueryInterface(IID_IDirectXFileData, (LPVOID *)&pxofobjChild); if (SUCCEEDED(hr)) { hr = pxofobjChild->GetType(&type); if (FAILED(hr)) goto e_Exit; if( TID_D3DRMAnimation == *type ) { hr = LoadAnimation(pxofobjChild, pde, options, fvf, pD3DDevice, pframeCur); if (FAILED(hr)) goto e_Exit; } GXRELEASE(pxofobjChild); } GXRELEASE(pxofChild); } e_Exit: GXRELEASE(pxofobjChild); GXRELEASE(pxofChild); return hr; } HRESULT CMyD3DApplication::GenerateMesh(SMeshContainer *pmcMesh) { // ASSUMPTION: pmcMesh->m_rgiAdjacency contains the current adjacency HRESULT hr = S_OK; LPDIRECT3DDEVICE8 pDevice = NULL; DWORD cFaces = pmcMesh->m_pSkinMesh->GetNumFaces(); hr = pmcMesh->m_pSkinMesh->GetDevice(&pDevice); if (FAILED(hr)) goto e_Exit; GXRELEASE(pmcMesh->pMesh); delete [] m_pBoneMatrices; pmcMesh->pMesh = NULL; m_pBoneMatrices = NULL; if (m_method == D3DNONINDEXED) { LPD3DXBONECOMBINATION rgBoneCombinations; hr = pmcMesh->m_pSkinMesh->ConvertToBlendedMesh ( D3DXMESH_MANAGED|D3DXMESHOPT_VERTEXCACHE, pmcMesh->m_rgiAdjacency, NULL, &pmcMesh->cpattr, &pmcMesh->m_pBoneCombinationBuf, NULL, NULL, &pmcMesh->pMesh ); if (FAILED(hr)) goto e_Exit; // calculate the max face influence count if ((pmcMesh->pMesh->GetFVF() & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) { pmcMesh->m_maxFaceInfl = 1 + ((pmcMesh->pMesh->GetFVF() & D3DFVF_POSITION_MASK) - D3DFVF_XYZRHW) / 2; } else { pmcMesh->m_maxFaceInfl = 1; } /* 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. */ if (m_d3dCaps.MaxVertexBlendMatrices <= 2) { // calculate the index of the attribute table to split on rgBoneCombinations = reinterpret_cast(pmcMesh->m_pBoneCombinationBuf->GetBufferPointer()); for (pmcMesh->iAttrSplit = 0; pmcMesh->iAttrSplit < pmcMesh->cpattr; pmcMesh->iAttrSplit++) { DWORD cInfl = 0; for (DWORD iInfl = 0; iInfl < pmcMesh->m_maxFaceInfl; iInfl++) { if (rgBoneCombinations[pmcMesh->iAttrSplit].BoneId[iInfl] != UINT_MAX) { ++cInfl; } } if (cInfl > m_d3dCaps.MaxVertexBlendMatrices) { break; } } // if there is both HW and SW, add the Software Processing flag if (pmcMesh->iAttrSplit < pmcMesh->cpattr) { LPD3DXMESH pMeshTmp; hr = pmcMesh->pMesh->CloneMeshFVF(D3DXMESH_SOFTWAREPROCESSING|pmcMesh->pMesh->GetOptions(), pmcMesh->pMesh->GetFVF(), pDevice, &pMeshTmp); if (FAILED(hr)) { goto e_Exit; } pmcMesh->pMesh->Release(); pmcMesh->pMesh = pMeshTmp; pMeshTmp = NULL; } } else { pmcMesh->iAttrSplit = pmcMesh->cpattr; } } else if (m_method == D3DINDEXEDVS) { // Get palette size pmcMesh->m_paletteSize = min(28, pmcMesh->m_pSkinMesh->GetNumBones()); DWORD flags = D3DXMESHOPT_VERTEXCACHE; if (m_d3dCaps.VertexShaderVersion >= D3DVS_VERSION(1, 1)) { pmcMesh->m_bUseSW = false; flags |= D3DXMESH_MANAGED; } else { pmcMesh->m_bUseSW = true; flags |= D3DXMESH_SYSTEMMEM; } hr = pmcMesh->m_pSkinMesh->ConvertToIndexedBlendedMesh(flags, pmcMesh->m_rgiAdjacency, pmcMesh->m_paletteSize, NULL, &pmcMesh->cpattr, &pmcMesh->m_pBoneCombinationBuf, NULL, NULL, &pmcMesh->pMesh); if (FAILED(hr)) goto e_Exit; if ((pmcMesh->pMesh->GetFVF() & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) { pmcMesh->m_maxFaceInfl = ((pmcMesh->pMesh->GetFVF() & D3DFVF_POSITION_MASK) - D3DFVF_XYZRHW) / 2; } else { pmcMesh->m_maxFaceInfl = 1; } // FVF has to match our declarator. Vertex shaders are not as forgiving as FF pipeline DWORD newFVF = (pmcMesh->pMesh->GetFVF() & D3DFVF_POSITION_MASK) | D3DFVF_NORMAL | D3DFVF_TEX1 | D3DFVF_LASTBETA_UBYTE4; if (newFVF != pmcMesh->pMesh->GetFVF()) { LPD3DXMESH pMesh; hr = pmcMesh->pMesh->CloneMeshFVF(pmcMesh->pMesh->GetOptions(), newFVF, pDevice, &pMesh); if (!FAILED(hr)) { pmcMesh->pMesh->Release(); pmcMesh->pMesh = pMesh; pMesh = NULL; } } } else if (m_method == D3DINDEXED) { DWORD maxFaceInfl; DWORD flags = D3DXMESHOPT_VERTEXCACHE; hr = pmcMesh->m_pSkinMesh->GetMaxFaceInfluences(&maxFaceInfl); if (FAILED(hr)) goto e_Exit; // 12 entry palette guarantees that any triangle (4 independent influences per vertex of a tri) // can be handled maxFaceInfl = min(maxFaceInfl, 12); if (m_d3dCaps.MaxVertexBlendMatrixIndex + 1 < maxFaceInfl) { // HW does not support indexed vertex blending. Use SW instead pmcMesh->m_paletteSize = min(256, pmcMesh->m_pSkinMesh->GetNumBones()); pmcMesh->m_bUseSW = true; flags |= D3DXMESH_SYSTEMMEM; } else { pmcMesh->m_paletteSize = min(m_d3dCaps.MaxVertexBlendMatrixIndex + 1, pmcMesh->m_pSkinMesh->GetNumBones()); pmcMesh->m_bUseSW = false; flags |= D3DXMESH_MANAGED; } hr = pmcMesh->m_pSkinMesh->ConvertToIndexedBlendedMesh(flags, pmcMesh->m_rgiAdjacency, pmcMesh->m_paletteSize, NULL, &pmcMesh->cpattr, &pmcMesh->m_pBoneCombinationBuf, NULL, NULL, &pmcMesh->pMesh); if (FAILED(hr)) goto e_Exit; // Here we are talking of max vertex influence which we determine from // the FVF of the returned mesh if ((pmcMesh->pMesh->GetFVF() & D3DFVF_POSITION_MASK) != D3DFVF_XYZ) { pmcMesh->m_maxFaceInfl = ((pmcMesh->pMesh->GetFVF() & D3DFVF_POSITION_MASK) - D3DFVF_XYZRHW) / 2; } else { pmcMesh->m_maxFaceInfl = 1; } } else if (m_method == SOFTWARE) { hr = pmcMesh->m_pSkinMesh->GenerateSkinnedMesh ( D3DXMESH_WRITEONLY, // options 0.0f, // minimum bone weight allowed pmcMesh->m_rgiAdjacency, // adjacency of in-mesh NULL, // adjacency of out-mesh NULL, // face remap array NULL, // vertex remap buffer &pmcMesh->pMesh // out-mesh ); if (FAILED(hr)) goto e_Exit; hr = pmcMesh->pMesh->GetAttributeTable(NULL, &pmcMesh->cpattr); if (FAILED(hr)) goto e_Exit; delete[] pmcMesh->m_pAttrTable; pmcMesh->m_pAttrTable = new D3DXATTRIBUTERANGE[pmcMesh->cpattr]; if (pmcMesh->m_pAttrTable == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } hr = pmcMesh->pMesh->GetAttributeTable(pmcMesh->m_pAttrTable, NULL); if (FAILED(hr)) goto e_Exit; hr = pmcMesh->m_pSkinMesh->GetMaxFaceInfluences(&pmcMesh->m_maxFaceInfl); if (FAILED(hr)) goto e_Exit; // Allocate space for blend matrices m_pBoneMatrices = new D3DXMATRIXA16[m_maxBones]; if (m_pBoneMatrices == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } } pmcMesh->m_Method = m_method; e_Exit: GXRELEASE(pDevice); return hr; } HRESULT CMyD3DApplication::LoadMesh(LPDIRECTXFILEDATA pxofobjCur, DWORD options, DWORD fvf, LPDIRECT3DDEVICE8 pD3DDevice, SFrame *pframeParent) { HRESULT hr = S_OK; SMeshContainer *pmcMesh = NULL; LPD3DXBUFFER pbufMaterials = NULL; LPD3DXBUFFER pbufAdjacency = NULL; DWORD cchName; UINT cFaces; UINT iMaterial; LPDIRECT3DDEVICE8 m_pDevice = m_pd3dDevice; LPDWORD pAdjacencyIn; pmcMesh = new SMeshContainer(); if (pmcMesh == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } hr = pxofobjCur->GetName(NULL, &cchName); if (FAILED(hr)) goto e_Exit; if (cchName > 0) { pmcMesh->szName = new char[cchName]; if (pmcMesh->szName == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } hr = pxofobjCur->GetName(pmcMesh->szName, &cchName); if (FAILED(hr)) goto e_Exit; } hr = D3DXLoadSkinMeshFromXof(pxofobjCur, options, pD3DDevice, &pbufAdjacency, &pbufMaterials, &pmcMesh->cMaterials, &pmcMesh->m_pBoneNamesBuf, &pmcMesh->m_pBoneOffsetBuf, &pmcMesh->m_pSkinMesh); if (FAILED(hr)) { if (hr == D3DXERR_LOADEDMESHASNODATA) hr = S_OK; goto e_Exit; } cFaces = pmcMesh->m_pSkinMesh->GetNumFaces(); pAdjacencyIn = static_cast(pbufAdjacency->GetBufferPointer()); pmcMesh->m_rgiAdjacency = new DWORD[cFaces * 3]; if (pmcMesh->m_rgiAdjacency == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } memcpy(pmcMesh->m_rgiAdjacency, pAdjacencyIn, cFaces * 3 * sizeof(DWORD)); // Process skinning data if (pmcMesh->m_pSkinMesh->GetNumBones()) { // Update max bones of any mesh in the app m_maxBones = max(pmcMesh->m_pSkinMesh->GetNumBones(), m_maxBones); pmcMesh->m_pBoneMatrix = new D3DXMATRIX*[pmcMesh->m_pSkinMesh->GetNumBones()]; if (pmcMesh->m_pBoneMatrix == NULL) goto e_Exit; pmcMesh->m_pBoneOffsetMat = reinterpret_cast(pmcMesh->m_pBoneOffsetBuf->GetBufferPointer()); hr = GenerateMesh(pmcMesh); if (FAILED(hr)) goto e_Exit; } else { pmcMesh->m_pSkinMesh->GetOriginalMesh(&(pmcMesh->pMesh)); pmcMesh->m_pSkinMesh->Release(); pmcMesh->m_pSkinMesh = NULL; pmcMesh->cpattr = pmcMesh->cMaterials; } if ((pbufMaterials == NULL) || (pmcMesh->cMaterials == 0)) { pmcMesh->rgMaterials = new D3DMATERIAL8[1]; pmcMesh->pTextures = new LPDIRECT3DTEXTURE8[1]; if (pmcMesh->rgMaterials == NULL || pmcMesh->pTextures == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } memset(pmcMesh->rgMaterials, 0, sizeof(D3DMATERIAL8)); pmcMesh->rgMaterials[0].Diffuse.r = 0.5f; pmcMesh->rgMaterials[0].Diffuse.g = 0.5f; pmcMesh->rgMaterials[0].Diffuse.b = 0.5f; pmcMesh->rgMaterials[0].Specular = pmcMesh->rgMaterials[0].Diffuse; pmcMesh->pTextures[0] = NULL; } else { pmcMesh->rgMaterials = new D3DMATERIAL8[pmcMesh->cMaterials]; pmcMesh->pTextures = new LPDIRECT3DTEXTURE8[pmcMesh->cMaterials]; if (pmcMesh->rgMaterials == NULL || pmcMesh->pTextures == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } LPD3DXMATERIAL pMaterials = (LPD3DXMATERIAL)pbufMaterials->GetBufferPointer(); for (iMaterial = 0; iMaterial < pmcMesh->cMaterials; iMaterial++) { pmcMesh->rgMaterials[iMaterial] = pMaterials[iMaterial].MatD3D; pmcMesh->pTextures[iMaterial] = NULL; if (pMaterials[iMaterial].pTextureFilename != NULL) { TCHAR szPath[MAX_PATH]; DXUtil_FindMediaFile(szPath, pMaterials[iMaterial].pTextureFilename); hr = D3DXCreateTextureFromFile(m_pDevice, szPath, &(pmcMesh->pTextures[iMaterial])); if (FAILED(hr)) pmcMesh->pTextures[iMaterial] = NULL; } } } // add the mesh to the parent frame pframeParent->AddMesh(pmcMesh); pmcMesh = NULL; e_Exit: delete pmcMesh; GXRELEASE(pbufAdjacency); GXRELEASE(pbufMaterials); return hr; } HRESULT CMyD3DApplication::LoadFrames(LPDIRECTXFILEDATA pxofobjCur, SDrawElement *pde, DWORD options, DWORD fvf, LPDIRECT3DDEVICE8 pD3DDevice, SFrame *pframeParent) { HRESULT hr = S_OK; LPDIRECTXFILEDATA pxofobjChild = NULL; LPDIRECTXFILEOBJECT pxofChild = NULL; const GUID *type; DWORD cbSize; D3DXMATRIX *pmatNew; SFrame *pframeCur; DWORD cchName; // Get the type of the object hr = pxofobjCur->GetType(&type); if (FAILED(hr)) goto e_Exit; if (*type == TID_D3DRMMesh) { hr = LoadMesh(pxofobjCur, options, fvf, pD3DDevice, pframeParent); if (FAILED(hr)) goto e_Exit; } else if (*type == TID_D3DRMFrameTransformMatrix) { hr = pxofobjCur->GetData(NULL, &cbSize, (PVOID*)&pmatNew); if (FAILED(hr)) goto e_Exit; // update the parents matrix with the new one pframeParent->matRot = *pmatNew; pframeParent->matRotOrig = *pmatNew; } else if (*type == TID_D3DRMAnimationSet) { LoadAnimationSet(pxofobjCur, pde, options, fvf, pD3DDevice, pframeParent); } else if (*type == TID_D3DRMAnimation) { LoadAnimation(pxofobjCur, pde, options, fvf, pD3DDevice, pframeParent); } else if (*type == TID_D3DRMFrame) { pframeCur = new SFrame(); if (pframeCur == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } hr = pxofobjCur->GetName(NULL, &cchName); if (FAILED(hr)) goto e_Exit; if (cchName > 0) { pframeCur->szName = new char[cchName]; if (pframeCur->szName == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } hr = pxofobjCur->GetName(pframeCur->szName, &cchName); if (FAILED(hr)) goto e_Exit; } pframeParent->AddFrame(pframeCur); // Enumerate child objects. // Child object can be data, data reference or binary. // Use QueryInterface() to find what type of object a child is. while (SUCCEEDED(pxofobjCur->GetNextObject(&pxofChild))) { // Query the child for it's FileData hr = pxofChild->QueryInterface(IID_IDirectXFileData, (LPVOID *)&pxofobjChild); if (SUCCEEDED(hr)) { hr = LoadFrames(pxofobjChild, pde, options, fvf, pD3DDevice, pframeCur); if (FAILED(hr)) goto e_Exit; GXRELEASE(pxofobjChild); } GXRELEASE(pxofChild); } } e_Exit: GXRELEASE(pxofobjChild); GXRELEASE(pxofChild); return hr; } HRESULT CMyD3DApplication::DeleteSelectedMesh() { if (m_pdeSelected != NULL) { SDrawElement *pdeCur = m_pdeHead; SDrawElement *pdePrev = NULL; while ((pdeCur != NULL) && (pdeCur != m_pdeSelected)) { pdePrev = pdeCur; pdeCur = pdeCur->pdeNext; } if (pdePrev == NULL) { m_pdeHead = m_pdeHead->pdeNext; } else { pdePrev->pdeNext = pdeCur->pdeNext; } m_pdeSelected->pdeNext = NULL; if (m_pdeHead == m_pdeSelected) m_pdeHead = NULL; delete m_pdeSelected; m_pdeSelected = NULL; } return S_OK; }