Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1046 lines
30 KiB

  1. //-----------------------------------------------------------------------------
  2. // File: D3DFile.cpp
  3. //
  4. // Desc: Support code for loading DirectX .X files.
  5. //
  6. // Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #define D3D_OVERLOADS
  10. #include "StdAfx.h"
  11. #include "guids.h"
  12. #include "D3DUtil.h"
  13. #include "D3DMath.h"
  14. #include "D3DTextr.h"
  15. #include "dxfile.h"
  16. #include "rmxfguid.h"
  17. #include "rmxftmpl.h"
  18. #include "D3DFile.h"
  19. #include "sealife.h"
  20. //-----------------------------------------------------------------------------
  21. // Name: GetFace
  22. // Desc: Get the nth face
  23. //-----------------------------------------------------------------------------
  24. DWORD* GetFace(DWORD* pFaceData, DWORD dwFace)
  25. {
  26. for(DWORD i=0; i<dwFace; i++)
  27. pFaceData += (*pFaceData) + 1;
  28. return pFaceData;
  29. }
  30. //-----------------------------------------------------------------------------
  31. // Name: GetNumIndices
  32. // Desc: Get number of indices from face data
  33. //-----------------------------------------------------------------------------
  34. DWORD GetNumIndices(DWORD* pFaceData, DWORD dwNumFaces)
  35. {
  36. DWORD dwNumIndices = 0;
  37. while(dwNumFaces-- > 0)
  38. {
  39. dwNumIndices += (*pFaceData-2)*3;
  40. pFaceData += *pFaceData + 1;
  41. }
  42. return dwNumIndices;
  43. }
  44. //-----------------------------------------------------------------------------
  45. // Name: CD3DFileBaseObject()
  46. // Desc:
  47. //-----------------------------------------------------------------------------
  48. CD3DFileObject::CD3DFileObject(TCHAR* strName)
  49. {
  50. m_pNext = NULL;
  51. m_pChild = NULL;
  52. m_strName[0] = 0;
  53. m_bHasMeshData = FALSE;
  54. if (strName)
  55. StrCpy(m_strName, strName);
  56. // Set a default matrix
  57. D3DUtil_SetIdentityMatrix(m_mat);
  58. // Set a default material
  59. D3DUtil_InitMaterial(m_Material[0].m_mtrl, 1.0f, 1.0f, 1.0f);
  60. ZeroMemory(m_Material, sizeof(m_Material));
  61. m_dwNumMaterials = 0;
  62. m_bHasAlpha = FALSE;
  63. // Clear out vertex data
  64. m_dwNumVertices = 0L;
  65. m_pVertices = NULL;
  66. m_dwNumIndices = 0L;
  67. m_pIndices = NULL;
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Name:
  71. // Desc:
  72. //-----------------------------------------------------------------------------
  73. CD3DFileObject::~CD3DFileObject()
  74. {
  75. SAFE_DELETE(m_pChild);
  76. SAFE_DELETE(m_pNext);
  77. for(DWORD i=0; i<m_dwNumMaterials; i++)
  78. D3DTextr_DestroyTexture(m_Material[i].m_strTexture);
  79. SAFE_DELETE(m_pVertices);
  80. SAFE_DELETE(m_pIndices);
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Name: SetMeshGeometry()
  84. // Desc:
  85. //-----------------------------------------------------------------------------
  86. HRESULT CD3DFileObject::SetMeshGeometry(D3DVECTOR* pVertexData,
  87. DWORD dwNumVertices, DWORD* pFaceData,
  88. DWORD dwNumFaces)
  89. {
  90. // Set up vertices
  91. m_dwNumVertices = dwNumVertices;
  92. m_pVertices = new D3DVERTEX[m_dwNumVertices];
  93. if (NULL == m_pVertices)
  94. return E_FAIL;
  95. for(DWORD i=0; i< m_dwNumVertices; i++)
  96. {
  97. ZeroMemory(&m_pVertices[i], sizeof(D3DVERTEX));
  98. m_pVertices[i].x = pVertexData[i].x;
  99. m_pVertices[i].y = pVertexData[i].y;
  100. m_pVertices[i].z = pVertexData[i].z;
  101. }
  102. // Count the number of indices (converting n-sided faces to triangles)
  103. m_dwNumIndices = GetNumIndices(pFaceData, dwNumFaces);
  104. // Allocate memory for the indices, you must call AddFace() to set the vertices
  105. m_pIndices = new WORD[m_dwNumIndices];
  106. if (NULL == m_pIndices)
  107. return E_FAIL;
  108. m_bHasMeshData = TRUE;
  109. return S_OK;
  110. }
  111. //-----------------------------------------------------------------------------
  112. // Name:
  113. // Desc:
  114. //-----------------------------------------------------------------------------
  115. VOID CD3DFileObject::AddChild(CD3DFileObject* pChild)
  116. {
  117. if (m_pChild)
  118. m_pChild->AddNext(pChild);
  119. else
  120. m_pChild = pChild;
  121. }
  122. //-----------------------------------------------------------------------------
  123. // Name:
  124. // Desc:
  125. //-----------------------------------------------------------------------------
  126. VOID CD3DFileObject::AddNext(CD3DFileObject* pNext)
  127. {
  128. if (m_pNext)
  129. m_pNext->AddNext(pNext);
  130. else
  131. m_pNext = pNext;
  132. }
  133. //-----------------------------------------------------------------------------
  134. // Name:
  135. // Desc:
  136. //-----------------------------------------------------------------------------
  137. VOID CD3DFileObject::Render(LPDIRECT3DDEVICE7 pd3dDevice, BOOL bAlpha)
  138. {
  139. if (m_bHasMeshData)
  140. {
  141. // Render the mesh
  142. WORD* pIndices = m_pIndices;
  143. for(DWORD i=0; i <= m_dwNumMaterials; i++)
  144. {
  145. // Skip materials with no references
  146. if (0L == m_Material[i].m_dwNumIndices)
  147. continue;
  148. // Render opaque and transparent meshes during separate passes
  149. if (bAlpha == m_bHasAlpha)
  150. {
  151. TCHAR* strTexture = m_Material[i].m_strTexture;
  152. DWORD dwNumIndices = m_Material[i].m_dwNumIndices;
  153. if (strTexture[0])
  154. pd3dDevice->SetTexture(0, D3DTextr_GetSurface(strTexture));
  155. pd3dDevice->SetMaterial(&m_Material[i].m_mtrl);
  156. pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, D3DFVF_VERTEX,
  157. m_pVertices, m_dwNumVertices,
  158. pIndices, dwNumIndices, NULL);
  159. }
  160. pIndices += m_Material[i].m_dwNumIndices;
  161. }
  162. }
  163. else
  164. {
  165. if (m_pChild)
  166. {
  167. // Save the old matrix sate
  168. D3DMATRIX matWorldOld, matWorldNew;
  169. pd3dDevice->GetTransform(D3DTRANSFORMSTATE_WORLD, &matWorldOld);
  170. // Concat the frame matrix with the current world matrix
  171. matWorldNew = m_mat * matWorldOld;
  172. pd3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matWorldNew);
  173. // Render the child nodes
  174. m_pChild->Render(pd3dDevice, bAlpha);
  175. // Restore the old matrix state
  176. pd3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matWorldOld);
  177. }
  178. }
  179. // Render the remaining sibling nodes
  180. if (m_pNext)
  181. m_pNext->Render(pd3dDevice, bAlpha);
  182. }
  183. //-----------------------------------------------------------------------------
  184. // Name: SetMaterialData()
  185. // Desc: Sets the material structure for the mesh
  186. //-----------------------------------------------------------------------------
  187. VOID CD3DFileObject::SetMaterialData(DWORD dwMaterial, D3DMATERIAL7* pmtrl,
  188. TCHAR* strName)
  189. {
  190. if (dwMaterial < MAX_MATERIAL)
  191. {
  192. m_Material[dwMaterial].m_mtrl = *pmtrl;
  193. StrCpyN(m_Material[dwMaterial].m_strTexture, strName, MAX_TEXTURE_NAME);
  194. if (pmtrl->diffuse.a < 1.0f)
  195. m_bHasAlpha = TRUE;
  196. }
  197. }
  198. //-----------------------------------------------------------------------------
  199. // Name: AddFace()
  200. // Desc: Adds one or more faces to a material slot in a Mesh. Note: this must
  201. // be called in order (material 0 first, then 1, ...)
  202. //-----------------------------------------------------------------------------
  203. VOID CD3DFileObject::AddFace(DWORD dwMaterial, DWORD* pFaceData,
  204. DWORD dwNumFaces)
  205. {
  206. // Make sure dwMaterial is in range
  207. if (dwMaterial >= MAX_MATERIAL)
  208. return;
  209. // Update the material count
  210. if (m_dwNumMaterials < dwMaterial+1)
  211. m_dwNumMaterials = dwMaterial+1;
  212. // add indices to the end
  213. WORD* pIndices = m_pIndices;
  214. for(DWORD i=0; i<=dwMaterial; i++)
  215. pIndices += m_Material[i].m_dwNumIndices;
  216. // Assign the indices (build a triangle fan for high-order polygons)
  217. while(dwNumFaces--)
  218. {
  219. DWORD dwNumVerticesPerFace = *pFaceData++;
  220. for(DWORD i=2; i<dwNumVerticesPerFace; i++)
  221. {
  222. m_Material[dwMaterial].m_dwNumIndices += 3;
  223. *pIndices++ = (WORD)pFaceData[0];
  224. *pIndices++ = (WORD)pFaceData[i-1];
  225. *pIndices++ = (WORD)pFaceData[i];
  226. }
  227. pFaceData += dwNumVerticesPerFace;
  228. }
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Name:
  232. // Desc:
  233. //-----------------------------------------------------------------------------
  234. HRESULT CD3DFileObject::GetMeshGeometry(D3DVERTEX** ppVertices, DWORD* pdwNumVertices,
  235. WORD** ppIndices, DWORD* pdwNumIndices)
  236. {
  237. if (ppVertices) *ppVertices = m_pVertices;
  238. if (pdwNumVertices) *pdwNumVertices = m_dwNumVertices;
  239. if (ppIndices) *ppIndices = m_pIndices;
  240. if (pdwNumIndices) *pdwNumIndices = m_dwNumIndices;
  241. return S_OK;
  242. }
  243. //-----------------------------------------------------------------------------
  244. // Name:
  245. // Desc:
  246. //-----------------------------------------------------------------------------
  247. HRESULT CD3DFileObject::ComputeNormals()
  248. {
  249. D3DVECTOR* pNormals = new D3DVECTOR[m_dwNumVertices];
  250. ZeroMemory(pNormals, sizeof(D3DVECTOR)*m_dwNumVertices);
  251. for(DWORD i=0; i<m_dwNumIndices; i+=3)
  252. {
  253. WORD a = m_pIndices[i+0];
  254. WORD b = m_pIndices[i+1];
  255. WORD c = m_pIndices[i+2];
  256. D3DVECTOR* v1 = (D3DVECTOR*)&m_pVertices[a];
  257. D3DVECTOR* v2 = (D3DVECTOR*)&m_pVertices[b];
  258. D3DVECTOR* v3 = (D3DVECTOR*)&m_pVertices[c];
  259. D3DVECTOR n = Normalize(CrossProduct(*v2-*v1, *v3-*v2));
  260. pNormals[a] += n;
  261. pNormals[b] += n;
  262. pNormals[c] += n;
  263. }
  264. // Assign the newly computed normals back to the vertices
  265. for(i=0; i<m_dwNumVertices; i++)
  266. {
  267. // Provide some relief to bogus normals
  268. if (Magnitude(pNormals[i]) < 0.1f)
  269. pNormals[i] = D3DVECTOR(0.0f, 0.0f, 1.0f);
  270. pNormals[i] = Normalize(pNormals[i]);
  271. m_pVertices[i].nx = pNormals[i].x;
  272. m_pVertices[i].ny = pNormals[i].y;
  273. m_pVertices[i].nz = pNormals[i].z;
  274. }
  275. delete pNormals;
  276. return S_OK;
  277. }
  278. //-----------------------------------------------------------------------------
  279. // Name:
  280. // Desc:
  281. //-----------------------------------------------------------------------------
  282. VOID CD3DFileObject::SetNormals(D3DVECTOR* pNormals)
  283. {
  284. for(DWORD i=0; i<m_dwNumVertices; i++)
  285. {
  286. m_pVertices[i].nx = pNormals[i].x;
  287. m_pVertices[i].ny = pNormals[i].y;
  288. m_pVertices[i].nz = pNormals[i].z;
  289. }
  290. }
  291. //-----------------------------------------------------------------------------
  292. // Name:
  293. // Desc:
  294. //-----------------------------------------------------------------------------
  295. VOID CD3DFileObject::SetTextureCoords(FLOAT* pTexCoords)
  296. {
  297. for(DWORD i=0; i<m_dwNumVertices; i++)
  298. {
  299. m_pVertices[i].tu = pTexCoords[2*i+0];
  300. m_pVertices[i].tv = pTexCoords[2*i+1];
  301. }
  302. }
  303. //-----------------------------------------------------------------------------
  304. // Name: ParseXXXX()
  305. // Desc: The following routines implement the DirectX .X file loader.
  306. //-----------------------------------------------------------------------------
  307. //-----------------------------------------------------------------------------
  308. // Name:
  309. // Desc:
  310. //-----------------------------------------------------------------------------
  311. HRESULT ParseMaterial(LPDIRECTXFILEDATA pFileData, CD3DFileObject* pMesh,
  312. DWORD dwMaterial)
  313. {
  314. // Read data from the file
  315. LONG_PTR pData;
  316. DWORD dwSize;
  317. TCHAR strTexture[128];
  318. if (FAILED(pFileData->GetData(NULL, &dwSize, (VOID**)&pData)))
  319. return NULL;
  320. // Set the material properties for the mesh
  321. D3DMATERIAL7 mtrl;
  322. ZeroMemory(&mtrl, sizeof(mtrl));
  323. memcpy(&mtrl.diffuse, (VOID*)(pData+0), sizeof(FLOAT)*4);
  324. memcpy(&mtrl.ambient, (VOID*)(pData+0), sizeof(FLOAT)*4);
  325. memcpy(&mtrl.power, (VOID*)(pData+16), sizeof(FLOAT)*1);
  326. memcpy(&mtrl.specular, (VOID*)(pData+20), sizeof(FLOAT)*3);
  327. memcpy(&mtrl.emissive, (VOID*)(pData+32), sizeof(FLOAT)*3);
  328. strTexture[0] = 0;
  329. LPDIRECTXFILEOBJECT pChildObj;
  330. if (SUCCEEDED(pFileData->GetNextObject(&pChildObj)))
  331. {
  332. LPDIRECTXFILEDATA pChildData;
  333. if (SUCCEEDED(pChildObj->QueryInterface(IID_IDirectXFileData,
  334. (VOID**)&pChildData)))
  335. {
  336. const GUID* pguid;
  337. pChildData->GetType(&pguid);
  338. if (TID_D3DRMTextureFilename == *pguid)
  339. {
  340. TCHAR** string;
  341. if (FAILED(pChildData->GetData(NULL, &dwSize, (VOID**)&string)))
  342. return NULL;
  343. D3DTextr_CreateTextureFromFile(*string);
  344. StrCpyN(strTexture, *string, 128);
  345. }
  346. pChildData->Release();
  347. }
  348. pChildObj->Release();
  349. }
  350. pMesh->SetMaterialData(dwMaterial, &mtrl, strTexture);
  351. return S_OK;
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Name:
  355. // Desc:
  356. //-----------------------------------------------------------------------------
  357. HRESULT ParseMeshMaterialList(LPDIRECTXFILEDATA pFileData,
  358. CD3DFileObject* pMesh)
  359. {
  360. LPDIRECTXFILEOBJECT pChildObj;
  361. LPDIRECTXFILEDATA pChildData;
  362. LPDIRECTXFILEDATAREFERENCE pChildDataRef;
  363. DWORD dwMaterial = 0;
  364. while(SUCCEEDED(pFileData->GetNextObject(&pChildObj)))
  365. {
  366. if (SUCCEEDED(pChildObj->QueryInterface(IID_IDirectXFileData,
  367. (VOID**)&pChildData)))
  368. {
  369. const GUID* pguid;
  370. pChildData->GetType(&pguid);
  371. if (TID_D3DRMMaterial == *pguid)
  372. {
  373. ParseMaterial(pChildData, pMesh, dwMaterial++);
  374. }
  375. pChildData->Release();
  376. }
  377. if (SUCCEEDED(pChildObj->QueryInterface(IID_IDirectXFileDataReference,
  378. (VOID**)&pChildDataRef)))
  379. {
  380. if (SUCCEEDED(pChildDataRef->Resolve(&pChildData)))
  381. {
  382. const GUID* pguid;
  383. pChildData->GetType(&pguid);
  384. if (TID_D3DRMMaterial == *pguid)
  385. {
  386. ParseMaterial(pChildData, pMesh, dwMaterial++);
  387. }
  388. pChildData->Release();
  389. }
  390. pChildDataRef->Release();
  391. }
  392. pChildObj->Release();
  393. }
  394. return S_OK;
  395. }
  396. //-----------------------------------------------------------------------------
  397. // Name:
  398. // Desc:
  399. //-----------------------------------------------------------------------------
  400. HRESULT ParseMesh(LPDIRECTXFILEDATA pFileData, CD3DFileObject* pParentFrame)
  401. {
  402. DWORD dwNameLen=80;
  403. CHAR strName[80];
  404. TCHAR szName[80];
  405. if (FAILED(pFileData->GetName(strName, &dwNameLen)))
  406. return E_FAIL;
  407. // Read the Mesh data from the file
  408. LONG_PTR pData;
  409. DWORD dwSize;
  410. SHAnsiToUnicode(strName, szName, ARRAYSIZE(szName));
  411. if (FAILED(pFileData->GetData(NULL, &dwSize, (VOID**)&pData)))
  412. return E_FAIL;
  413. DWORD dwNumVertices = *((DWORD*)pData); pData += 4;
  414. D3DVECTOR* pVertices = ((D3DVECTOR*)pData); pData += 12*dwNumVertices;
  415. DWORD dwNumFaces = *((DWORD*)pData); pData += 4;
  416. DWORD* pFaceData = (DWORD*)pData;
  417. // Create the Mesh object
  418. CD3DFileObject* pMesh = new CD3DFileObject(szName);
  419. pMesh->SetMeshGeometry(pVertices, dwNumVertices, pFaceData, dwNumFaces);
  420. BOOL bHasNormals = FALSE;
  421. BOOL bHasMaterials = FALSE;
  422. // Enumerate child objects.
  423. LPDIRECTXFILEOBJECT pChildObj;
  424. while(SUCCEEDED(pFileData->GetNextObject(&pChildObj)))
  425. {
  426. LPDIRECTXFILEDATA pChildData;
  427. if (SUCCEEDED(pChildObj->QueryInterface(IID_IDirectXFileData,
  428. (VOID**)&pChildData)))
  429. {
  430. const GUID* pGUID;
  431. LONG_PTR pData;
  432. DWORD dwSize;
  433. pChildData->GetType(&pGUID);
  434. if (FAILED(pChildData->GetData(NULL, &dwSize, (VOID**)&pData)))
  435. {
  436. delete pMesh;
  437. return NULL;
  438. }
  439. if (TID_D3DRMMeshMaterialList == *pGUID)
  440. {
  441. DWORD dwNumMaterials = *((DWORD*)pData); pData += 4;
  442. DWORD dwNumMatFaces = *((DWORD*)pData); pData += 4;
  443. DWORD* pMatFace = (DWORD*)pData;
  444. if (dwNumMaterials == 1 || dwNumMatFaces != dwNumFaces)
  445. {
  446. // Only one material add all faces at once
  447. pMesh->AddFace(0, pFaceData, dwNumFaces);
  448. }
  449. else
  450. {
  451. // Multiple materials, add in sorted order
  452. for(DWORD mat=0; mat<dwNumMaterials; mat++)
  453. {
  454. for(DWORD face=0; face<dwNumMatFaces; face++)
  455. {
  456. if (pMatFace[face] == mat)
  457. pMesh->AddFace(mat, GetFace(pFaceData, face), 1);
  458. }
  459. }
  460. }
  461. ParseMeshMaterialList(pChildData, pMesh);
  462. bHasMaterials = TRUE;
  463. }
  464. if (TID_D3DRMMeshNormals == *pGUID)
  465. {
  466. DWORD dwNumNormals = *((DWORD*)pData);
  467. D3DVECTOR* pNormals = (D3DVECTOR*)(pData+4);
  468. if (dwNumNormals == dwNumVertices)
  469. {
  470. pMesh->SetNormals(pNormals);
  471. bHasNormals = TRUE;
  472. }
  473. }
  474. if (TID_D3DRMMeshTextureCoords == *pGUID)
  475. {
  476. // Copy the texture coords into the mesh's vertices
  477. DWORD dwNumTexCoords = *((DWORD*)pData);
  478. FLOAT* pTexCoords = (FLOAT*)(((FLOAT*)pData)+4);
  479. if (dwNumTexCoords == dwNumVertices)
  480. pMesh->SetTextureCoords(pTexCoords);
  481. }
  482. pChildData->Release();
  483. }
  484. pChildObj->Release();
  485. }
  486. if (FALSE == bHasMaterials)
  487. pMesh->AddFace(0, pFaceData, dwNumFaces);
  488. if (FALSE == bHasNormals)
  489. pMesh->ComputeNormals();
  490. pParentFrame->AddChild(pMesh);
  491. return S_OK;
  492. }
  493. //-----------------------------------------------------------------------------
  494. // Name:
  495. // Desc:
  496. //-----------------------------------------------------------------------------
  497. HRESULT ParseFrame(LPDIRECTXFILEDATA pFileData, CD3DFileObject* pParentFrame)
  498. {
  499. DWORD dwNameLen=80;
  500. CHAR strName[80];
  501. TCHAR szName[80];
  502. if (FAILED(pFileData->GetName(strName, &dwNameLen)))
  503. return E_FAIL;
  504. SHAnsiToUnicode(strName, szName, ARRAYSIZE(szName));
  505. CD3DFileObject* pFrame = new CD3DFileObject(szName);
  506. // Enumerate child objects.
  507. LPDIRECTXFILEOBJECT pChildObj;
  508. while(SUCCEEDED(pFileData->GetNextObject(&pChildObj)))
  509. {
  510. LPDIRECTXFILEDATA pChildData;
  511. if (SUCCEEDED(pChildObj->QueryInterface(IID_IDirectXFileData,
  512. (VOID**)&pChildData)))
  513. {
  514. const GUID* pGUID;
  515. pChildData->GetType(&pGUID);
  516. if (TID_D3DRMFrame == *pGUID)
  517. ParseFrame(pChildData, pFrame);
  518. if (TID_D3DRMMesh == *pGUID)
  519. ParseMesh(pChildData, pFrame);
  520. if (TID_D3DRMFrameTransformMatrix == *pGUID)
  521. {
  522. DWORD dwSize;
  523. VOID* pData;
  524. if (FAILED(pChildData->GetData(NULL, &dwSize, &pData)))
  525. {
  526. delete pFrame;
  527. return NULL;
  528. }
  529. if (dwSize == sizeof(D3DMATRIX))
  530. {
  531. // Convert from a left- to a right-handed cordinate system
  532. D3DMATRIX* pmatFrame = (D3DMATRIX*)pData;
  533. pmatFrame->_13 *= -1.0f;
  534. pmatFrame->_31 *= -1.0f;
  535. pmatFrame->_23 *= -1.0f;
  536. pmatFrame->_32 *= -1.0f;
  537. pmatFrame->_43 *= -1.0f;
  538. pFrame->SetMatrix(pmatFrame);
  539. }
  540. }
  541. pChildData->Release();
  542. }
  543. pChildObj->Release();
  544. }
  545. pParentFrame->AddChild(pFrame);
  546. return S_OK;
  547. }
  548. //-----------------------------------------------------------------------------
  549. // Name: CD3DFile()
  550. // Desc: Class constructor
  551. //-----------------------------------------------------------------------------
  552. CD3DFile::CD3DFile()
  553. {
  554. m_pRoot = NULL;
  555. }
  556. //-----------------------------------------------------------------------------
  557. // Name: ~CD3DFile()
  558. // Desc: Class destructor
  559. //-----------------------------------------------------------------------------
  560. CD3DFile::~CD3DFile()
  561. {
  562. SAFE_DELETE(m_pRoot);
  563. }
  564. //-----------------------------------------------------------------------------
  565. // Name: Load()
  566. // Desc: Loads a .X geometry file, and creates a hierarchy of frames and meshes
  567. // to represent the geometry in that file.
  568. //-----------------------------------------------------------------------------
  569. HRESULT CD3DFile::Load(LPCTSTR pszFilename)
  570. {
  571. HRESULT hr;
  572. LPDIRECTXFILE pDXFile;
  573. LPDIRECTXFILEENUMOBJECT pEnumObj = NULL;
  574. LPDIRECTXFILEDATA pFileData;
  575. const GUID* pGUID;
  576. CD3DFileObject* pFrame = NULL;
  577. CHAR szFilename[MAX_PATH];
  578. SHTCharToAnsi(pszFilename, szFilename, ARRAYSIZE(szFilename));
  579. // Cleanup any existing object
  580. SAFE_DELETE(m_pRoot);
  581. // Create the file object, and register the D3DRM templates for .X files
  582. if (FAILED(DirectXFileCreate(&pDXFile)))
  583. return E_FAIL;
  584. if (FAILED(pDXFile->RegisterTemplates((VOID*)D3DRM_XTEMPLATES,
  585. D3DRM_XTEMPLATE_BYTES)))
  586. {
  587. pDXFile->Release();
  588. return E_FAIL;
  589. }
  590. // Create an enumerator object, to enumerate through the .X file objects.
  591. // This will open the file in the current directory.
  592. hr = pDXFile->CreateEnumObject(szFilename, DXFILELOAD_FROMFILE, &pEnumObj);
  593. if (FAILED(hr))
  594. {
  595. CHAR szPath[MAX_PATH];
  596. GetCurrentDirectoryA(ARRAYSIZE(szPath), szPath);
  597. PathAppendA(szPath, szFilename);
  598. hr = pDXFile->CreateEnumObject(szPath, DXFILELOAD_FROMFILE, &pEnumObj);
  599. if (FAILED(hr))
  600. {
  601. pDXFile->Release();
  602. return hr;
  603. }
  604. }
  605. // Create a root object for the X file object
  606. m_pRoot = new CD3DFileObject(TEXT("D3DFile_Root"));
  607. // Cycle through each object. Parse meshes and frames as appropriate
  608. while(SUCCEEDED(hr = pEnumObj->GetNextDataObject(&pFileData)))
  609. {
  610. pFileData->GetType(&pGUID);
  611. if (*pGUID == TID_D3DRMFrame)
  612. ParseFrame(pFileData, m_pRoot);
  613. if (*pGUID == TID_D3DRMMesh)
  614. ParseMesh(pFileData, m_pRoot);
  615. pFileData->Release();
  616. }
  617. // Success will result in hr == DXFILEERR_NOMOREOBJECTS
  618. if (DXFILEERR_NOMOREOBJECTS == hr)
  619. hr = S_OK;
  620. else
  621. SAFE_DELETE(m_pRoot);
  622. pEnumObj->Release();
  623. pDXFile->Release();
  624. return hr;
  625. }
  626. //-----------------------------------------------------------------------------
  627. // Name: GetMeshVertices()
  628. // Desc: Traverse the hierarchy of frames and meshes that make up the file
  629. // object, and retrieves the vertices for the specified mesh.
  630. //-----------------------------------------------------------------------------
  631. HRESULT CD3DFile::GetMeshVertices(TCHAR* strName, D3DVERTEX** ppVertices,
  632. DWORD* pdwNumVertices)
  633. {
  634. CD3DFileObject* pObject = FindObject(strName);
  635. if (pObject)
  636. return pObject->GetMeshGeometry(ppVertices, pdwNumVertices, NULL, NULL);
  637. return E_FAIL;
  638. }
  639. //-----------------------------------------------------------------------------
  640. // Name: GetMeshVertices()
  641. // Desc: Traverse the hierarchy of frames and meshes that make up the file
  642. // object, and retrieves the vertices for the specified mesh.
  643. //-----------------------------------------------------------------------------
  644. HRESULT CD3DFile::GetMeshIndices(TCHAR* strName, WORD** ppIndices,
  645. DWORD* pdwNumIndices)
  646. {
  647. CD3DFileObject* pObject = FindObject(strName);
  648. if (pObject)
  649. return pObject->GetMeshGeometry(NULL, NULL, ppIndices, pdwNumIndices);
  650. return E_FAIL;
  651. }
  652. //-----------------------------------------------------------------------------
  653. // Name: EnumObjects()
  654. // Desc: Enumerates all objects in the file.
  655. //-----------------------------------------------------------------------------
  656. BOOL CD3DFileObject::EnumObjects(BOOL (*fnCallback)(CD3DFileObject*,D3DMATRIX*,VOID*),
  657. D3DMATRIX* pmat, VOID* pContext)
  658. {
  659. if (fnCallback(this, pmat, pContext) == TRUE)
  660. return TRUE;
  661. if (m_pChild)
  662. {
  663. // Concat matrix set
  664. D3DMATRIX matSave = (*pmat);
  665. (*pmat) = (*pmat) * m_mat;
  666. if (m_pChild->EnumObjects(fnCallback, pmat, pContext) == TRUE)
  667. return TRUE;
  668. // Restore matrix set
  669. (*pmat) = matSave;
  670. }
  671. if (m_pNext)
  672. if (m_pNext->EnumObjects(fnCallback, pmat, pContext) == TRUE)
  673. return TRUE;
  674. return FALSE;
  675. }
  676. //-----------------------------------------------------------------------------
  677. // Name: EnumObjects()
  678. // Desc: Enumerates all objects in the file.
  679. //-----------------------------------------------------------------------------
  680. VOID CD3DFile::EnumObjects(BOOL (*fnCallback)(CD3DFileObject*,D3DMATRIX*,VOID*),
  681. D3DMATRIX* pmat, VOID* pContext)
  682. {
  683. if (m_pRoot)
  684. {
  685. D3DMATRIX mat;
  686. if (pmat)
  687. mat = *pmat;
  688. else
  689. D3DUtil_SetIdentityMatrix(mat);
  690. m_pRoot->EnumObjects(fnCallback, &mat, pContext);
  691. }
  692. }
  693. //-----------------------------------------------------------------------------
  694. // Name: ScaleMeshCB()
  695. // Desc: Callback to scale a mesh
  696. //-----------------------------------------------------------------------------
  697. BOOL ScaleMeshCB(CD3DFileObject* pFileObject, D3DMATRIX*, VOID* pContext)
  698. {
  699. D3DVERTEX* pVertices;
  700. DWORD dwNumVertices;
  701. if (SUCCEEDED(pFileObject->GetMeshGeometry(&pVertices, &dwNumVertices,
  702. NULL, NULL)))
  703. {
  704. for(DWORD i=0; i<dwNumVertices; i++)
  705. {
  706. pVertices[i].x *= (*((FLOAT*)pContext));
  707. pVertices[i].y *= (*((FLOAT*)pContext));
  708. pVertices[i].z *= (*((FLOAT*)pContext));
  709. }
  710. }
  711. // Keep enumerating
  712. return FALSE;
  713. }
  714. //-----------------------------------------------------------------------------
  715. // Name: FindMeshCB()
  716. // Desc: Callback to scale a mesh
  717. //-----------------------------------------------------------------------------
  718. BOOL FindMeshCB(CD3DFileObject* pFileObject, D3DMATRIX*, VOID* pContext)
  719. {
  720. struct FINDMESHRECORD
  721. {
  722. TCHAR* strName;
  723. CD3DFileObject* pObject;
  724. };
  725. FINDMESHRECORD* data = (FINDMESHRECORD*)pContext;
  726. if (0 == lstrcmpi(data->strName, pFileObject->GetName()))
  727. {
  728. data->pObject = pFileObject;
  729. return TRUE;
  730. }
  731. // Keep enumerating
  732. return FALSE;
  733. }
  734. //-----------------------------------------------------------------------------
  735. // Name: Scale()
  736. // Desc: Scales all meshes in the file
  737. //-----------------------------------------------------------------------------
  738. VOID CD3DFile::Scale(FLOAT fScale)
  739. {
  740. EnumObjects(ScaleMeshCB, NULL, (VOID*)&fScale);
  741. }
  742. //-----------------------------------------------------------------------------
  743. // Name: FindObject()
  744. // Desc: Searches all meshes in file object and returns named mesh
  745. //-----------------------------------------------------------------------------
  746. CD3DFileObject* CD3DFile::FindObject(TCHAR* strName)
  747. {
  748. if (NULL == strName)
  749. return m_pRoot;
  750. struct FINDMESHRECORD
  751. {
  752. TCHAR* strName;
  753. CD3DFileObject* pObject;
  754. };
  755. FINDMESHRECORD data = { strName, NULL };
  756. EnumObjects(FindMeshCB, NULL, (VOID*)&data);
  757. return data.pObject;
  758. }
  759. //-----------------------------------------------------------------------------
  760. // Name: Render()
  761. // Desc: Renders the hierarchy of frames and meshes that make up the file
  762. // object
  763. //-----------------------------------------------------------------------------
  764. HRESULT CD3DFile::Render(LPDIRECT3DDEVICE7 pd3dDevice)
  765. {
  766. LPDIRECTDRAWSURFACE7 pddsSavedTexture;
  767. D3DMATRIX matSaved;
  768. D3DMATERIAL7 mtrlSaved;
  769. DWORD dwAlphaState, dwSrcBlendState, dwDestBlendState;
  770. if (m_pRoot)
  771. {
  772. // State render states that will be overwritten
  773. pd3dDevice->GetMaterial(&mtrlSaved);
  774. pd3dDevice->GetTexture(0, &pddsSavedTexture);
  775. pd3dDevice->GetTransform(D3DTRANSFORMSTATE_WORLD, &matSaved);
  776. pd3dDevice->GetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, &dwAlphaState);
  777. pd3dDevice->GetRenderState(D3DRENDERSTATE_SRCBLEND, &dwSrcBlendState);
  778. pd3dDevice->GetRenderState(D3DRENDERSTATE_DESTBLEND, &dwDestBlendState);
  779. // Render the opaque file object's hierarchy of frames and meshes
  780. m_pRoot->Render(pd3dDevice, FALSE);
  781. // Render the transparent file object's hierarchy of frames and meshes
  782. // pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
  783. // pd3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
  784. // pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
  785. // m_pRoot->Render(pd3dDevice, TRUE);
  786. // Restore the render states
  787. pd3dDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, dwAlphaState);
  788. pd3dDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, dwSrcBlendState);
  789. pd3dDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, dwDestBlendState);
  790. pd3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matSaved);
  791. pd3dDevice->SetTexture(0, pddsSavedTexture);
  792. pd3dDevice->SetMaterial(&mtrlSaved);
  793. // Keep the ref count of the texture consistent
  794. if (pddsSavedTexture)
  795. pddsSavedTexture->Release();
  796. }
  797. return S_OK;
  798. }