void cSkinnedMesh::UpdateSkinnedMesh( ST_BONE* pBone ) { // pCurrentBoneMatrices 를 계산하시오 // pCurrentBoneMatrices = pBoneOffsetMatrices * ppBoneMatrixPtrs if(pBone->pMeshContainer) { ST_BONE_MESH* pBoneMesh = (ST_BONE_MESH*)pBone->pMeshContainer; if(pBoneMesh->pSkinInfo) { LPD3DXSKININFO pSkinInfo = pBoneMesh->pSkinInfo; DWORD dwNumBones = pSkinInfo->GetNumBones(); for (DWORD i = 0; i < dwNumBones; ++i) { pBoneMesh->pCurrentBoneMatrices[i] = pBoneMesh->pBoneOffsetMatrices[i] * *(pBoneMesh->ppBoneMatrixPtrs[i]); } } BYTE* src = NULL; BYTE* dest = NULL; pBoneMesh->pOrigMesh->LockVertexBuffer( D3DLOCK_READONLY, (void**)&src ); pBoneMesh->MeshData.pMesh->LockVertexBuffer( 0, (void**)&dest ); //MeshData.pMesh을 업데이트 시켜준다. pBoneMesh->pSkinInfo->UpdateSkinnedMesh( pBoneMesh->pCurrentBoneMatrices, NULL, src, dest ); pBoneMesh->MeshData.pMesh->UnlockVertexBuffer(); pBoneMesh->pOrigMesh->UnlockVertexBuffer(); } //재귀적으로 모든 프레임에 대해서 실행. if(pBone->pFrameFirstChild) { UpdateSkinnedMesh((ST_BONE*)pBone->pFrameFirstChild); } if(pBone->pFrameSibling) { UpdateSkinnedMesh((ST_BONE*)pBone->pFrameSibling); } }
void cSkinnedMesh::SetupBoneMatrixPtrs( ST_BONE* pBone ) { // 각 프레임의 메시 컨테이너에 있는 pSkinInfo를 이용하여 영향받는 모든 // 프레임의 매트릭스를 ppBoneMatrixPtrs에 연결한다. // pSkinInfo->GetNumBones() 으로 영향받는 본의 개수를 찾음. // pSkinInfo->GetBoneName(i) 로 i번 프레임의 이름을 찾음 // D3DXFrameFind(루트 프레임, 프레임 이름) 로 프레임을 찾음. // 찾아서 월드매트릭스를 걸어줘라. if(pBone->pMeshContainer) { ST_BONE_MESH* pBoneMesh = (ST_BONE_MESH*)pBone->pMeshContainer; if(pBoneMesh->pSkinInfo) { LPD3DXSKININFO pSkinInfo = pBoneMesh->pSkinInfo; DWORD dwNumBones = pSkinInfo->GetNumBones(); for (DWORD i = 0; i < dwNumBones; ++i) { LPCSTR szBoneName = pSkinInfo->GetBoneName(i); ST_BONE* pBone = (ST_BONE*)D3DXFrameFind(m_pRoot, szBoneName); pBoneMesh->ppBoneMatrixPtrs[i] = &(pBone->matWorld); } } } //재귀적으로 모든 프레임에 대해서 실행. if(pBone->pFrameFirstChild) { SetupBoneMatrixPtrs((ST_BONE*)pBone->pFrameFirstChild); } if(pBone->pFrameSibling) { SetupBoneMatrixPtrs((ST_BONE*)pBone->pFrameSibling); } }
//----------------------------------------------------------------------------- // Desc: 在这里是调用了成员函数 GenerateGameSkinMesh(pMeshContainer); // 是在这里加载了蒙皮信息 //----------------------------------------------------------------------------- HRESULT DexAllocateHierarchy::CreateMeshContainer(LPCSTR Name, CONST D3DXMESHDATA *pMeshData, CONST D3DXMATERIAL *pMaterials, CONST D3DXEFFECTINSTANCE *pEffectInstances, DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppNewMeshContainer) { HRESULT hr; stDexMeshContainerEx *pMeshContainer = NULL; LPDIRECT3DDEVICE9 device = NULL; UINT NumFaces; UINT iMaterial; UINT iBone, cBones; 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; return hr; } // get the pMesh interface pointer out of the mesh data structure pMesh = pMeshData->pMesh; pMesh->GetDevice( &device ); // this sample does not FVF compatible meshes, so fail when one is found if (pMesh->GetFVF() == 0) { hr = E_FAIL; return hr; } // allocate the overloaded structure to return as a D3DXMESHCONTAINER pMeshContainer = new stDexMeshContainerEx; if (pMeshContainer == NULL) { hr = E_OUTOFMEMORY; return hr; } memset(pMeshContainer, 0, sizeof(stDexMeshContainerEx)); // 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)) { if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; } 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, device, &pMeshContainer->MeshData.pMesh ); if (FAILED(hr)) { if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; } // 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; if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; } 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 file[1000]; //FindMediaFile(file,pMeshContainer->pMaterials[iMaterial].pTextureFilename); // 根据纹理的文件名创建纹理资源,如果创建失败,纹理指针必须赋成NULL // MessageNULL(file); //D3DXCreateTextureFromFileEx(device, file, // D3DX_DEFAULT_NONPOW2, // D3DX_DEFAULT_NONPOW2, // D3DX_FROM_FILE, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, // D3DX_FILTER_NONE, D3DX_FILTER_NONE, D3DCOLOR_XRGB(0,0,0), NULL, NULL, // &pMeshContainer->ppTextures[iMaterial]); string texname = "model/"; //轉到model文件夾中去找紋理 texname += pMeshContainer->pMaterials[iMaterial].pTextureFilename; if( FAILED( D3DXCreateTextureFromFile( device, texname.c_str(), &pMeshContainer->ppTextures[iMaterial] ) ) ) { getLog()->BeginLog(); getLog()->Log(log_allert, "load model texture %s failed! \n", texname.c_str()); pMeshContainer->ppTextures[iMaterial] = NULL; getLog()->EndLog(); } // 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; if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; } // 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)); } // GenerateGameSkinMesh will take the general skinning information and transform it to a HW friendly version hr = GenerateGameSkinMesh(device, pMeshContainer ); if (FAILED(hr)) { if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; } } *ppNewMeshContainer = pMeshContainer; pMeshContainer = NULL; // call Destroy function to properly clean up the memory allocated if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; }
//----------------------------------------------------------------------------- // Name: CMultiAnimAllocateHierarchy::CreateMeshContainer() // Desc: Called by D3DX during the loading of a mesh hierarchy. At a minumum, // the app should allocate a D3DXMESHCONTAINER or a child of it and fill // in the members based on the parameters here. The app can further // customize the allocation behavior here. In our case, we initialize // m_amxBoneOffsets from the skin info for convenience reason. // Then we call ConvertToIndexedBlendedMesh to obtain a new mesh object // that's compatible with the palette size we have to work with. //----------------------------------------------------------------------------- HRESULT CMultiAnimAllocateHierarchy::CreateMeshContainer( THIS_ LPCSTR Name, CONST D3DXMESHDATA *pMeshData, CONST D3DXMATERIAL *pMaterials, CONST D3DXEFFECTINSTANCE *pEffectInstances, DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppNewMeshContainer ) { assert( m_pMA ); * ppNewMeshContainer = NULL; HRESULT hr = S_OK; MultiAnimMC * pMC = new MultiAnimMC; if( pMC == NULL ) { hr = E_OUTOFMEMORY; goto e_Exit; } ZeroMemory( pMC, sizeof( MultiAnimMC ) ); // if this is a static mesh, exit early; we're only interested in skinned meshes if( pSkinInfo == NULL ) { hr = S_OK; goto e_Exit; } // only support mesh type if( pMeshData->Type != D3DXMESHTYPE_MESH ) { hr = E_FAIL; goto e_Exit; } if( Name ) pMC->Name = (CHAR *) HeapCopy( (CHAR *) Name ); else pMC->Name = (CHAR *) HeapCopy( "<no_name>" ); // copy the mesh over pMC->MeshData.Type = pMeshData->Type; pMC->MeshData.pMesh = pMeshData->pMesh; pMC->MeshData.pMesh->AddRef(); // copy adjacency over { DWORD dwNumFaces = pMC->MeshData.pMesh->GetNumFaces(); pMC->pAdjacency = new DWORD[ 3 * dwNumFaces ]; if( pMC->pAdjacency == NULL ) { hr = E_OUTOFMEMORY; goto e_Exit; } CopyMemory( pMC->pAdjacency, pAdjacency, 3 * sizeof( DWORD ) * dwNumFaces ); } // ignore effects instances pMC->pEffects = NULL; // alloc and copy materials pMC->NumMaterials = max( 1, NumMaterials ); pMC->pMaterials = new D3DXMATERIAL [ pMC->NumMaterials ]; pMC->m_apTextures = new LPDIRECT3DTEXTURE9 [ pMC->NumMaterials ]; if( pMC->pMaterials == NULL || pMC->m_apTextures == NULL ) { hr = E_OUTOFMEMORY; goto e_Exit; } if( NumMaterials > 0 ) { CopyMemory( pMC->pMaterials, pMaterials, NumMaterials * sizeof( D3DXMATERIAL ) ); for( DWORD i = 0; i < NumMaterials; ++ i ) { if( pMC->pMaterials[ i ].pTextureFilename ) { // CALLBACK to get valid filename TCHAR sNewPath[ MAX_PATH ]; TCHAR tszTexName[ MAX_PATH ]; if( FAILED( DXUtil_ConvertAnsiStringToGenericCch( tszTexName, pMC->pMaterials[ i ].pTextureFilename, MAX_PATH ) ) ) pMC->m_apTextures[ i ] = NULL; else if( SUCCEEDED( DXUtil_FindMediaFileCch( sNewPath, MAX_PATH, tszTexName ) ) ) { // create the D3D texture if( FAILED( D3DXCreateTextureFromFile( m_pMA->m_pDevice, sNewPath, &pMC->m_apTextures[ i ] ) ) ) pMC->m_apTextures[ i ] = NULL; } else pMC->m_apTextures[ i ] = NULL; } else pMC->m_apTextures[ i ] = NULL; } } else // mock up a default material and set it { ZeroMemory( & pMC->pMaterials[ 0 ].MatD3D, sizeof( ParaMaterial ) ); pMC->pMaterials[ 0 ].MatD3D.Diffuse.r = 0.5f; pMC->pMaterials[ 0 ].MatD3D.Diffuse.g = 0.5f; pMC->pMaterials[ 0 ].MatD3D.Diffuse.b = 0.5f; pMC->pMaterials[ 0 ].MatD3D.Specular = pMC->pMaterials[ 0 ].MatD3D.Diffuse; pMC->pMaterials[ 0 ].pTextureFilename = NULL; } // save the skininfo object pMC->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); // Get the bone offset matrices from the skin info pMC->m_amxBoneOffsets = new Matrix4[ pSkinInfo->GetNumBones() ]; if( pMC->m_amxBoneOffsets == NULL ) { hr = E_OUTOFMEMORY; goto e_Exit; } { for( DWORD i = 0; i < pSkinInfo->GetNumBones(); ++ i ) pMC->m_amxBoneOffsets[ i ] = * (Matrix4 *) pSkinInfo->GetBoneOffsetMatrix( i ); } // // Determine the palette size we need to work with, then call ConvertToIndexedBlendedMesh // to set up a new mesh that is compatible with the palette size. // { UINT iPaletteSize = 0; m_pMA->m_pEffect->GetInt( "MATRIX_PALETTE_SIZE", (INT *) & iPaletteSize ); pMC->m_dwNumPaletteEntries = min( iPaletteSize, pMC->pSkinInfo->GetNumBones() ); } // generate the skinned mesh - creates a mesh with blend weights and indices hr = pMC->pSkinInfo->ConvertToIndexedBlendedMesh( pMC->MeshData.pMesh, D3DXMESH_MANAGED | D3DXMESHOPT_VERTEXCACHE, pMC->m_dwNumPaletteEntries, pMC->pAdjacency, NULL, NULL, NULL, &pMC->m_dwMaxNumFaceInfls, &pMC->m_dwNumAttrGroups, &pMC->m_pBufBoneCombos, &pMC->m_pWorkingMesh ); if( FAILED( hr ) ) goto e_Exit; // Make sure the working set is large enough for this mesh. // This is a bone array used for all mesh containers as a working // set during drawing. If one was created previously that isn't // large enough for this mesh, we have to reallocate. if( m_pMA->m_dwWorkingPaletteSize < pMC->m_dwNumPaletteEntries ) { if( m_pMA->m_amxWorkingPalette ) delete [] m_pMA->m_amxWorkingPalette; m_pMA->m_dwWorkingPaletteSize = pMC->m_dwNumPaletteEntries; m_pMA->m_amxWorkingPalette = new Matrix4[ m_pMA->m_dwWorkingPaletteSize ]; if( m_pMA->m_amxWorkingPalette == NULL ) { m_pMA->m_dwWorkingPaletteSize = 0; hr = E_OUTOFMEMORY; goto e_Exit; } } // ensure the proper vertex format for the mesh { DWORD dwOldFVF = pMC->m_pWorkingMesh->GetFVF(); DWORD dwNewFVF = ( dwOldFVF & D3DFVF_POSITION_MASK ) | D3DFVF_NORMAL | D3DFVF_TEX1 | D3DFVF_LASTBETA_UBYTE4; if( dwNewFVF != dwOldFVF ) { LPD3DXMESH pMesh; hr = pMC->m_pWorkingMesh->CloneMeshFVF( pMC->m_pWorkingMesh->GetOptions(), dwNewFVF, m_pMA->m_pDevice, &pMesh ); if( FAILED( hr ) ) goto e_Exit; pMC->m_pWorkingMesh->Release(); pMC->m_pWorkingMesh = pMesh; // if the loaded mesh didn't contain normals, compute them here if( ! ( dwOldFVF & D3DFVF_NORMAL ) ) { hr = D3DXComputeNormals( pMC->m_pWorkingMesh, NULL ); if( FAILED( hr ) ) goto e_Exit; } } } // Interpret the UBYTE4 as a Color. // The GeForce3 doesn't support the UBYTE4 decl type. So, we convert any // blend indices to a Color semantic, and later in the shader convert // it back using the D3DCOLORtoUBYTE4() intrinsic. Note that we don't // convert any data, just the declaration. D3DVERTEXELEMENT9 pDecl[ MAX_FVF_DECL_SIZE ]; D3DVERTEXELEMENT9 * pDeclCur; hr = pMC->m_pWorkingMesh->GetDeclaration( pDecl ); if( FAILED( hr ) ) goto e_Exit; pDeclCur = pDecl; while( pDeclCur->Stream != 0xff ) { if( ( pDeclCur->Usage == D3DDECLUSAGE_BLENDINDICES ) && ( pDeclCur->UsageIndex == 0 ) ) pDeclCur->Type = D3DDECLTYPE_D3DCOLOR; pDeclCur++; } hr = pMC->m_pWorkingMesh->UpdateSemantics( pDecl ); if( FAILED( hr ) ) goto e_Exit; e_Exit: if( FAILED( hr ) ) { if( pMC ) DestroyMeshContainer( pMC ); } else * ppNewMeshContainer = pMC; return hr; }
/* ================== Callback called when a mesh data is encountered during the .x file load Name - name of the Mesh (const char*) meshData - the mesh data materials - material array effectInstances - effect files / settings for the mesh numMaterials - number of materials in the mesh adjacency - adjacency array pSkinInfo - skin info. etNewMeshContainer - output pointer to assign our newly created mesh container ================== */ HRESULT XMeshHierarchy::CreateMeshContainer( LPCSTR Name, CONST D3DXMESHDATA *meshData, CONST D3DXMATERIAL *materials, CONST D3DXEFFECTINSTANCE *effectInstances, DWORD numMaterials, CONST DWORD *adjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER* retNewMeshContainer) { // Create a mesh container structure to fill and initilaise to zero values // Note: I use my extended version of the structure (D3DXMESHCONTAINER_EXTENDED) defined in MeshStructures.h D3DXMESHCONTAINER_EXTENDED *newMeshContainer=new D3DXMESHCONTAINER_EXTENDED; ZeroMemory(newMeshContainer, sizeof(D3DXMESHCONTAINER_EXTENDED)); // Always a good idea to initialise return pointer before proceeding *retNewMeshContainer = 0; // The mesh name (may be 0) needs copying over if (Name && strlen(Name)) { newMeshContainer->Name = Debug->DuplicateCharString(Name); } else { } // The mesh type (D3DXMESHTYPE_MESH, D3DXMESHTYPE_PMESH or D3DXMESHTYPE_PATCHMESH) if (meshData->Type!=D3DXMESHTYPE_MESH) { // This demo does not handle mesh types other than the standard // Other types are D3DXMESHTYPE_PMESH (progressive mesh) and D3DXMESHTYPE_PATCHMESH (patch mesh) DestroyMeshContainer(newMeshContainer); return E_FAIL; } newMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; // Adjacency data - holds information about triangle adjacency, required by the ID3DMESH object DWORD dwFaces = meshData->pMesh->GetNumFaces(); newMeshContainer->pAdjacency = new DWORD[dwFaces*3]; memcpy(newMeshContainer->pAdjacency, adjacency, sizeof(DWORD) * dwFaces*3); // Get the Direct3D device, luckily this is held in the mesh itself (Note: must release it when done with it) LPDIRECT3DDEVICE9 pd3dDevice = 0; meshData->pMesh->GetDevice(&pd3dDevice); // Can just assign pointer and add a ref rather than need to clone newMeshContainer->MeshData.pMesh=meshData->pMesh; newMeshContainer->MeshData.pMesh->AddRef(); // Create material and texture arrays. Note that I always want to have at least one newMeshContainer->NumMaterials = max (numMaterials, 1); newMeshContainer->exMaterials = new D3DMATERIAL9[newMeshContainer->NumMaterials]; newMeshContainer->exTextures = new LPDIRECT3DTEXTURE9[newMeshContainer->NumMaterials]; ZeroMemory(newMeshContainer->exTextures, sizeof(LPDIRECT3DTEXTURE9) * newMeshContainer->NumMaterials); if (numMaterials > 0) { // Load all the textures and copy the materials over for(DWORD i = 0; i < numMaterials; ++i) { newMeshContainer->exTextures[i] = 0; newMeshContainer->exMaterials[i]=materials[i].MatD3D; if(materials[i].pTextureFilename) { char mTexturePath [2048]; mTexturePath [0] = 0; strcat (mTexturePath, mPath); strcat (mTexturePath, "\\"); strcat (mTexturePath, materials[i].pTextureFilename); // Use the D3DX function to load the texture if(FAILED(D3DXCreateTextureFromFile(pd3dDevice, mTexturePath, &newMeshContainer->exTextures[i]))) { Debug->Header ("Could not load texture:", 3); Debug->DataChar (mTexturePath, 1); return 0; } } } } else // make a default material in the case where the mesh did not provide one { ZeroMemory(&newMeshContainer->exMaterials[0], sizeof( D3DMATERIAL9 ) ); newMeshContainer->exMaterials[0].Diffuse.r = 0.5f; newMeshContainer->exMaterials[0].Diffuse.g = 0.5f; newMeshContainer->exMaterials[0].Diffuse.b = 0.5f; newMeshContainer->exMaterials[0].Specular = newMeshContainer->exMaterials[0].Diffuse; newMeshContainer->exTextures[0]=0; } // If there is skin data associated with the mesh copy it over if (pSkinInfo) { // save off the SkinInfo newMeshContainer->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); // Need an array of offset matrices to move the vertices from the figure space to the bone's space UINT numBones = pSkinInfo->GetNumBones(); newMeshContainer->exBoneOffsets = new D3DXMATRIX[numBones]; // Create the arrays for the bones and the frame matrices newMeshContainer->exFrameCombinedMatrixPointer = new D3DXMATRIX*[numBones]; // get each of the bone offset matrices so that we don't need to get them later for (UINT i = 0; i < numBones; i++) newMeshContainer->exBoneOffsets[i] = *(newMeshContainer->pSkinInfo->GetBoneOffsetMatrix(i)); Debug->Header ("Mesh has skinning info. Number of bones is:", 3); Debug->DataInt (numBones, 1); // Note: in the Microsoft samples a GenerateSkinnedMesh function is called here in order to prepare // the skinned mesh data for optimial hardware acceleration. As mentioned in the notes this sample // does not do hardware skinning but instead uses software skinning. } else { Debug->Header ("Mesh has no skinning info", 1); // No skin info so 0 all the pointers newMeshContainer->pSkinInfo = 0; newMeshContainer->exBoneOffsets = 0; newMeshContainer->exSkinMesh = 0; newMeshContainer->exFrameCombinedMatrixPointer = 0; } // When we got the device we caused an internal reference count to be incremented // So we now need to release it pd3dDevice->Release(); // The mesh may contain a reference to an effect file if (effectInstances) { if (effectInstances->pEffectFilename) Debug->Header ("This .x file references an effect file. Effect files are not handled by IndieLib", 1); } // Set the output mesh container pointer to our newly created one *retNewMeshContainer = newMeshContainer; return S_OK; }
//--------------------------------- HRESULT CAllocateHierarchy::CreateMeshContainer (LPCSTR Name, const D3DXMESHDATA *pMeshData, \ const D3DXMATERIAL *pMaterials,const D3DXEFFECTINSTANCE *pEffectInstances, \ DWORD NumMaterials, const DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, \ LPD3DXMESHCONTAINER *ppNewMeshContainer) { DWORD i, j; D3DXMESHCONTAINER_DERIVED *pMeshContainer; LPD3DXMESH pMesh, pTempMesh; HRESULT hr = E_FAIL; *ppNewMeshContainer = NULL; //podporované su iba bezne meshe if (pMeshData->Type != D3DXMESHTYPE_MESH) return E_FAIL; //alokácia derivovanej štruktúry kvôli návratovej hodnote - LPD3DXMESHCONTAINER pMeshContainer = new D3DXMESHCONTAINER_DERIVED; if (pMeshContainer == NULL) return E_OUTOFMEMORY; pMesh = pMeshData->pMesh; pMesh->AddRef(); pMeshContainer->NumMaterials = max (1, NumMaterials); pMeshContainer->dwNumPaintings = 1; pMeshContainer->dwNumCoords = 1; if (m_localData.xmlTextures) { const char *szTemp; if (szTemp = g_pXML->Attr (m_localData.xmlTextures, "paint_num")) pMeshContainer->dwNumPaintings = (DWORD)atoi (szTemp); if (szTemp = g_pXML->Attr (m_localData.xmlTextures, "coord_num")) pMeshContainer->dwNumCoords = (DWORD)atoi (szTemp); } pMeshContainer->dwNumPaintings = max (1, pMeshContainer->dwNumPaintings); pMeshContainer->dwNumCoords = max (1, pMeshContainer->dwNumCoords); if (pMeshContainer->dwNumPaintings <= m_localData.dwUseThisPainting) m_localData.dwUseThisPainting = 0; // chyba, pozadovana painting-verzia nie je v xml definovana ////////////////////////////////////////////////////////////////////////// // mesh cloning - tangent, binormal, tex. koordinaty - pocitaju sa len pre modely s viac ako jednou texturovou vrstvou if (pMeshContainer->dwNumCoords > 1) { const DWORD dwRealNumCoords = (pMesh->GetFVF() & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT; const int intTexCoordsToAdd = pMeshContainer->dwNumCoords - dwRealNumCoords; DWORD dwVertexStride = pMesh->GetNumBytesPerVertex (); D3DVERTEXELEMENT9 meshDeclaration[MAX_FVF_DECL_SIZE]; if (SUCCEEDED (pMesh->GetDeclaration (meshDeclaration))) { DWORD dwNumDeclarations = 0; for (i=0; (i < MAX_FVF_DECL_SIZE) && (meshDeclaration[i].Stream != 0xFF); i++) dwNumDeclarations++; // pridanie deklaracie pre tangent meshDeclaration[dwNumDeclarations].Stream = 0; meshDeclaration[dwNumDeclarations].Offset = (WORD)dwVertexStride; meshDeclaration[dwNumDeclarations].Type = D3DDECLTYPE_FLOAT3; meshDeclaration[dwNumDeclarations].Method = D3DDECLMETHOD_DEFAULT; meshDeclaration[dwNumDeclarations].Usage = D3DDECLUSAGE_TANGENT; meshDeclaration[dwNumDeclarations].UsageIndex = 0; dwNumDeclarations++; // pridanie deklaracie pre binormal meshDeclaration[dwNumDeclarations].Stream = 0; meshDeclaration[dwNumDeclarations].Offset = (WORD)(dwVertexStride + 3*sizeof(float)); meshDeclaration[dwNumDeclarations].Type = D3DDECLTYPE_FLOAT3; meshDeclaration[dwNumDeclarations].Method = D3DDECLMETHOD_DEFAULT; meshDeclaration[dwNumDeclarations].Usage = D3DDECLUSAGE_BINORMAL; meshDeclaration[dwNumDeclarations].UsageIndex = 0; dwNumDeclarations++; // pridanie texturovych koordinatov for (int k=0; k<intTexCoordsToAdd; k++) { meshDeclaration[dwNumDeclarations].Stream = 0; meshDeclaration[dwNumDeclarations].Offset = (WORD)(dwVertexStride + 6*sizeof(float) + k*2*sizeof(float)); meshDeclaration[dwNumDeclarations].Type = D3DDECLTYPE_FLOAT2; meshDeclaration[dwNumDeclarations].Method = D3DDECLMETHOD_DEFAULT; meshDeclaration[dwNumDeclarations].Usage = D3DDECLUSAGE_TEXCOORD; meshDeclaration[dwNumDeclarations].UsageIndex = BYTE(k + dwRealNumCoords); dwNumDeclarations++; } // ukoncovaci element memset (&meshDeclaration[dwNumDeclarations], 0, sizeof(D3DVERTEXELEMENT9)); meshDeclaration[dwNumDeclarations].Stream = 0xFF; meshDeclaration[dwNumDeclarations].Type = D3DDECLTYPE_UNUSED; if (FAILED (pMesh->CloneMesh (pMesh->GetOptions(), meshDeclaration, g_pD3DDevice, &pTempMesh))) goto e_Exit; pMesh->Release (); pMesh = pTempMesh; } ////////////////////////////////////////////////////////////////////////// const DWORD dwVertexCount = pMesh->GetNumVertices (); dwVertexStride = pMesh->GetNumBytesPerVertex (); // uprava koordinatov, ak je to potrebne for (i=dwRealNumCoords; i < pMeshContainer->dwNumCoords; i++) { LPVOID pData; DWORD dwUseThisCoords = 0xFFFFFFFF,dwTexCoordOffsetSrc = 0xFFFFFFFF, dwTexCoordOffsetDst = 0xFFFFFFFF; if (m_localData.xmlTextures) { ezxml_t pTextureTag, pCoordsTag; const char *szTemp; char szCoordsTag[16]; if (pTextureTag = g_pXML->Child (m_localData.xmlTextures, "texture0")) { sprintf (szCoordsTag, "coords%u", i); if (pCoordsTag = g_pXML->Child (pTextureTag, szCoordsTag)) if (szTemp = g_pXML->Attr (pCoordsTag, "usecoords")) { dwUseThisCoords = (DWORD) atoi (szTemp); if (dwUseThisCoords >= i) dwUseThisCoords = 0; } } } if ((i > dwRealNumCoords) && (dwUseThisCoords == 0xFFFFFFFF)) dwUseThisCoords = 0; // ak je v xml definovany usecoords, tak kopirovat koordinaty if (dwUseThisCoords != 0xFFFFFFFF) { for (j=0; (j < MAX_FVF_DECL_SIZE) && (meshDeclaration[j].Stream != 0xFF); j++) if (meshDeclaration[j].Usage == D3DDECLUSAGE_TEXCOORD) if (meshDeclaration[j].UsageIndex == dwUseThisCoords) dwTexCoordOffsetSrc = meshDeclaration[j].Offset; else if (meshDeclaration[j].UsageIndex == i) dwTexCoordOffsetDst = meshDeclaration[j].Offset; if ((dwTexCoordOffsetSrc == 0xFFFFFFFF) || (dwTexCoordOffsetDst == 0xFFFFFFFF)) continue; // chyba if (SUCCEEDED (pMesh->LockVertexBuffer (0, &pData))) { LPBYTE pVertexData = (LPBYTE)pData; // kopirovanie koordinatov z vrstvy dwUseThisCoords for (j=0; j<dwVertexCount; j++) { memcpy ((pVertexData + dwTexCoordOffsetDst), (pVertexData + dwTexCoordOffsetSrc), 2*sizeof(float)); pVertexData += dwVertexStride; } pMesh->UnlockVertexBuffer (); } } } // vypocet tangent a binormal if (!CalculateMeshTangents (pMesh, 1)) g_pConsole->Message(MSG_CON_ERR, "MeshLoader: CalculateMeshTangents() function failed"); } ////////////////////////////////////////////////////////////////////////// // nacitanie informacii o materialoch a texturach z x suboru pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials]; pMeshContainer->pTextures = new LPDIRECT3DTEXTURE9 [pMeshContainer->NumMaterials * pMeshContainer->dwNumCoords * pMeshContainer->dwNumPaintings]; pMeshContainer->p7MTmaterials = new DWORD [pMeshContainer->NumMaterials]; if ((pMeshContainer->pMaterials == NULL) || (pMeshContainer->pTextures == NULL) || \ (pMeshContainer->p7MTmaterials == NULL)) {hr = E_OUTOFMEMORY; goto e_Exit;} memset (pMeshContainer->pMaterials, 0, sizeof(D3DXMATERIAL) * pMeshContainer->NumMaterials); memset (pMeshContainer->pTextures, 0, sizeof(LPDIRECT3DTEXTURE9) * pMeshContainer->NumMaterials * pMeshContainer->dwNumCoords * pMeshContainer->dwNumPaintings); memset (pMeshContainer->p7MTmaterials, 0xFF, sizeof(DWORD) * pMeshContainer->NumMaterials); // nacitanie materialov if (NumMaterials > 0) { for (i=0; i<NumMaterials; i++) { pMeshContainer->pMaterials[i].MatD3D = pMaterials[i].MatD3D; // do x suboru sa neexportuje udaj o ambient zlozke materialov, upravit podla potreby pMeshContainer->pMaterials[i].MatD3D.Ambient = D3DXCOLOR (1.0f, 1.0f, 1.0f, 1.0f); // vypnut Power ak nie je zadana Specular zlozka D3DCOLORVALUE &colorSpec = pMeshContainer->pMaterials[i].MatD3D.Specular; if ((colorSpec.r == 0) && (colorSpec.g == 0) && (colorSpec.b == 0)) pMeshContainer->pMaterials[i].MatD3D.Power = 0.0f; // nacitanie 7mt materialu, ak je k danemu povrchu priradeny #define MATERIAL_FLOAT_TOLERANCE 0.001f for (j=0; j < m_localData.dw7mtMaterialsNum; j++) if (m_localData.Mesh7mtMaterials[j].sz7mtMaterialName != NULL) { // porovnanie textur ak su dostupne if ((m_localData.Mesh7mtMaterials[j].szTextureName != NULL) && (pMaterials[i].pTextureFilename != NULL)) if (stricmp (m_localData.Mesh7mtMaterials[j].szTextureName, pMaterials[i].pTextureFilename) != 0) continue; // porovnanie materialov if (fabs (m_localData.Mesh7mtMaterials[j].material.rDif - pMaterials[i].MatD3D.Diffuse.r) > MATERIAL_FLOAT_TOLERANCE) continue; if (fabs (m_localData.Mesh7mtMaterials[j].material.gDif - pMaterials[i].MatD3D.Diffuse.g) > MATERIAL_FLOAT_TOLERANCE) continue; if (fabs (m_localData.Mesh7mtMaterials[j].material.bDif - pMaterials[i].MatD3D.Diffuse.b) > MATERIAL_FLOAT_TOLERANCE) continue; if (fabs (m_localData.Mesh7mtMaterials[j].material.aDif - pMaterials[i].MatD3D.Diffuse.a) > MATERIAL_FLOAT_TOLERANCE) continue; if (fabs (m_localData.Mesh7mtMaterials[j].material.rSpec - pMaterials[i].MatD3D.Specular.r) > MATERIAL_FLOAT_TOLERANCE) continue; if (fabs (m_localData.Mesh7mtMaterials[j].material.gSpec - pMaterials[i].MatD3D.Specular.g) > MATERIAL_FLOAT_TOLERANCE) continue; if (fabs (m_localData.Mesh7mtMaterials[j].material.bSpec - pMaterials[i].MatD3D.Specular.b) > MATERIAL_FLOAT_TOLERANCE) continue; if (fabs (m_localData.Mesh7mtMaterials[j].material.rEm - pMaterials[i].MatD3D.Emissive.r) > MATERIAL_FLOAT_TOLERANCE) continue; if (fabs (m_localData.Mesh7mtMaterials[j].material.gEm - pMaterials[i].MatD3D.Emissive.g) > MATERIAL_FLOAT_TOLERANCE) continue; if (fabs (m_localData.Mesh7mtMaterials[j].material.bEm - pMaterials[i].MatD3D.Emissive.b) > MATERIAL_FLOAT_TOLERANCE) continue; if (fabs (m_localData.Mesh7mtMaterials[j].material.specPower - pMaterials[i].MatD3D.Power) > MATERIAL_FLOAT_TOLERANCE) continue; // materialy su zhodne char szBuf[MAX_PATH] = "materials\\models\\"; strcat (szBuf, m_localData.Mesh7mtMaterials[j].sz7mtMaterialName); // 7mt material loading pMeshContainer->p7MTmaterials[i] = g_pMaterialManager->LoadMaterial (szBuf); break; } // ####################################################### // naèítanie textúr if ((pMaterials[i].pTextureFilename != NULL) && (pMaterials[i].pTextureFilename[0] != 0)) { char szTag[16]; ezxml_t pTextureTag = NULL; DWORD dwTextureIdx = 0xFFFFFFFF; pMeshContainer->pMaterials[i].pTextureFilename = new char [strlen (pMaterials[i].pTextureFilename) + 1]; strcpy (pMeshContainer->pMaterials[i].pTextureFilename, pMaterials[i].pTextureFilename); if (FindTextureIndexTagByName (m_localData.xmlTextures, pMaterials[i].pTextureFilename, dwTextureIdx)) { sprintf (szTag, "texture%u", dwTextureIdx); pTextureTag = g_pXML->Child (m_localData.xmlTextures, szTag); } for (j=0; j < pMeshContainer->dwNumCoords; j++) // pre jednotlive koordinaty { char szBuf[MAX_PATH] = "textures\\models\\"; if (pTextureTag == NULL) // pouzit texturu z x-suboru { strcat (szBuf, pMaterials[i].pTextureFilename); pMeshContainer->pTextures[ i * pMeshContainer->dwNumCoords * pMeshContainer->dwNumPaintings + j*pMeshContainer->dwNumPaintings + m_localData.dwUseThisPainting] = g_TextureLoader.CreateTexture (szBuf); } else { // ziskanie nazvu textury z xml suboru ezxml_t pCoordsTag, pPaintingTag; sprintf (szTag, "coords%u", j); if (pCoordsTag = g_pXML->Child (pTextureTag, szTag)) { sprintf (szTag, "painting%u", m_localData.dwUseThisPainting); if (pPaintingTag = g_pXML->Child (pCoordsTag, szTag)) if (pPaintingTag->txt) { strcat (szBuf, pPaintingTag->txt); pMeshContainer->pTextures[ i * pMeshContainer->dwNumCoords * pMeshContainer->dwNumPaintings + j*pMeshContainer->dwNumPaintings + m_localData.dwUseThisPainting] = g_TextureLoader.CreateTexture (szBuf); } } } } } } } else // nastavenie defaultneho materialu - Diffuse = 0.8, Specular = Emissive = 0.0, Ambient = 1.0 { pMeshContainer->pMaterials[0].pTextureFilename = NULL; pMeshContainer->pMaterials[0].MatD3D.Ambient = D3DXCOLOR (1.0f, 1.0f, 1.0f, 1.0f); pMeshContainer->pMaterials[0].MatD3D.Diffuse = D3DXCOLOR (0.8f, 0.8f, 0.8f, 1.0f); pMeshContainer->pMaterials[0].MatD3D.Emissive = D3DXCOLOR (0.0f, 0.0f, 0.0f, 1.0f); pMeshContainer->pMaterials[0].MatD3D.Specular = pMeshContainer->pMaterials[0].MatD3D.Emissive; pMeshContainer->pMaterials[0].MatD3D.Power = 0.0f; } /* // alokovanie pamäte pre materiály, textúry pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials]; pMeshContainer->pTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials]; if ((pMeshContainer->pMaterials == NULL) || (pMeshContainer->pTextures == NULL)) {hr = E_OUTOFMEMORY; goto e_Exit;} //inicializácia textúr a materiálov memset(pMeshContainer->pTextures, 0, sizeof(LPDIRECT3DTEXTURE9) * pMeshContainer->NumMaterials); memset(pMeshContainer->pMaterials, 0, sizeof(D3DXMATERIAL) * pMeshContainer->NumMaterials); //ak sú dostupné materiály, tak sa kopírujú if (NumMaterials > 0) { for (UINT iMaterial = 0; iMaterial < NumMaterials; iMaterial++) { pMeshContainer->pMaterials[iMaterial].MatD3D = pMaterials[iMaterial].MatD3D; pMeshContainer->pMaterials[iMaterial].MatD3D.Ambient = D3DXCOLOR (1.0f, 1.0f, 1.0f, 1.0f); D3DCOLORVALUE &colorSpec = pMeshContainer->pMaterials[iMaterial].MatD3D.Specular; if ((colorSpec.r == 0) && (colorSpec.g == 0) && (colorSpec.b == 0)) pMeshContainer->pMaterials[iMaterial].MatD3D.Power = 0.0f; if (pMaterials[iMaterial].pTextureFilename != NULL) { wsprintf (szBuf, "textures\\models\\%s", pMaterials[iMaterial].pTextureFilename); pMeshContainer->pTextures[iMaterial] = g_TextureLoader.CreateTexture (szBuf); } } } else // ak nie je definovany žiaden materiál, potom sa nastavý defaultný { //Diffuse = Specular = 0.8, Ambient = 1.0 pMeshContainer->pMaterials[0].pTextureFilename = NULL; pMeshContainer->pMaterials[0].MatD3D.Ambient = D3DXCOLOR (1.0f, 1.0f, 1.0f, 1.0f); pMeshContainer->pMaterials[0].MatD3D.Diffuse = D3DXCOLOR (0.8f, 0.8f, 0.8f, 1.0f); pMeshContainer->pMaterials[0].MatD3D.Emissive = D3DXCOLOR (0.0f, 0.0f, 0.0f, 1.0f); pMeshContainer->pMaterials[0].MatD3D.Specular = pMeshContainer->pMaterials[0].MatD3D.Diffuse; pMeshContainer->pMaterials[0].MatD3D.Power = 5.0f; } */ ////////////////////////////////////////////////////////////////////////// // nacitanie skin infa if (m_localData.bLoadSkinInfo && (pSkinInfo != NULL)) { DWORD dwNumBones; pMeshContainer->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); // alokovanie pamate pre skin-info matice dwNumBones = pSkinInfo->GetNumBones(); if (dwNumBones > 0) { pMeshContainer->pBoneInverseMatrices = new D3DXMATRIX[dwNumBones]; pMeshContainer->ppBoneTransformMatrices = new D3DXMATRIX*[dwNumBones]; if ((pMeshContainer->pBoneInverseMatrices == NULL) || \ (pMeshContainer->ppBoneTransformMatrices == NULL)) {hr = E_OUTOFMEMORY; goto e_Exit;} // nacitanie bone-offset matic for (DWORD iBone=0; iBone < dwNumBones; iBone++) pMeshContainer->pBoneInverseMatrices[iBone] = *(pSkinInfo->GetBoneOffsetMatrix(iBone)); memset (pMeshContainer->ppBoneTransformMatrices, 0, sizeof(LPD3DXMATRIX) * dwNumBones); } ////////////////////////////////////////////////////////////////////////// // upravy pre shader skinning pMeshContainer->NumPaletteEntries = min(MAX_SKIN_BONES, pMeshContainer->pSkinInfo->GetNumBones()); if (FAILED (pMeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh ( pMesh, D3DXMESH_MANAGED | D3DXMESHOPT_VERTEXCACHE, pMeshContainer->NumPaletteEntries, pAdjacency, NULL, NULL, NULL, &pMeshContainer->NumInfl, &pMeshContainer->NumAttributeGroups, &pMeshContainer->pBoneCombinationBuf, &pTempMesh))) goto e_Exit; pMesh->Release (); pMesh = pTempMesh; pTempMesh = NULL; } ////////////////////////////////////////////////////////////////////////// // optimalizacia #ifdef MAKE_MESH_OPTIMIZATION if (pAdjacency) { // pMesh->GenerateAdjacency () // ??? pMesh->OptimizeInplace ( \ D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, \ pAdjacency, NULL, NULL, NULL); } #endif ////////////////////////////////////////////////////////////////////////// pMeshContainer->MeshData.pMesh = pMesh; pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; *ppNewMeshContainer = pMeshContainer; return S_OK; e_Exit: pMesh->Release (); SAFE_DELETE (pMeshContainer) return hr; }
HRESULT BoneHierarchyLoader::CreateMeshContainer(LPCSTR Name, CONST D3DXMESHDATA *pMeshData, CONST D3DXMATERIAL *pMaterials, CONST D3DXEFFECTINSTANCE *pEffectInstances, DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppNewMeshContainer) { //Create new Bone Mesh BoneMesh *boneMesh = new BoneMesh; memset(boneMesh, 0, sizeof(BoneMesh)); //Get mesh data boneMesh->OriginalMesh = pMeshData->pMesh; boneMesh->MeshData.pMesh = pMeshData->pMesh; boneMesh->MeshData.Type = pMeshData->Type; pMeshData->pMesh->AddRef(); //Add Reference so that the mesh isnt deallocated IDirect3DDevice9 *g_pDevice = NULL; pMeshData->pMesh->GetDevice(&g_pDevice); //Get g_pDevice ptr from mesh //Copy materials and load textures (just like with a static mesh) for (int i=0; i<(int)NumMaterials; i++) { D3DXMATERIAL mtrl; memcpy(&mtrl, &pMaterials[i], sizeof(D3DXMATERIAL)); boneMesh->materials.push_back(mtrl.MatD3D); IDirect3DTexture9* newTexture = NULL; if (mtrl.pTextureFilename != NULL) { char textureFname[200]; strcpy(textureFname, "resources/meshes/"); strcat(textureFname, mtrl.pTextureFilename); //Load texture D3DXCreateTextureFromFile(g_pDevice, textureFname, &newTexture); } boneMesh->textures.push_back(newTexture); } if (pSkinInfo != NULL) { //Get Skin Info boneMesh->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); //Add reference so that the SkinInfo isnt deallocated //Clone mesh and store in boneMesh->MeshData.pMesh pMeshData->pMesh->CloneMeshFVF(D3DXMESH_MANAGED, pMeshData->pMesh->GetFVF(), g_pDevice, &boneMesh->MeshData.pMesh); //Get Attribute Table boneMesh->MeshData.pMesh->GetAttributeTable(NULL, &boneMesh->NumAttributeGroups); boneMesh->attributeTable = new D3DXATTRIBUTERANGE[boneMesh->NumAttributeGroups]; boneMesh->MeshData.pMesh->GetAttributeTable(boneMesh->attributeTable, NULL); //Create bone offset and current matrices int NumBones = pSkinInfo->GetNumBones(); boneMesh->boneOffsetMatrices = new D3DXMATRIX[NumBones]; boneMesh->currentBoneMatrices = new D3DXMATRIX[NumBones]; //Get bone offset matrices for (int i=0; i < NumBones; i++) boneMesh->boneOffsetMatrices[i] = *(boneMesh->pSkinInfo->GetBoneOffsetMatrix(i)); } //Set ppNewMeshContainer to the newly created boneMesh container *ppNewMeshContainer = boneMesh; return S_OK; }
//==================================================================================== // メッシュコンテナの作成(XFileの各パーツの集合)ようはスキンメッシュモデルをここで作る //==================================================================================== HRESULT CInheritanceHierarchy::CreateMeshContainer(LPCSTR Name, CONST D3DXMESHDATA* pMeshData, CONST D3DXMATERIAL* pMaterials, CONST D3DXEFFECTINSTANCE* pEffectInstances, DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppMeshContainer ) { //======================================================================== // コンテナ作成に当たって必要な変数を用意 //======================================================================== MYMESHCONTAINER *pMeshContainer = NULL; int iFacesAmount; DWORD iMaterial; LPDIRECT3DDEVICE9 pDevice = NULL; LPD3DXMESH pMesh = NULL; *ppMeshContainer = NULL; DWORD dwBoneNum=0; //======================================================================== // コンテナを動的確保して値を入れていく作業へ //======================================================================== pMesh = pMeshData->pMesh; pMeshContainer = new MYMESHCONTAINER; //メモリ不足のときは終了 if (pMeshContainer == NULL) { return E_OUTOFMEMORY; } //作成に成功したら中身を0で初期化しておく ZeroMemory(pMeshContainer, sizeof(MYMESHCONTAINER)); //メッシュコンテナとしてXFileでつけられてる名前を拾う pMeshContainer->Name=new TCHAR[lstrlen(Name) + 1]; // \0分の+1 //名前がなかったらおかしいので終了 if (!pMeshContainer->Name) { return E_FAIL; } //名前があるならそれにする strcpy(pMeshContainer->Name,Name); // デバイスゲット pMesh->GetDevice(&pDevice); // 面の数ゲット iFacesAmount = pMesh->GetNumFaces(); pMeshContainer->MeshData.pMesh = pMesh; pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; //通常メッシュの場合はこれが必要。スキンの場合、これをするとメモリリークになる。 if (pSkinInfo == NULL) { pMesh->AddRef(); } //メッシュのマテリアル設定 pMeshContainer->NumMaterials = max(1, NumMaterials); pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials]; pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials]; pMeshContainer->pAdjacency = new DWORD[iFacesAmount * NUM_POLYGON_CREATE_TRIANGLE]; //隣接性情報またはマテリアルがなければ終了 if( pMeshContainer->pAdjacency == NULL || pMeshContainer->pMaterials == NULL ) { return E_FAIL; } //情報をメッシュコンテナに流し込む memcpy(pMeshContainer->pAdjacency, pAdjacency, sizeof(DWORD) * iFacesAmount * NUM_POLYGON_CREATE_TRIANGLE); memset(pMeshContainer->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) * pMeshContainer->NumMaterials); //======================================================================== //該当メッシュがスキン情報を持っている場合 //======================================================================== if (pSkinInfo != NULL) { pMeshContainer->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); dwBoneNum = pSkinInfo->GetNumBones(); pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[dwBoneNum]; for (DWORD i = 0; i < dwBoneNum; i++) { memcpy(&pMeshContainer->pBoneOffsetMatrices[i], pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(i), sizeof(D3DMATRIX)); } // インデックスつきのものに変換 シェーダー使わないやつとは別なので注意 if (FAILED(pMeshContainer->pSkinInfo->ConvertToIndexedBlendedMesh(pMesh, NULL, dwBoneNum, pMeshContainer->pAdjacency, NULL, NULL, NULL, &pMeshContainer->dwWeight, &pMeshContainer->dwBoneNum, &pMeshContainer->pBoneBuffer, &pMeshContainer->MeshData.pMesh))) { return E_FAIL; } // コンバート ConvertMesh(&pMeshContainer->MeshData.pMesh); D3DVERTEXELEMENT9 elements[] = { // 頂点ストリーム(パイプライン)番号, オフセット(頂点の型の先頭からのバイト数), データ型, DEFAULTでOK, 使用用途, 使用用途が同じものを複数使うときに仕分ける番号 { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0 }, { 0, 24, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDINDICES, 0 }, { 0, 28, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }, { 0, 40, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, { 0, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, D3DDECL_END() // 定義終了 絶対必要 }; pMeshContainer->pSkinInfo->SetDeclaration(elements); } //======================================================================== // モデルのマテリアル情報 //======================================================================== if (NumMaterials > 0) { memcpy(pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL) * NumMaterials); for (iMaterial = 0; iMaterial < NumMaterials; iMaterial++) { // マテリアルのディフーズ色を強制的に変更 pMeshContainer->pMaterials[iMaterial].MatD3D.Diffuse = DEFAULT_POLYGON_COLOR; if (pMeshContainer->pMaterials[iMaterial].pTextureFilename != NULL) { TCHAR strTexturePath[MAX_PATH]; strcpy( strTexturePath,TEX_FOLDER_PATH); strcat_s( strTexturePath, sizeof( char ) * MAX_LENGTH_FILE_PATH, pMeshContainer->pMaterials[iMaterial].pTextureFilename ); if (FAILED(D3DXCreateTextureFromFile(pDevice, 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 = COLOR_OF_NOT_EXIST_MATERIAL.r; pMeshContainer->pMaterials[0].MatD3D.Diffuse.g = COLOR_OF_NOT_EXIST_MATERIAL.g; pMeshContainer->pMaterials[0].MatD3D.Diffuse.b = COLOR_OF_NOT_EXIST_MATERIAL.b; pMeshContainer->pMaterials[0].MatD3D.Specular = pMeshContainer->pMaterials[0].MatD3D.Diffuse; } //ローカルに生成したメッシュコンテナーを呼び出し側にコピーする (コピーじゃないけど・・・) *ppMeshContainer = pMeshContainer; //参照カウンタを増やしたので減らす SAFE_RELEASE(pDevice); return S_OK; }
/** * \brief callback called when a mesh data is encountered during the .x file load * \param Name - name of the Mesh (const char*) * \param meshData - the mesh data * \param materials - material array * \param effectInstances - effect files / settings for the mesh * \param numMaterials - number of materials in the mesh * \param adjacency - adjacency array * \param pSkinInfo - skin info. * \param retNewMeshContainer - output pointer to assign our newly created mesh container * \return success code * \author Keith Ditchburn \date 17 July 2005 */ HRESULT CMeshHierarchy::CreateMeshContainer( LPCSTR Name, CONST D3DXMESHDATA *meshData, CONST D3DXMATERIAL *materials, CONST D3DXEFFECTINSTANCE *effectInstances, DWORD numMaterials, CONST DWORD *adjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER* retNewMeshContainer) { // Create a mesh container structure to fill and initilaise to zero values // Note: I use my extended version of the structure (D3DXMESHCONTAINER_EXTENDED) defined in MeshStructures.h D3DXMESHCONTAINER_EXTENDED *newMeshContainer=new D3DXMESHCONTAINER_EXTENDED; ZeroMemory(newMeshContainer, sizeof(D3DXMESHCONTAINER_EXTENDED)); // Always a good idea to initialise return pointer before proceeding *retNewMeshContainer = 0; // The mesh name (may be 0) needs copying over if (Name && strlen(Name)) { newMeshContainer->Name=CUtility::DuplicateCharString(Name); CUtility::DebugString("Added mesh: "+ToString(Name)+"\n"); } else { CUtility::DebugString("Added Mesh: no name given\n"); } // The mesh type (D3DXMESHTYPE_MESH, D3DXMESHTYPE_PMESH or D3DXMESHTYPE_PATCHMESH) if (meshData->Type!=D3DXMESHTYPE_MESH) { // This demo does not handle mesh types other than the standard // Other types are D3DXMESHTYPE_PMESH (progressive mesh) and D3DXMESHTYPE_PATCHMESH (patch mesh) DestroyMeshContainer(newMeshContainer); return E_FAIL; } newMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; // Adjacency data - holds information about triangle adjacency, required by the ID3DMESH object DWORD dwFaces = meshData->pMesh->GetNumFaces(); newMeshContainer->pAdjacency = new DWORD[dwFaces*3]; memcpy(newMeshContainer->pAdjacency, adjacency, sizeof(DWORD) * dwFaces*3); // Get the Direct3D device, luckily this is held in the mesh itself (Note: must release it when done with it) LPDIRECT3DDEVICE9 pd3dDevice = 0; meshData->pMesh->GetDevice(&pd3dDevice); D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE]; meshData->pMesh->GetDeclaration(decl); HRESULT res; DWORD dwVertexStride = meshData->pMesh->GetNumBytesPerVertex (); DWORD dwNumDeclarations = 0; bool haveNormals = false; for (int i=0; (i < MAX_FVF_DECL_SIZE) && (decl[i].Stream != 0xFF); i++) { if (decl[dwNumDeclarations].Usage == D3DDECLUSAGE_NORMAL) haveNormals = true; if (decl[dwNumDeclarations].Usage == D3DDECLUSAGE_TANGENT) { dwNumDeclarations = 0; break; } dwNumDeclarations++; } if (dwNumDeclarations) { if (!haveNormals) { // normals decl[dwNumDeclarations].Stream = 0; decl[dwNumDeclarations].Offset = (WORD)dwVertexStride; decl[dwNumDeclarations].Type = D3DDECLTYPE_FLOAT3; decl[dwNumDeclarations].Method = D3DDECLMETHOD_DEFAULT; decl[dwNumDeclarations].Usage = D3DDECLUSAGE_NORMAL; decl[dwNumDeclarations].UsageIndex = 0; dwVertexStride += sizeof(float)*3; dwNumDeclarations++; } // tangent decl[dwNumDeclarations].Stream = 0; decl[dwNumDeclarations].Offset = (WORD)dwVertexStride; decl[dwNumDeclarations].Type = D3DDECLTYPE_FLOAT3; decl[dwNumDeclarations].Method = D3DDECLMETHOD_DEFAULT; decl[dwNumDeclarations].Usage = D3DDECLUSAGE_TANGENT; decl[dwNumDeclarations].UsageIndex = 0; dwNumDeclarations++; // ending element memset (&decl[dwNumDeclarations], 0, sizeof(D3DVERTEXELEMENT9)); decl[dwNumDeclarations].Stream = 0xFF; decl[dwNumDeclarations].Type = D3DDECLTYPE_UNUSED; } res = meshData->pMesh->CloneMesh(meshData->pMesh->GetOptions(),decl,pd3dDevice,&newMeshContainer->MeshData.pMesh); assert(res == D3D_OK); if (!haveNormals) { res = D3DXComputeNormals(newMeshContainer->MeshData.pMesh,newMeshContainer->pAdjacency); // compute normals assert(res == D3D_OK); } res = D3DXComputeTangent(newMeshContainer->MeshData.pMesh,0,0,1,TRUE,NULL); // compute tangent(u) assert(res == D3D_OK); //newMeshContainer->MeshData.pMesh=meshData->pMesh; newMeshContainer->MeshData.pMesh->AddRef(); // Create material and texture arrays. Note that I always want to have at least one newMeshContainer->NumMaterials = max(numMaterials,1); newMeshContainer->exMaterials = new D3DMATERIAL9[newMeshContainer->NumMaterials]; newMeshContainer->exTextures = new LPDIRECT3DTEXTURE9[newMeshContainer->NumMaterials]; ZeroMemory(newMeshContainer->exTextures, sizeof(LPDIRECT3DTEXTURE9) * newMeshContainer->NumMaterials); if (numMaterials>0) { // Load all the textures and copy the materials over for(DWORD i = 0; i < numMaterials; ++i) { newMeshContainer->exTextures[i] = 0; newMeshContainer->exMaterials[i]=materials[i].MatD3D; if(materials[i].pTextureFilename) { std::string texturePath(materials[i].pTextureFilename); if (CUtility::FindFile(&texturePath)) { // Use the D3DX function to load the texture if(FAILED(D3DXCreateTextureFromFile(pd3dDevice, texturePath.c_str(), &newMeshContainer->exTextures[i]))) { CUtility::DebugString("Could not load texture: "+texturePath+"\n"); } } else { CUtility::DebugString("Could not find texture: "+ToString(materials[i].pTextureFilename)+"\n"); } } } } else // make a default material in the case where the mesh did not provide one { ZeroMemory(&newMeshContainer->exMaterials[0], sizeof( D3DMATERIAL9 ) ); newMeshContainer->exMaterials[0].Diffuse.r = 0.5f; newMeshContainer->exMaterials[0].Diffuse.g = 0.5f; newMeshContainer->exMaterials[0].Diffuse.b = 0.5f; newMeshContainer->exMaterials[0].Specular = newMeshContainer->exMaterials[0].Diffuse; newMeshContainer->exTextures[0]=0; } // If there is skin data associated with the mesh copy it over if (pSkinInfo) { // save off the SkinInfo newMeshContainer->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); // Need an array of offset matrices to move the vertices from the figure space to the bone's space UINT numBones = pSkinInfo->GetNumBones(); newMeshContainer->exBoneOffsets = new D3DXMATRIX[numBones]; // Create the arrays for the bones and the frame matrices newMeshContainer->exFrameCombinedMatrixPointer = new D3DXMATRIX*[numBones]; // get each of the bone offset matrices so that we don't need to get them later for (UINT i = 0; i < numBones; i++) newMeshContainer->exBoneOffsets[i] = *(newMeshContainer->pSkinInfo->GetBoneOffsetMatrix(i)); CUtility::DebugString("Mesh has skinning info.\n Number of bones is: "+ToString(numBones)+"\n"); // Note: in the Microsoft samples a GenerateSkinnedMesh function is called here in order to prepare // the skinned mesh data for optimial hardware acceleration. As mentioned in the notes this sample // does not do hardware skinning but instead uses software skinning. } else { // No skin info so 0 all the pointers newMeshContainer->pSkinInfo = 0; newMeshContainer->exBoneOffsets = 0; newMeshContainer->exSkinMesh = 0; newMeshContainer->exFrameCombinedMatrixPointer = 0; } // When we got the device we caused an internal reference count to be incremented // So we now need to release it pd3dDevice->Release(); // The mesh may contain a reference to an effect file if (effectInstances) { if (effectInstances->pEffectFilename) CUtility::DebugString("This .x file references an effect file. Effect files are not handled by this demo\n"); } // Set the output mesh container pointer to our newly created one *retNewMeshContainer = newMeshContainer; return S_OK; }
//====================================================================== // <<<メッシュ コンテナ オブジェクトの割り当て要求の実装>>> // Name : [in] メッシュの名前 // pMeshData : [in] メッシュデータ構造体へのポインタ // pMaterials : [in] メッシュに使うマテリアルの配列 // pEffectInstances : [in] メッシュに使うエフェクトインスタンスの配列 // NumMaterials : [in] マテリアル配列内のマテリアルの数 // pAdjacency : [in] メッシュの隣接性配列 // pSkinInfo : [in] スキンデータが見つかった場合のスキンメッシュオブジェクトへのポインタ // ppNewMeshContainer : [out, retval] 作成されたメッシュコンテナを返す //====================================================================== 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 = S_OK; *ppNewMeshContainer = NULL; // patch meshes を扱う事はできない if( pMeshData->Type != D3DXMESHTYPE_MESH ) { return E_FAIL; } LPD3DXMESH pMesh = pMeshData->pMesh; // FVF で記述されたメッシュ以外は読めぬ if( pMesh->GetFVF() == 0 ) { return E_FAIL; } UINT NumFaces = pMesh->GetNumFaces(); // メッシュ作成 CXMesh *pCXMesh = NULL; try { pCXMesh = new CXMesh; } catch ( std::bad_alloc& ) { // メモリが足りない return E_OUTOFMEMORY; } // 名前設定 pCXMesh->SetName( Name ); // メッシュタイプ設定 pCXMesh->MeshData.Type = D3DXMESHTYPE_MESH; LPDIRECT3DDEVICE9 pD3DDevice = NULL; // デバイスを取得 if( FAILED( pMesh->GetDevice( &pD3DDevice ) ) ) { hr = E_FAIL; goto e_Exit; } // Xファイルに法線が無かったら計算で求める if( !( pMesh->GetFVF() & D3DFVF_NORMAL ) ) { ////FVFに法線を追加した新しいメッシュにする//// hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), pMesh->GetFVF() | D3DFVF_NORMAL, pD3DDevice, &pCXMesh->MeshData.pMesh ); if( FAILED( hr ) ) { goto e_Exit; } // 引数で渡されたメッシュへのポインタに新しいメッシュへのポインタをセット // pMeshへの参照はこの時点で存在しないので、ここではreleaseをかけない pMesh = pCXMesh->MeshData.pMesh; D3DXComputeNormals( pMesh, NULL ); } // 法線があった else { // リファレンスを増やすだけ pCXMesh->MeshData.pMesh = pMesh; pMesh->AddRef(); } // マテリアル用のメモリを確保 pCXMesh->NumMaterials = max( 1, NumMaterials ); try { pCXMesh->pMaterials = new D3DXMATERIAL[pCXMesh->NumMaterials]; pCXMesh->m_ppTextures = new LPDIRECT3DTEXTURE9[pCXMesh->NumMaterials]; pCXMesh->pAdjacency = new DWORD[NumFaces * 3]; } catch ( std::bad_alloc& ) { // メモリが足りない goto e_Exit; } memcpy( pCXMesh->pAdjacency, pAdjacency, sizeof( DWORD ) * NumFaces * 3 ); memset( pCXMesh->m_ppTextures, 0, sizeof( LPDIRECT3DTEXTURE9 ) * pCXMesh->NumMaterials ); // マテリアルのコピー if( NumMaterials > 0 ) { memcpy( pCXMesh->pMaterials, pMaterials, sizeof( D3DXMATERIAL ) * NumMaterials ); for( UINT i=0; i<NumMaterials; i++ ) { if( pCXMesh->pMaterials[i].pTextureFilename != NULL ) { // テクスチャを読み込む if( FAILED( D3DXCreateTextureFromFileEx( pD3DDevice, pCXMesh->pMaterials[i].pTextureFilename, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DUSAGE_RENDERTARGET, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, m_KeyColor, NULL, NULL, &pCXMesh->m_ppTextures[i] ) ) ) { // 読み込み失敗 pCXMesh->m_ppTextures[i] = NULL; } pD3DDevice->SetTexture(0, pCXMesh->m_ppTextures[i]); pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, true); pD3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER); pD3DDevice->SetRenderState(D3DRS_ALPHAREF, 8); } } } // マテリアルが無いので適当にセット else { pCXMesh->pMaterials[0].pTextureFilename = NULL; memset( &pCXMesh->pMaterials[0].MatD3D, 0, sizeof( D3DMATERIAL9 ) ); pCXMesh->pMaterials[0].MatD3D.Diffuse.r = 0.5f; pCXMesh->pMaterials[0].MatD3D.Diffuse.g = 0.5f; pCXMesh->pMaterials[0].MatD3D.Diffuse.b = 0.5f; pCXMesh->pMaterials[0].MatD3D.Specular = pCXMesh->pMaterials[0].MatD3D.Diffuse; } // ワンスキン形式のXファイルだった時の処理 if( pSkinInfo != NULL ) { /* スキンメッシュ用の処理*/ /*pSkinInfo と pMesh をセット*/ pCXMesh->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); pCXMesh->m_pOrigMesh = pMesh; pMesh->AddRef(); /* Bone Offset Matrices 保存用のメモリを確保*/ UINT NumBones = pSkinInfo->GetNumBones(); try { pCXMesh->m_pBoneOffsetMatrices = new D3DXMATRIX[NumBones]; } catch ( std::bad_alloc& ) { // メモリが足りない goto e_Exit; } /*Bone Offset Matrices 読み込み*/ for( UINT i = 0; i < NumBones; i++ ) { //memcpy(&pCXMesh->m_pBoneOffsetMatrices[i], pCXMesh->pSkinInfo->GetBoneOffsetMatrix(i), sizeof(D3DMATRIX) ); pCXMesh->m_pBoneOffsetMatrices[i] = *(pCXMesh->pSkinInfo->GetBoneOffsetMatrix( i ) ); } // ジェネレート処理 hr = m_pModel->GenerateSkinnedMesh( m_pD3DX9, pCXMesh, m_MaxBlend ); if( FAILED( hr ) ) { goto e_Exit; } } // メッシュコンテナの割り当て。 // CXMeshクラスは D3DXMESHCONTAINER を継承している *ppNewMeshContainer = pCXMesh; pCXMesh = NULL; e_Exit: // 開放処理 F_RELEASE( pD3DDevice ); if( pCXMesh != NULL ) { DestroyMeshContainer( pCXMesh ); } return hr; }
HRESULT CD3DAllocate::CreateMeshContainer(THIS_ LPCSTR name, CONST D3DXMESHDATA *mesh, CONST D3DXMATERIAL *mats, CONST D3DXEFFECTINSTANCE *effects, unsigned long numMats, CONST unsigned long *indices, LPD3DXSKININFO skin, LPD3DXMESHCONTAINER* outContainer) { stD3DContainerEx *meshCon = new stD3DContainerEx; ZeroMemory(meshCon, sizeof(stD3DContainerEx)); *outContainer = NULL; meshCon->Name = NULL; if(name) { int len = strlen(name) + 1; meshCon->Name = new char[len]; memcpy(meshCon->Name, name, len * sizeof(char)); } if(mesh->Type != D3DXMESHTYPE_MESH) { // D3DXMESHTYPE_PMESH are progressive meshes. // D3DXMESHTYPE_PATCHMESH are patch meshes. // In this code we only handle normal meshes. DestroyMeshContainer(meshCon); return E_FAIL; } meshCon->MeshData.Type = D3DXMESHTYPE_MESH; // Copy indices. unsigned long numFaces = mesh->pMesh->GetNumFaces(); meshCon->pAdjacency = new unsigned long[numFaces * 3]; memcpy(meshCon->pAdjacency, indices, sizeof(unsigned long) * numFaces * 3); // Get D3D Device. LPDIRECT3DDEVICE9 d3dDevice = NULL; mesh->pMesh->GetDevice(&d3dDevice); // Get mesh's declaration. D3DVERTEXELEMENT9 elements[MAX_FVF_DECL_SIZE]; if(FAILED(mesh->pMesh->GetDeclaration(elements))) return E_FAIL; // Clone mesh to get copy of mesh. mesh->pMesh->CloneMesh(D3DXMESH_MANAGED, elements, d3dDevice, &meshCon->MeshData.pMesh); // Allocate materials and textures. meshCon->NumMaterials = max(numMats, 1); meshCon->mat = new D3DMATERIAL9[meshCon->NumMaterials]; meshCon->textures = new LPDIRECT3DTEXTURE9[meshCon->NumMaterials]; ZeroMemory(meshCon->mat, sizeof(D3DMATERIAL9) * meshCon->NumMaterials); ZeroMemory(meshCon->textures, sizeof(LPDIRECT3DTEXTURE9) * meshCon->NumMaterials); if(numMats > 0) { // If any materials get them and any textures. for(unsigned long i = 0; i < numMats; ++i) { meshCon->textures[i] = NULL; meshCon->mat[i] = mats[i].MatD3D; if(mats[i].pTextureFilename) { if(FAILED(D3DXCreateTextureFromFile(d3dDevice, mats[i].pTextureFilename, &meshCon->textures[i]))) meshCon->textures[i] = NULL; } } } else { // Set to default material and null texture. ZeroMemory(&meshCon->mat[0], sizeof(D3DMATERIAL9)); meshCon->mat[0].Diffuse.r = 0.5f; meshCon->mat[0].Diffuse.g = 0.5f; meshCon->mat[0].Diffuse.b = 0.5f; meshCon->mat[0].Specular = meshCon->mat[0].Diffuse; meshCon->textures[0] = NULL; } // Nullify. meshCon->pSkinInfo = NULL; meshCon->boneMatrices = NULL; if(skin) { // If skin mesh allocate and get bones. meshCon->pSkinInfo = skin; skin->AddRef(); unsigned int numBones = skin->GetNumBones(); meshCon->boneMatrices = new D3DXMATRIX*[numBones]; } // Release reference count. if(d3dDevice) d3dDevice->Release(); d3dDevice = NULL; *outContainer = meshCon; return S_OK; }
HRESULT BoneHierarchyLoader::CreateMeshContainer( LPCSTR Name, CONST D3DXMESHDATA *pMeshData, CONST D3DXMATERIAL *pMaterials, CONST D3DXEFFECTINSTANCE *pEffectInstances, DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppNewMeshContainer ) { BoneMesh* boneMesh = new BoneMesh(); // 메시 데이터를 얻는다. // 소프트웨어 스키닝을 위해서는 메시의 원본 형태의 데이터를 보관해두어야한다. boneMesh->_originalMesh = pMeshData->pMesh; boneMesh->MeshData.pMesh = pMeshData->pMesh; boneMesh->MeshData.Type = pMeshData->Type; // 메시의 메모리가 해제되지 않도록 참조값을 증가시킨다 pMeshData->pMesh->AddRef(); LPDIRECT3DDEVICE9 device = nullptr; pMeshData->pMesh->GetDevice( &device ); // materials, texture for (int i = 0; i < NumMaterials; i++) { D3DXMATERIAL mtrl; memcpy(&mtrl, &pMaterials[i], sizeof(D3DXMATERIAL)); boneMesh->_materials.push_back(mtrl.MatD3D); /*IDirect3DTexture9* newTexture = nullptr; if (mtrl.pTextureFilename != nullptr) { char texFileName[200] = ""; strcat(texFileName, mtrl.pTextureFilename); D3DXCreateTextureFromFile(device, texFileName, &newTexture); } boneMesh->_textures.push_back(newTexture);*/ } if (pSkinInfo != nullptr) { boneMesh->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); pMeshData->pMesh->CloneMeshFVF( D3DXMESH_MANAGED, pMeshData->pMesh->GetFVF(), device, &boneMesh->MeshData.pMesh ); boneMesh->MeshData.pMesh->GetAttributeTable( nullptr, &boneMesh->_numAttributeGroups ); boneMesh->_attributeTable = new D3DXATTRIBUTERANGE[ boneMesh->_numAttributeGroups ]; boneMesh->MeshData.pMesh->GetAttributeTable( boneMesh->_attributeTable, nullptr ); int numBones = pSkinInfo->GetNumBones(); boneMesh->_boneOffsetMatrices = new D3DXMATRIX[ numBones ]; boneMesh->_currentBoneMatrices = new D3DXMATRIX[ numBones ]; for (int i = 0; i < numBones; i++) { boneMesh->_boneOffsetMatrices[ i ] = *(boneMesh->pSkinInfo->GetBoneOffsetMatrix( i )); } } *ppNewMeshContainer = boneMesh; return S_OK; }
//ボーンの生成 HRESULT Dx_Hierarchy::CreateBone(DxMeshContainer *pMeshContainer,LPDIRECT3DDEVICE9 lpD3DDev) { DWORD dwBoneAmt=0; LPD3DXSKININFO pSkinInfo = pMeshContainer->pSkinInfo; pMeshContainer->lpMesh = pMeshContainer->MeshData.pMesh; pMeshContainer->MeshData.pMesh->AddRef(); // Bone Offset Matrices 保存用のメモリを確保 dwBoneAmt = pSkinInfo->GetNumBones(); pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[dwBoneAmt]; if( !pMeshContainer->pBoneOffsetMatrices ) return E_OUTOFMEMORY; // Bone Offset Matrices 読み込み for (DWORD i= 0; i < dwBoneAmt; i++){ memcpy(&pMeshContainer->pBoneOffsetMatrices[i], pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(i),sizeof(D3DMATRIX)); } HRESULT hr = S_OK; //スキン情報がないなら終了 if( !pMeshContainer->pSkinInfo ) return hr; //初期化しておく if(pMeshContainer->MeshData.pMesh) SAFE_RELEASE( pMeshContainer->MeshData.pMesh ); if(pMeshContainer->pBoneCombinationBuf) SAFE_RELEASE( pMeshContainer->pBoneCombinationBuf ); hr = pMeshContainer->lpMesh->CloneMeshFVF( D3DXMESH_MANAGED, pMeshContainer->lpMesh->GetFVF(), lpD3DDev , &pMeshContainer->MeshData.pMesh ); if( FAILED( hr ) ) return hr; //メッシュコンテナに所属している頂点数の取得 hr = pMeshContainer->MeshData.pMesh->GetAttributeTable( NULL, &pMeshContainer->NumAttributeGroups ); if( FAILED( hr ) ) return hr; //メッシュコンテナに所属している頂点情報の格納 delete[] pMeshContainer->pAttributeTable; pMeshContainer->pAttributeTable = new D3DXATTRIBUTERANGE[pMeshContainer->NumAttributeGroups]; if( !pMeshContainer->pAttributeTable ){ hr = E_OUTOFMEMORY; return hr; } hr = pMeshContainer->MeshData.pMesh->GetAttributeTable(pMeshContainer->pAttributeTable, NULL ); if( FAILED( hr ) ) return hr; // 他のメッシュによってボーン行列用のメモリが確保しきれていない場合は確保 if( pMeshContainer->NumBoneMatricesMax < pMeshContainer->pSkinInfo->GetNumBones() ){ pMeshContainer->NumBoneMatricesMax = pMeshContainer->pSkinInfo->GetNumBones(); delete []pMeshContainer->pBoneMatrices; pMeshContainer->pBoneMatrices = new D3DXMATRIXA16[pMeshContainer->NumBoneMatricesMax]; if( !pMeshContainer->pBoneMatrices ){ hr = E_OUTOFMEMORY; return hr; } } return hr; }
HRESULT AllocateHierarchy::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) { string strTexturePath; string strFilename = _pSkinmesh->GetMeshname(); strFilename = strFilename + "\\" + pMeshContainer->pMaterials[iMaterial].pTextureFilename; strTexturePath = MODEL_DIR(strFilename.c_str()); if( FAILED( Moon_CreateTexture( pd3dDevice, const_cast<char*>(strTexturePath.c_str()), &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 = _pSkinmesh->GenerateSkinmesh(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; }