windows-nt/Source/XPSP1/NT/shell/osshell/control/scrnsave/dolphin/d3dfile.cpp
2020-09-26 16:20:57 +08:00

1047 lines
30 KiB
C++

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