|
|
//-----------------------------------------------------------------------------
// File: D3DFile.cpp
//
// Desc: Support code for loading DirectX .X files.
//
// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#define STRICT
#define D3D_OVERLOADS
#include "StdAfx.h"
#include "guids.h"
#include "D3DUtil.h"
#include "D3DMath.h"
#include "D3DTextr.h"
#include "dxfile.h"
#include "rmxfguid.h"
#include "rmxftmpl.h"
#include "D3DFile.h"
#include "sealife.h"
//-----------------------------------------------------------------------------
// Name: GetFace
// Desc: Get the nth face
//-----------------------------------------------------------------------------
DWORD* GetFace(DWORD* pFaceData, DWORD dwFace) { for(DWORD i=0; i<dwFace; i++) pFaceData += (*pFaceData) + 1;
return pFaceData; }
//-----------------------------------------------------------------------------
// Name: GetNumIndices
// Desc: Get number of indices from face data
//-----------------------------------------------------------------------------
DWORD GetNumIndices(DWORD* pFaceData, DWORD dwNumFaces) { DWORD dwNumIndices = 0; while(dwNumFaces-- > 0) { dwNumIndices += (*pFaceData-2)*3; pFaceData += *pFaceData + 1; }
return dwNumIndices; }
//-----------------------------------------------------------------------------
// Name: CD3DFileBaseObject()
// Desc:
//-----------------------------------------------------------------------------
CD3DFileObject::CD3DFileObject(TCHAR* strName) { m_pNext = NULL; m_pChild = NULL; m_strName[0] = 0; m_bHasMeshData = FALSE;
if (strName) StrCpy(m_strName, strName);
// Set a default matrix
D3DUtil_SetIdentityMatrix(m_mat);
// Set a default material
D3DUtil_InitMaterial(m_Material[0].m_mtrl, 1.0f, 1.0f, 1.0f); ZeroMemory(m_Material, sizeof(m_Material)); m_dwNumMaterials = 0; m_bHasAlpha = FALSE;
// Clear out vertex data
m_dwNumVertices = 0L; m_pVertices = NULL; m_dwNumIndices = 0L; m_pIndices = NULL; }
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
CD3DFileObject::~CD3DFileObject() { SAFE_DELETE(m_pChild); SAFE_DELETE(m_pNext);
for(DWORD i=0; i<m_dwNumMaterials; i++) D3DTextr_DestroyTexture(m_Material[i].m_strTexture);
SAFE_DELETE(m_pVertices); SAFE_DELETE(m_pIndices); }
//-----------------------------------------------------------------------------
// Name: SetMeshGeometry()
// Desc:
//-----------------------------------------------------------------------------
HRESULT CD3DFileObject::SetMeshGeometry(D3DVECTOR* pVertexData, DWORD dwNumVertices, DWORD* pFaceData, DWORD dwNumFaces) { // Set up vertices
m_dwNumVertices = dwNumVertices; m_pVertices = new D3DVERTEX[m_dwNumVertices]; if (NULL == m_pVertices) return E_FAIL;
for(DWORD i=0; i< m_dwNumVertices; i++) { ZeroMemory(&m_pVertices[i], sizeof(D3DVERTEX)); m_pVertices[i].x = pVertexData[i].x; m_pVertices[i].y = pVertexData[i].y; m_pVertices[i].z = pVertexData[i].z; }
// Count the number of indices (converting n-sided faces to triangles)
m_dwNumIndices = GetNumIndices(pFaceData, dwNumFaces);
// Allocate memory for the indices, you must call AddFace() to set the vertices
m_pIndices = new WORD[m_dwNumIndices];
if (NULL == m_pIndices) return E_FAIL;
m_bHasMeshData = TRUE;
return S_OK; }
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
VOID CD3DFileObject::AddChild(CD3DFileObject* pChild) { if (m_pChild) m_pChild->AddNext(pChild); else m_pChild = pChild; }
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
VOID CD3DFileObject::AddNext(CD3DFileObject* pNext) { if (m_pNext) m_pNext->AddNext(pNext); else m_pNext = pNext; }
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
VOID CD3DFileObject::Render(LPDIRECT3DDEVICE7 pd3dDevice, BOOL bAlpha) { if (m_bHasMeshData) { // Render the mesh
WORD* pIndices = m_pIndices; for(DWORD i=0; i <= m_dwNumMaterials; i++) { // Skip materials with no references
if (0L == m_Material[i].m_dwNumIndices) continue;
// Render opaque and transparent meshes during separate passes
if (bAlpha == m_bHasAlpha) { TCHAR* strTexture = m_Material[i].m_strTexture; DWORD dwNumIndices = m_Material[i].m_dwNumIndices;
if (strTexture[0]) pd3dDevice->SetTexture(0, D3DTextr_GetSurface(strTexture)); pd3dDevice->SetMaterial(&m_Material[i].m_mtrl); pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, D3DFVF_VERTEX, m_pVertices, m_dwNumVertices, pIndices, dwNumIndices, NULL); }
pIndices += m_Material[i].m_dwNumIndices; } } else { if (m_pChild) { // Save the old matrix sate
D3DMATRIX matWorldOld, matWorldNew; pd3dDevice->GetTransform(D3DTRANSFORMSTATE_WORLD, &matWorldOld);
// Concat the frame matrix with the current world matrix
matWorldNew = m_mat * matWorldOld; pd3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matWorldNew);
// Render the child nodes
m_pChild->Render(pd3dDevice, bAlpha);
// Restore the old matrix state
pd3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matWorldOld); } }
// Render the remaining sibling nodes
if (m_pNext) m_pNext->Render(pd3dDevice, bAlpha); }
//-----------------------------------------------------------------------------
// Name: SetMaterialData()
// Desc: Sets the material structure for the mesh
//-----------------------------------------------------------------------------
VOID CD3DFileObject::SetMaterialData(DWORD dwMaterial, D3DMATERIAL7* pmtrl, TCHAR* strName) { if (dwMaterial < MAX_MATERIAL) { m_Material[dwMaterial].m_mtrl = *pmtrl; StrCpyN(m_Material[dwMaterial].m_strTexture, strName, MAX_TEXTURE_NAME);
if (pmtrl->diffuse.a < 1.0f) m_bHasAlpha = TRUE; } }
//-----------------------------------------------------------------------------
// Name: AddFace()
// Desc: Adds one or more faces to a material slot in a Mesh. Note: this must
// be called in order (material 0 first, then 1, ...)
//-----------------------------------------------------------------------------
VOID CD3DFileObject::AddFace(DWORD dwMaterial, DWORD* pFaceData, DWORD dwNumFaces) { // Make sure dwMaterial is in range
if (dwMaterial >= MAX_MATERIAL) return;
// Update the material count
if (m_dwNumMaterials < dwMaterial+1) m_dwNumMaterials = dwMaterial+1;
// add indices to the end
WORD* pIndices = m_pIndices; for(DWORD i=0; i<=dwMaterial; i++) pIndices += m_Material[i].m_dwNumIndices;
// Assign the indices (build a triangle fan for high-order polygons)
while(dwNumFaces--) { DWORD dwNumVerticesPerFace = *pFaceData++;
for(DWORD i=2; i<dwNumVerticesPerFace; i++) { m_Material[dwMaterial].m_dwNumIndices += 3; *pIndices++ = (WORD)pFaceData[0]; *pIndices++ = (WORD)pFaceData[i-1]; *pIndices++ = (WORD)pFaceData[i]; }
pFaceData += dwNumVerticesPerFace; } }
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT CD3DFileObject::GetMeshGeometry(D3DVERTEX** ppVertices, DWORD* pdwNumVertices, WORD** ppIndices, DWORD* pdwNumIndices) { if (ppVertices) *ppVertices = m_pVertices; if (pdwNumVertices) *pdwNumVertices = m_dwNumVertices; if (ppIndices) *ppIndices = m_pIndices; if (pdwNumIndices) *pdwNumIndices = m_dwNumIndices;
return S_OK; }
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT CD3DFileObject::ComputeNormals() { D3DVECTOR* pNormals = new D3DVECTOR[m_dwNumVertices]; ZeroMemory(pNormals, sizeof(D3DVECTOR)*m_dwNumVertices);
for(DWORD i=0; i<m_dwNumIndices; i+=3) { WORD a = m_pIndices[i+0]; WORD b = m_pIndices[i+1]; WORD c = m_pIndices[i+2];
D3DVECTOR* v1 = (D3DVECTOR*)&m_pVertices[a]; D3DVECTOR* v2 = (D3DVECTOR*)&m_pVertices[b]; D3DVECTOR* v3 = (D3DVECTOR*)&m_pVertices[c];
D3DVECTOR n = Normalize(CrossProduct(*v2-*v1, *v3-*v2));
pNormals[a] += n; pNormals[b] += n; pNormals[c] += n; }
// Assign the newly computed normals back to the vertices
for(i=0; i<m_dwNumVertices; i++) { // Provide some relief to bogus normals
if (Magnitude(pNormals[i]) < 0.1f) pNormals[i] = D3DVECTOR(0.0f, 0.0f, 1.0f); pNormals[i] = Normalize(pNormals[i]); m_pVertices[i].nx = pNormals[i].x; m_pVertices[i].ny = pNormals[i].y; m_pVertices[i].nz = pNormals[i].z; }
delete pNormals;
return S_OK; }
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
VOID CD3DFileObject::SetNormals(D3DVECTOR* pNormals) { for(DWORD i=0; i<m_dwNumVertices; i++) { m_pVertices[i].nx = pNormals[i].x; m_pVertices[i].ny = pNormals[i].y; m_pVertices[i].nz = pNormals[i].z; } }
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
VOID CD3DFileObject::SetTextureCoords(FLOAT* pTexCoords) { for(DWORD i=0; i<m_dwNumVertices; i++) { m_pVertices[i].tu = pTexCoords[2*i+0]; m_pVertices[i].tv = pTexCoords[2*i+1]; } }
//-----------------------------------------------------------------------------
// Name: ParseXXXX()
// Desc: The following routines implement the DirectX .X file loader.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT ParseMaterial(LPDIRECTXFILEDATA pFileData, CD3DFileObject* pMesh, DWORD dwMaterial) { // Read data from the file
LONG_PTR pData; DWORD dwSize; TCHAR strTexture[128];
if (FAILED(pFileData->GetData(NULL, &dwSize, (VOID**)&pData))) return NULL;
// Set the material properties for the mesh
D3DMATERIAL7 mtrl; ZeroMemory(&mtrl, sizeof(mtrl)); memcpy(&mtrl.diffuse, (VOID*)(pData+0), sizeof(FLOAT)*4); memcpy(&mtrl.ambient, (VOID*)(pData+0), sizeof(FLOAT)*4); memcpy(&mtrl.power, (VOID*)(pData+16), sizeof(FLOAT)*1); memcpy(&mtrl.specular, (VOID*)(pData+20), sizeof(FLOAT)*3); memcpy(&mtrl.emissive, (VOID*)(pData+32), sizeof(FLOAT)*3); strTexture[0] = 0;
LPDIRECTXFILEOBJECT pChildObj; if (SUCCEEDED(pFileData->GetNextObject(&pChildObj))) { LPDIRECTXFILEDATA pChildData;
if (SUCCEEDED(pChildObj->QueryInterface(IID_IDirectXFileData, (VOID**)&pChildData))) { const GUID* pguid; pChildData->GetType(&pguid);
if (TID_D3DRMTextureFilename == *pguid) { TCHAR** string;
if (FAILED(pChildData->GetData(NULL, &dwSize, (VOID**)&string))) return NULL;
D3DTextr_CreateTextureFromFile(*string); StrCpyN(strTexture, *string, 128); }
pChildData->Release(); }
pChildObj->Release(); }
pMesh->SetMaterialData(dwMaterial, &mtrl, strTexture);
return S_OK; }
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT ParseMeshMaterialList(LPDIRECTXFILEDATA pFileData, CD3DFileObject* pMesh) { LPDIRECTXFILEOBJECT pChildObj; LPDIRECTXFILEDATA pChildData; LPDIRECTXFILEDATAREFERENCE pChildDataRef; DWORD dwMaterial = 0;
while(SUCCEEDED(pFileData->GetNextObject(&pChildObj))) { if (SUCCEEDED(pChildObj->QueryInterface(IID_IDirectXFileData, (VOID**)&pChildData))) { const GUID* pguid; pChildData->GetType(&pguid);
if (TID_D3DRMMaterial == *pguid) { ParseMaterial(pChildData, pMesh, dwMaterial++); }
pChildData->Release(); }
if (SUCCEEDED(pChildObj->QueryInterface(IID_IDirectXFileDataReference, (VOID**)&pChildDataRef))) { if (SUCCEEDED(pChildDataRef->Resolve(&pChildData))) { const GUID* pguid; pChildData->GetType(&pguid);
if (TID_D3DRMMaterial == *pguid) { ParseMaterial(pChildData, pMesh, dwMaterial++); }
pChildData->Release(); } pChildDataRef->Release(); }
pChildObj->Release(); } return S_OK; }
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT ParseMesh(LPDIRECTXFILEDATA pFileData, CD3DFileObject* pParentFrame) { DWORD dwNameLen=80; CHAR strName[80]; TCHAR szName[80];
if (FAILED(pFileData->GetName(strName, &dwNameLen))) return E_FAIL;
// Read the Mesh data from the file
LONG_PTR pData; DWORD dwSize;
SHAnsiToUnicode(strName, szName, ARRAYSIZE(szName)); if (FAILED(pFileData->GetData(NULL, &dwSize, (VOID**)&pData))) return E_FAIL;
DWORD dwNumVertices = *((DWORD*)pData); pData += 4; D3DVECTOR* pVertices = ((D3DVECTOR*)pData); pData += 12*dwNumVertices; DWORD dwNumFaces = *((DWORD*)pData); pData += 4; DWORD* pFaceData = (DWORD*)pData;
// Create the Mesh object
CD3DFileObject* pMesh = new CD3DFileObject(szName); pMesh->SetMeshGeometry(pVertices, dwNumVertices, pFaceData, dwNumFaces);
BOOL bHasNormals = FALSE; BOOL bHasMaterials = FALSE;
// Enumerate child objects.
LPDIRECTXFILEOBJECT pChildObj; while(SUCCEEDED(pFileData->GetNextObject(&pChildObj))) { LPDIRECTXFILEDATA pChildData;
if (SUCCEEDED(pChildObj->QueryInterface(IID_IDirectXFileData, (VOID**)&pChildData))) { const GUID* pGUID; LONG_PTR pData; DWORD dwSize;
pChildData->GetType(&pGUID); if (FAILED(pChildData->GetData(NULL, &dwSize, (VOID**)&pData))) { delete pMesh; return NULL; }
if (TID_D3DRMMeshMaterialList == *pGUID) { DWORD dwNumMaterials = *((DWORD*)pData); pData += 4; DWORD dwNumMatFaces = *((DWORD*)pData); pData += 4; DWORD* pMatFace = (DWORD*)pData;
if (dwNumMaterials == 1 || dwNumMatFaces != dwNumFaces) { // Only one material add all faces at once
pMesh->AddFace(0, pFaceData, dwNumFaces); } else { // Multiple materials, add in sorted order
for(DWORD mat=0; mat<dwNumMaterials; mat++) { for(DWORD face=0; face<dwNumMatFaces; face++) { if (pMatFace[face] == mat) pMesh->AddFace(mat, GetFace(pFaceData, face), 1); } } }
ParseMeshMaterialList(pChildData, pMesh); bHasMaterials = TRUE; }
if (TID_D3DRMMeshNormals == *pGUID) { DWORD dwNumNormals = *((DWORD*)pData); D3DVECTOR* pNormals = (D3DVECTOR*)(pData+4);
if (dwNumNormals == dwNumVertices) { pMesh->SetNormals(pNormals); bHasNormals = TRUE; } }
if (TID_D3DRMMeshTextureCoords == *pGUID) { // Copy the texture coords into the mesh's vertices
DWORD dwNumTexCoords = *((DWORD*)pData); FLOAT* pTexCoords = (FLOAT*)(((FLOAT*)pData)+4);
if (dwNumTexCoords == dwNumVertices) pMesh->SetTextureCoords(pTexCoords); }
pChildData->Release(); }
pChildObj->Release(); }
if (FALSE == bHasMaterials) pMesh->AddFace(0, pFaceData, dwNumFaces);
if (FALSE == bHasNormals) pMesh->ComputeNormals();
pParentFrame->AddChild(pMesh); return S_OK; }
//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
HRESULT ParseFrame(LPDIRECTXFILEDATA pFileData, CD3DFileObject* pParentFrame) { DWORD dwNameLen=80; CHAR strName[80]; TCHAR szName[80];
if (FAILED(pFileData->GetName(strName, &dwNameLen))) return E_FAIL;
SHAnsiToUnicode(strName, szName, ARRAYSIZE(szName)); CD3DFileObject* pFrame = new CD3DFileObject(szName);
// Enumerate child objects.
LPDIRECTXFILEOBJECT pChildObj; while(SUCCEEDED(pFileData->GetNextObject(&pChildObj))) { LPDIRECTXFILEDATA pChildData; if (SUCCEEDED(pChildObj->QueryInterface(IID_IDirectXFileData, (VOID**)&pChildData))) { const GUID* pGUID; pChildData->GetType(&pGUID);
if (TID_D3DRMFrame == *pGUID) ParseFrame(pChildData, pFrame);
if (TID_D3DRMMesh == *pGUID) ParseMesh(pChildData, pFrame);
if (TID_D3DRMFrameTransformMatrix == *pGUID) { DWORD dwSize; VOID* pData; if (FAILED(pChildData->GetData(NULL, &dwSize, &pData))) { delete pFrame; return NULL; }
if (dwSize == sizeof(D3DMATRIX)) { // Convert from a left- to a right-handed cordinate system
D3DMATRIX* pmatFrame = (D3DMATRIX*)pData; pmatFrame->_13 *= -1.0f; pmatFrame->_31 *= -1.0f; pmatFrame->_23 *= -1.0f; pmatFrame->_32 *= -1.0f; pmatFrame->_43 *= -1.0f; pFrame->SetMatrix(pmatFrame); } }
pChildData->Release(); }
pChildObj->Release(); }
pParentFrame->AddChild(pFrame); return S_OK; }
//-----------------------------------------------------------------------------
// Name: CD3DFile()
// Desc: Class constructor
//-----------------------------------------------------------------------------
CD3DFile::CD3DFile() { m_pRoot = NULL; }
//-----------------------------------------------------------------------------
// Name: ~CD3DFile()
// Desc: Class destructor
//-----------------------------------------------------------------------------
CD3DFile::~CD3DFile() { SAFE_DELETE(m_pRoot); }
//-----------------------------------------------------------------------------
// Name: Load()
// Desc: Loads a .X geometry file, and creates a hierarchy of frames and meshes
// to represent the geometry in that file.
//-----------------------------------------------------------------------------
HRESULT CD3DFile::Load(LPCTSTR pszFilename) { HRESULT hr; LPDIRECTXFILE pDXFile; LPDIRECTXFILEENUMOBJECT pEnumObj = NULL; LPDIRECTXFILEDATA pFileData; const GUID* pGUID; CD3DFileObject* pFrame = NULL; CHAR szFilename[MAX_PATH];
SHTCharToAnsi(pszFilename, szFilename, ARRAYSIZE(szFilename)); // Cleanup any existing object
SAFE_DELETE(m_pRoot);
// Create the file object, and register the D3DRM templates for .X files
if (FAILED(DirectXFileCreate(&pDXFile))) return E_FAIL; if (FAILED(pDXFile->RegisterTemplates((VOID*)D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES))) { pDXFile->Release(); return E_FAIL; }
// Create an enumerator object, to enumerate through the .X file objects.
// This will open the file in the current directory.
hr = pDXFile->CreateEnumObject(szFilename, DXFILELOAD_FROMFILE, &pEnumObj); if (FAILED(hr)) { CHAR szPath[MAX_PATH];
GetCurrentDirectoryA(ARRAYSIZE(szPath), szPath); PathAppendA(szPath, szFilename); hr = pDXFile->CreateEnumObject(szPath, DXFILELOAD_FROMFILE, &pEnumObj); if (FAILED(hr)) { pDXFile->Release(); return hr; } }
// Create a root object for the X file object
m_pRoot = new CD3DFileObject(TEXT("D3DFile_Root"));
// Cycle through each object. Parse meshes and frames as appropriate
while(SUCCEEDED(hr = pEnumObj->GetNextDataObject(&pFileData))) { pFileData->GetType(&pGUID);
if (*pGUID == TID_D3DRMFrame) ParseFrame(pFileData, m_pRoot);
if (*pGUID == TID_D3DRMMesh) ParseMesh(pFileData, m_pRoot);
pFileData->Release(); }
// Success will result in hr == DXFILEERR_NOMOREOBJECTS
if (DXFILEERR_NOMOREOBJECTS == hr) hr = S_OK; else SAFE_DELETE(m_pRoot);
pEnumObj->Release(); pDXFile->Release();
return hr; }
//-----------------------------------------------------------------------------
// Name: GetMeshVertices()
// Desc: Traverse the hierarchy of frames and meshes that make up the file
// object, and retrieves the vertices for the specified mesh.
//-----------------------------------------------------------------------------
HRESULT CD3DFile::GetMeshVertices(TCHAR* strName, D3DVERTEX** ppVertices, DWORD* pdwNumVertices) { CD3DFileObject* pObject = FindObject(strName); if (pObject) return pObject->GetMeshGeometry(ppVertices, pdwNumVertices, NULL, NULL);
return E_FAIL; }
//-----------------------------------------------------------------------------
// Name: GetMeshVertices()
// Desc: Traverse the hierarchy of frames and meshes that make up the file
// object, and retrieves the vertices for the specified mesh.
//-----------------------------------------------------------------------------
HRESULT CD3DFile::GetMeshIndices(TCHAR* strName, WORD** ppIndices, DWORD* pdwNumIndices) { CD3DFileObject* pObject = FindObject(strName); if (pObject) return pObject->GetMeshGeometry(NULL, NULL, ppIndices, pdwNumIndices);
return E_FAIL; }
//-----------------------------------------------------------------------------
// Name: EnumObjects()
// Desc: Enumerates all objects in the file.
//-----------------------------------------------------------------------------
BOOL CD3DFileObject::EnumObjects(BOOL (*fnCallback)(CD3DFileObject*,D3DMATRIX*,VOID*), D3DMATRIX* pmat, VOID* pContext) { if (fnCallback(this, pmat, pContext) == TRUE) return TRUE;
if (m_pChild) { // Concat matrix set
D3DMATRIX matSave = (*pmat); (*pmat) = (*pmat) * m_mat; if (m_pChild->EnumObjects(fnCallback, pmat, pContext) == TRUE) return TRUE;
// Restore matrix set
(*pmat) = matSave; }
if (m_pNext) if (m_pNext->EnumObjects(fnCallback, pmat, pContext) == TRUE) return TRUE;
return FALSE; }
//-----------------------------------------------------------------------------
// Name: EnumObjects()
// Desc: Enumerates all objects in the file.
//-----------------------------------------------------------------------------
VOID CD3DFile::EnumObjects(BOOL (*fnCallback)(CD3DFileObject*,D3DMATRIX*,VOID*), D3DMATRIX* pmat, VOID* pContext) { if (m_pRoot) { D3DMATRIX mat;
if (pmat) mat = *pmat; else D3DUtil_SetIdentityMatrix(mat);
m_pRoot->EnumObjects(fnCallback, &mat, pContext); } }
//-----------------------------------------------------------------------------
// Name: ScaleMeshCB()
// Desc: Callback to scale a mesh
//-----------------------------------------------------------------------------
BOOL ScaleMeshCB(CD3DFileObject* pFileObject, D3DMATRIX*, VOID* pContext) { D3DVERTEX* pVertices; DWORD dwNumVertices;
if (SUCCEEDED(pFileObject->GetMeshGeometry(&pVertices, &dwNumVertices, NULL, NULL))) { for(DWORD i=0; i<dwNumVertices; i++) { pVertices[i].x *= (*((FLOAT*)pContext)); pVertices[i].y *= (*((FLOAT*)pContext)); pVertices[i].z *= (*((FLOAT*)pContext)); } }
// Keep enumerating
return FALSE; }
//-----------------------------------------------------------------------------
// Name: FindMeshCB()
// Desc: Callback to scale a mesh
//-----------------------------------------------------------------------------
BOOL FindMeshCB(CD3DFileObject* pFileObject, D3DMATRIX*, VOID* pContext) { struct FINDMESHRECORD { TCHAR* strName; CD3DFileObject* pObject; };
FINDMESHRECORD* data = (FINDMESHRECORD*)pContext; if (0 == lstrcmpi(data->strName, pFileObject->GetName())) { data->pObject = pFileObject; return TRUE; }
// Keep enumerating
return FALSE; }
//-----------------------------------------------------------------------------
// Name: Scale()
// Desc: Scales all meshes in the file
//-----------------------------------------------------------------------------
VOID CD3DFile::Scale(FLOAT fScale) { EnumObjects(ScaleMeshCB, NULL, (VOID*)&fScale); }
//-----------------------------------------------------------------------------
// Name: FindObject()
// Desc: Searches all meshes in file object and returns named mesh
//-----------------------------------------------------------------------------
CD3DFileObject* CD3DFile::FindObject(TCHAR* strName) { if (NULL == strName) return m_pRoot;
struct FINDMESHRECORD { TCHAR* strName; CD3DFileObject* pObject; };
FINDMESHRECORD data = { strName, NULL };
EnumObjects(FindMeshCB, NULL, (VOID*)&data); return data.pObject; }
//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Renders the hierarchy of frames and meshes that make up the file
// object
//-----------------------------------------------------------------------------
HRESULT CD3DFile::Render(LPDIRECT3DDEVICE7 pd3dDevice) { LPDIRECTDRAWSURFACE7 pddsSavedTexture; D3DMATRIX matSaved; D3DMATERIAL7 mtrlSaved; DWORD dwAlphaState, dwSrcBlendState, dwDestBlendState;
if (m_pRoot) { // State render states that will be overwritten
pd3dDevice->GetMaterial(&mtrlSaved); pd3dDevice->GetTexture(0, &pddsSavedTexture); pd3dDevice->GetTransform(D3DTRANSFORMSTATE_WORLD, &matSaved); pd3dDevice->GetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, &dwAlphaState); pd3dDevice->GetRenderState(D3DRENDERSTATE_SRCBLEND, &dwSrcBlendState); pd3dDevice->GetRenderState(D3DRENDERSTATE_DESTBLEND, &dwDestBlendState);
// Render the opaque file object's hierarchy of frames and meshes
m_pRoot->Render(pd3dDevice, FALSE);
// Render the transparent file object's hierarchy of frames and meshes
// pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
// pd3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
// pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
// m_pRoot->Render(pd3dDevice, TRUE);
// Restore the render states
pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, dwAlphaState); pd3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, dwSrcBlendState); pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, dwDestBlendState); pd3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matSaved); pd3dDevice->SetTexture(0, pddsSavedTexture); pd3dDevice->SetMaterial(&mtrlSaved);
// Keep the ref count of the texture consistent
if (pddsSavedTexture) pddsSavedTexture->Release(); }
return S_OK; }
|