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; 
}