www.pudn.com > XFileLoadingCode.zip > MeshHierarchy.cpp
#include "dxstdafx.h"
#include "structures.h"
#include "meshhierarchy.h"
#include "utilities.h"
/**
* \brief callback called when a new frame is encountered during the .x file load
* \param Name - name of the frame
* \param ppNewFrame - output pointer assign our newly created frame
* \return success code
* \author Keith Ditchburn \date 17 July 2005
*/
HRESULT CMeshHierarchy::CreateFrame(LPCSTR Name, LPD3DXFRAME *ppNewFrame)
{
// Always a good idea to initialise return pointer before proceeding
*ppNewFrame = NULL;
// Create a new frame using the derived version of the structure
D3DXFRAME_EXTENDED *newFrame = new D3DXFRAME_EXTENDED;
ZeroMemory(newFrame,sizeof(D3DXFRAME_EXTENDED));
// Now fill in the data members in the frame structure
// The frame name (note: may be null or zero length)
newFrame->Name=CUtilities::DuplicateCharString(Name);
// Now initialize other data members of the frame to defaults
D3DXMatrixIdentity(&newFrame->TransformationMatrix);
D3DXMatrixIdentity(&newFrame->exCombinedTransformationMatrix);
newFrame->pMeshContainer = NULL;
newFrame->pFrameSibling = NULL;
newFrame->pFrameFirstChild = NULL;
// Assign the return pointer to our newly created frame
*ppNewFrame = newFrame;
// Output some debug info
#if defined(DEBUG) | defined(_DEBUG)
WCHAR debugText[2048];
WCHAR wideName[512];
if (Name && strlen(Name)>0)
CUtilities::FillWideStringFromCharString(Name,wideName,512);
else
StringCchPrintf(wideName,512,L"");
StringCchPrintf(debugText,2048,L"Added frame %s\n",wideName);
OutputDebugString(debugText);
#endif
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 pMeshData - the mesh data
* \param pMaterials - material array
* \param pEffectInstances - effect files / settings for the mesh
* \param NumMaterials - number of materials in the mesh
* \param pAdjacency - adjacency array
* \param pSkinInfo - skin info.
* \param ppNewMeshContainer - output pointer to assign our newly created mesh container
* \return success code
* \author Keith Ditchburn \date 17 July 2005
*/
HRESULT CMeshHierarchy::CreateMeshContainer( THIS_
LPCSTR Name,
CONST D3DXMESHDATA *pMeshData,
CONST D3DXMATERIAL *pMaterials,
CONST D3DXEFFECTINSTANCE *pEffectInstances,
DWORD NumMaterials,
CONST DWORD *pAdjacency,
LPD3DXSKININFO pSkinInfo,
LPD3DXMESHCONTAINER* ppNewMeshContainer)
{
// Create a mesh container structure to fill and initilaise to zero values
// Note: I use my extended version of the structure (D3DXMESHCONTAINER_EXTENDED)
D3DXMESHCONTAINER_EXTENDED *newMeshContainer=new D3DXMESHCONTAINER_EXTENDED;
ZeroMemory(newMeshContainer, sizeof(D3DXMESHCONTAINER_EXTENDED));
// Always a good idea to initialise return pointer before proceeding
*ppNewMeshContainer = NULL;
// The mesh name (may be null) needs copying over
newMeshContainer->Name=CUtilities::DuplicateCharString(Name);
// Output some debug info
#if defined(DEBUG) | defined(_DEBUG)
WCHAR debugText[2048];
WCHAR wName[512];
if (Name && strlen(Name)>0)
CUtilities::FillWideStringFromCharString(Name,wName,512);
else
StringCchPrintf(wName,512,L"");
StringCchPrintf(debugText,2048,L"Added Mesh %s\n",wName);
OutputDebugString(debugText);
#endif
// The mesh type (D3DXMESHTYPE_MESH, D3DXMESHTYPE_PMESH or D3DXMESHTYPE_PATCHMESH)
if (pMeshData->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 = pMeshData->pMesh->GetNumFaces();
newMeshContainer->pAdjacency = new DWORD[dwFaces*3];
memcpy(newMeshContainer->pAdjacency, pAdjacency, sizeof(DWORD) * dwFaces*3);
// Get the Direct3D device, luckily this is held in the mesh itself
LPDIRECT3DDEVICE9 pd3dDevice = NULL;
pMeshData->pMesh->GetDevice(&pd3dDevice);
// Make a copy of the mesh data that is passed in and place it in our mesh container
// FIX: 19 September 2005 - the CloneMeshFVF method was failing with some .x exported files from some packages
// due to the FVF not being able to be mapped. Changing to GetDeclaration solves the problem.
D3DVERTEXELEMENT9 Declaration[MAX_FVF_DECL_SIZE];
if (FAILED(pMeshData->pMesh->GetDeclaration(Declaration)))
return E_FAIL;
//pMeshData->pMesh->CloneMeshFVF(D3DXMESH_MANAGED,
// pMeshData->pMesh->GetFVF(), pd3dDevice,
// &newMeshContainer->MeshData.pMesh);
pMeshData->pMesh->CloneMesh(D3DXMESH_MANAGED,
Declaration, pd3dDevice,
&newMeshContainer->MeshData.pMesh);
// 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] = NULL;
newMeshContainer->exMaterials[i]=pMaterials[i].MatD3D;
if(pMaterials[i].pTextureFilename)
{
// Note: the texture filename in the mesh container is an LPSTR (char *) but this
// demo uses UNICODE so convert to LPWSTR (WCHAR*) required by D3DXCreateTextureFromFileW
WCHAR wszTexName[MAX_PATH];
CUtilities::FillWideStringFromCharString(pMaterials[i].pTextureFilename,wszTexName,MAX_PATH);
// Use the D3DX function to create the texturer
if(FAILED(D3DXCreateTextureFromFile(pd3dDevice, wszTexName,&newMeshContainer->exTextures[i])))
{
OutputDebugString(L"Could not load texture\n");
newMeshContainer->exTextures[i] = NULL;
// Note: there is often pain finding the textures for .x files as sometimes the filename
// includes the path and other times it does not. It is a cause of a lot of issues. By
// saving your .x file as text you can look at it and see what the filenames are set to
// which can help spot problems.
// Normally in my code I have complex methods of looking for the textures in various
// paths but it is beyond the scope of this demo so this demo simply looks in the
// directory the .x file is in (see code at top of CXFileEntity::LoadXFile for setting
// current directory)
}
}
}
}
else
// make a default material in the case where the mesh did not come with 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]=NULL;
}
// 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));
// Output some debug info
#if defined(DEBUG) | defined(_DEBUG)
WCHAR debugText[2048];
StringCchPrintf(debugText,2048,L"Mesh has skinning info.\n Number of bones %d\n",numBones);
OutputDebugString(debugText);
#endif
// 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 null all the pointers
newMeshContainer->pSkinInfo = NULL;
newMeshContainer->exBoneOffsets = NULL;
newMeshContainer->exSkinMesh = NULL;
newMeshContainer->exFrameCombinedMatrixPointer = NULL;
}
// When we got the device we caused an internal reference count to be incremented
// So we now need to release it
SAFE_RELEASE(pd3dDevice);
// The mesh may contain a reference to an effect file
if (pEffectInstances)
{
if (pEffectInstances->pEffectFilename)
{
OutputDebugString(L"This .x file references an effect file. Effect files are not handled by this demo");
}
}
// Set the output mesh container to our newly created one
*ppNewMeshContainer = newMeshContainer;
return S_OK;
}
/**
* \brief callback called to deallocate the frame data
* \param the frame to free
* \return success result
* \author Keith Ditchburn \date 17 July 2005
*/
HRESULT CMeshHierarchy::DestroyFrame(LPD3DXFRAME pFrameToFree)
{
// Convert to our extended type. OK as we know for sure it is:
D3DXFRAME_EXTENDED *pFrame = (D3DXFRAME_EXTENDED*)pFrameToFree;
SAFE_DELETE_ARRAY( pFrame->Name );
SAFE_DELETE( pFrame );
return S_OK;
}
/**
* \brief callback called to deallocate the mesh container data
* \param the mesh data to free
* \return success result
* \author Keith Ditchburn \date 17 July 2005
*/
HRESULT CMeshHierarchy::DestroyMeshContainer(LPD3DXMESHCONTAINER pMeshContainerBase)
{
// Convert to our extended type. OK as we know for sure it is:
D3DXMESHCONTAINER_EXTENDED* pMeshContainer = (D3DXMESHCONTAINER_EXTENDED*)pMeshContainerBase;
// name
SAFE_DELETE_ARRAY(pMeshContainer->Name)
// material array
SAFE_DELETE_ARRAY(pMeshContainer->exMaterials)
// release the textures before deleting the array
if(pMeshContainer->exTextures)
{
for(UINT i = 0; i < pMeshContainer->NumMaterials; ++i)
SAFE_RELEASE(pMeshContainer->exTextures[i]);
}
// texture array
SAFE_DELETE_ARRAY(pMeshContainer->exTextures)
// adjacency data
SAFE_DELETE_ARRAY(pMeshContainer->pAdjacency)
// bone parts
SAFE_DELETE_ARRAY(pMeshContainer->exBoneOffsets)
// frame matrices
SAFE_DELETE_ARRAY(pMeshContainer->exFrameCombinedMatrixPointer)
// release skin mesh
SAFE_RELEASE(pMeshContainer->exSkinMesh)
// release the main mesh
SAFE_RELEASE(pMeshContainer->MeshData.pMesh)
// release skin information
SAFE_RELEASE(pMeshContainer->pSkinInfo)
// finally delete the mesh container itself
SAFE_DELETE(pMeshContainer);
return S_OK;
}