1 //-----------------------------------------------------------------------------
2 // File: DXUTMesh.cpp
3 //
4 // Desc: Support code for loading DirectX .X files.
5 //
6 // Copyright (c) Microsoft Corporation. All rights reserved.
7 //-----------------------------------------------------------------------------
8 #include "dxstdafx.h"
9 #include <dxfile.h>
10 #include <rmxfguid.h>
11 #include <rmxftmpl.h>
12 #include "DXUTMesh.h"
13 #undef min // use __min instead
14 #undef max // use __max instead
15
16
17
18
19 //-----------------------------------------------------------------------------
CDXUTMesh(LPCWSTR strName)20 CDXUTMesh::CDXUTMesh( LPCWSTR strName )
21 {
22 StringCchCopy( m_strName, 512, strName );
23 m_pMesh = NULL;
24 m_pMaterials = NULL;
25 m_pTextures = NULL;
26 m_bUseMaterials = TRUE;
27 m_pVB = NULL;
28 m_pIB = NULL;
29 m_pDecl = NULL;
30 m_strMaterials = NULL;
31 m_dwNumMaterials = 0;
32 m_dwNumVertices = 0;
33 m_dwNumFaces = 0;
34 m_dwBytesPerVertex = 0;
35 }
36
37
38
39
40 //-----------------------------------------------------------------------------
~CDXUTMesh()41 CDXUTMesh::~CDXUTMesh()
42 {
43 Destroy();
44 }
45
46
47
48
49 //-----------------------------------------------------------------------------
Create(LPDIRECT3DDEVICE9 pd3dDevice,LPCWSTR strFilename)50 HRESULT CDXUTMesh::Create( LPDIRECT3DDEVICE9 pd3dDevice, LPCWSTR strFilename )
51 {
52 WCHAR strPath[MAX_PATH];
53 LPD3DXBUFFER pAdjacencyBuffer = NULL;
54 LPD3DXBUFFER pMtrlBuffer = NULL;
55 HRESULT hr;
56
57 // Cleanup previous mesh if any
58 Destroy();
59
60 // Find the path for the file, and convert it to ANSI (for the D3DX API)
61 DXUTFindDXSDKMediaFileCch( strPath, sizeof(strPath) / sizeof(WCHAR), strFilename );
62
63 // Load the mesh
64 if( FAILED( hr = D3DXLoadMeshFromX( strPath, D3DXMESH_MANAGED, pd3dDevice,
65 &pAdjacencyBuffer, &pMtrlBuffer, NULL,
66 &m_dwNumMaterials, &m_pMesh ) ) )
67 {
68 return hr;
69 }
70
71 // Optimize the mesh for performance
72 if( FAILED( hr = m_pMesh->OptimizeInplace(
73 D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE,
74 (DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL, NULL, NULL ) ) )
75 {
76 SAFE_RELEASE( pAdjacencyBuffer );
77 SAFE_RELEASE( pMtrlBuffer );
78 return hr;
79 }
80
81 // Set strPath to the path of the mesh file
82 WCHAR *pLastBSlash = wcsrchr( strPath, L'\\' );
83 if( pLastBSlash )
84 *(pLastBSlash + 1) = L'\0';
85 else
86 *strPath = L'\0';
87
88 D3DXMATERIAL* d3dxMtrls = (D3DXMATERIAL*)pMtrlBuffer->GetBufferPointer();
89 hr = CreateMaterials( strPath, pd3dDevice, d3dxMtrls, m_dwNumMaterials );
90
91 SAFE_RELEASE( pAdjacencyBuffer );
92 SAFE_RELEASE( pMtrlBuffer );
93
94 // Extract data from m_pMesh for easy access
95 D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
96 m_dwNumVertices = m_pMesh->GetNumVertices();
97 m_dwNumFaces = m_pMesh->GetNumFaces();
98 m_dwBytesPerVertex = m_pMesh->GetNumBytesPerVertex();
99 m_pMesh->GetIndexBuffer( &m_pIB );
100 m_pMesh->GetVertexBuffer( &m_pVB );
101 m_pMesh->GetDeclaration( decl );
102 pd3dDevice->CreateVertexDeclaration( decl, &m_pDecl );
103
104 return hr;
105 }
106
107
108 //-----------------------------------------------------------------------------
Create(LPDIRECT3DDEVICE9 pd3dDevice,LPD3DXFILEDATA pFileData)109 HRESULT CDXUTMesh::Create( LPDIRECT3DDEVICE9 pd3dDevice,
110 LPD3DXFILEDATA pFileData )
111 {
112 LPD3DXBUFFER pMtrlBuffer = NULL;
113 LPD3DXBUFFER pAdjacencyBuffer = NULL;
114 HRESULT hr;
115
116 // Cleanup previous mesh if any
117 Destroy();
118
119 // Load the mesh from the DXFILEDATA object
120 if( FAILED( hr = D3DXLoadMeshFromXof( pFileData, D3DXMESH_MANAGED, pd3dDevice,
121 &pAdjacencyBuffer, &pMtrlBuffer, NULL,
122 &m_dwNumMaterials, &m_pMesh ) ) )
123 {
124 return hr;
125 }
126
127 // Optimize the mesh for performance
128 if( FAILED( hr = m_pMesh->OptimizeInplace(
129 D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE,
130 (DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL, NULL, NULL ) ) )
131 {
132 SAFE_RELEASE( pAdjacencyBuffer );
133 SAFE_RELEASE( pMtrlBuffer );
134 return hr;
135 }
136
137 D3DXMATERIAL* d3dxMtrls = (D3DXMATERIAL*)pMtrlBuffer->GetBufferPointer();
138 hr = CreateMaterials( L"", pd3dDevice, d3dxMtrls, m_dwNumMaterials );
139
140 SAFE_RELEASE( pAdjacencyBuffer );
141 SAFE_RELEASE( pMtrlBuffer );
142
143 // Extract data from m_pMesh for easy access
144 D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
145 m_dwNumVertices = m_pMesh->GetNumVertices();
146 m_dwNumFaces = m_pMesh->GetNumFaces();
147 m_dwBytesPerVertex = m_pMesh->GetNumBytesPerVertex();
148 m_pMesh->GetIndexBuffer( &m_pIB );
149 m_pMesh->GetVertexBuffer( &m_pVB );
150 m_pMesh->GetDeclaration( decl );
151 pd3dDevice->CreateVertexDeclaration( decl, &m_pDecl );
152
153 return hr;
154 }
155
156
157 //-----------------------------------------------------------------------------
Create(LPDIRECT3DDEVICE9 pd3dDevice,ID3DXMesh * pInMesh,D3DXMATERIAL * pd3dxMaterials,DWORD dwMaterials)158 HRESULT CDXUTMesh::Create( LPDIRECT3DDEVICE9 pd3dDevice, ID3DXMesh* pInMesh,
159 D3DXMATERIAL* pd3dxMaterials, DWORD dwMaterials )
160 {
161 // Cleanup previous mesh if any
162 Destroy();
163
164 // Optimize the mesh for performance
165 DWORD *rgdwAdjacency = NULL;
166 rgdwAdjacency = new DWORD[pInMesh->GetNumFaces() * 3];
167 if( rgdwAdjacency == NULL )
168 return E_OUTOFMEMORY;
169 pInMesh->GenerateAdjacency(1e-6f,rgdwAdjacency);
170
171 D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE];
172 pInMesh->GetDeclaration( decl );
173
174 DWORD dwOptions = pInMesh->GetOptions();
175 dwOptions &= ~(D3DXMESH_32BIT | D3DXMESH_SYSTEMMEM | D3DXMESH_WRITEONLY);
176 dwOptions |= D3DXMESH_MANAGED;
177 dwOptions |= D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE;
178
179 ID3DXMesh* pTempMesh = NULL;
180 if( FAILED( pInMesh->Optimize( dwOptions, rgdwAdjacency, NULL, NULL, NULL, &pTempMesh ) ) )
181 {
182 SAFE_DELETE_ARRAY( rgdwAdjacency );
183 return E_FAIL;
184 }
185
186 SAFE_DELETE_ARRAY( rgdwAdjacency );
187 SAFE_RELEASE( m_pMesh );
188 m_pMesh = pTempMesh;
189
190 HRESULT hr;
191 hr = CreateMaterials( L"", pd3dDevice, pd3dxMaterials, dwMaterials );
192
193 // Extract data from m_pMesh for easy access
194 m_dwNumVertices = m_pMesh->GetNumVertices();
195 m_dwNumFaces = m_pMesh->GetNumFaces();
196 m_dwBytesPerVertex = m_pMesh->GetNumBytesPerVertex();
197 m_pMesh->GetIndexBuffer( &m_pIB );
198 m_pMesh->GetVertexBuffer( &m_pVB );
199 m_pMesh->GetDeclaration( decl );
200 pd3dDevice->CreateVertexDeclaration( decl, &m_pDecl );
201
202 return hr;
203 }
204
205
206 //-----------------------------------------------------------------------------
CreateMaterials(LPCWSTR strPath,IDirect3DDevice9 * pd3dDevice,D3DXMATERIAL * d3dxMtrls,DWORD dwNumMaterials)207 HRESULT CDXUTMesh::CreateMaterials( LPCWSTR strPath, IDirect3DDevice9 *pd3dDevice, D3DXMATERIAL* d3dxMtrls, DWORD dwNumMaterials )
208 {
209 // Get material info for the mesh
210 // Get the array of materials out of the buffer
211 m_dwNumMaterials = dwNumMaterials;
212 if( d3dxMtrls && m_dwNumMaterials > 0 )
213 {
214 // Allocate memory for the materials and textures
215 m_pMaterials = new D3DMATERIAL9[m_dwNumMaterials];
216 if( m_pMaterials == NULL )
217 return E_OUTOFMEMORY;
218 m_pTextures = new LPDIRECT3DBASETEXTURE9[m_dwNumMaterials];
219 if( m_pTextures == NULL )
220 return E_OUTOFMEMORY;
221 m_strMaterials = new CHAR[m_dwNumMaterials][MAX_PATH];
222 if( m_strMaterials == NULL )
223 return E_OUTOFMEMORY;
224
225 // Copy each material and create its texture
226 for( DWORD i=0; i<m_dwNumMaterials; i++ )
227 {
228 // Copy the material
229 m_pMaterials[i] = d3dxMtrls[i].MatD3D;
230 m_pTextures[i] = NULL;
231
232 // Create a texture
233 if( d3dxMtrls[i].pTextureFilename )
234 {
235 StringCchCopyA( m_strMaterials[i], MAX_PATH, d3dxMtrls[i].pTextureFilename );
236
237 WCHAR strTexture[MAX_PATH];
238 WCHAR strTextureTemp[MAX_PATH];
239 D3DXIMAGE_INFO ImgInfo;
240
241 // First attempt to look for texture in the same folder as the input folder.
242 MultiByteToWideChar( CP_ACP, 0, d3dxMtrls[i].pTextureFilename, -1, strTextureTemp, MAX_PATH );
243 strTextureTemp[MAX_PATH-1] = 0;
244
245 StringCchCopy( strTexture, MAX_PATH, strPath );
246 StringCchCat( strTexture, MAX_PATH, strTextureTemp );
247
248 // Inspect the texture file to determine the texture type.
249 if( FAILED( D3DXGetImageInfoFromFile( strTexture, &ImgInfo ) ) )
250 {
251 // Search the media folder
252 if( FAILED( DXUTFindDXSDKMediaFileCch( strTexture, MAX_PATH, strTextureTemp ) ) )
253 continue; // Can't find. Skip.
254
255 D3DXGetImageInfoFromFile( strTexture, &ImgInfo );
256 }
257
258 // Call the appropriate loader according to the texture type.
259 switch( ImgInfo.ResourceType )
260 {
261 case D3DRTYPE_TEXTURE:
262 {
263 IDirect3DTexture9 *pTex;
264 if( SUCCEEDED( D3DXCreateTextureFromFile( pd3dDevice, strTexture, &pTex ) ) )
265 {
266 // Obtain the base texture interface
267 pTex->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&m_pTextures[i] );
268 // Release the specialized instance
269 pTex->Release();
270 }
271 break;
272 }
273 case D3DRTYPE_CUBETEXTURE:
274 {
275 IDirect3DCubeTexture9 *pTex;
276 if( SUCCEEDED( D3DXCreateCubeTextureFromFile( pd3dDevice, strTexture, &pTex ) ) )
277 {
278 // Obtain the base texture interface
279 pTex->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&m_pTextures[i] );
280 // Release the specialized instance
281 pTex->Release();
282 }
283 break;
284 }
285 case D3DRTYPE_VOLUMETEXTURE:
286 {
287 IDirect3DVolumeTexture9 *pTex;
288 if( SUCCEEDED( D3DXCreateVolumeTextureFromFile( pd3dDevice, strTexture, &pTex ) ) )
289 {
290 // Obtain the base texture interface
291 pTex->QueryInterface( IID_IDirect3DBaseTexture9, (LPVOID*)&m_pTextures[i] );
292 // Release the specialized instance
293 pTex->Release();
294 }
295 break;
296 }
297 }
298 }
299 }
300 }
301 return S_OK;
302 }
303
304
305 //-----------------------------------------------------------------------------
SetFVF(LPDIRECT3DDEVICE9 pd3dDevice,DWORD dwFVF)306 HRESULT CDXUTMesh::SetFVF( LPDIRECT3DDEVICE9 pd3dDevice, DWORD dwFVF )
307 {
308 LPD3DXMESH pTempMesh = NULL;
309
310 if( m_pMesh )
311 {
312 if( FAILED( m_pMesh->CloneMeshFVF( m_pMesh->GetOptions(), dwFVF,
313 pd3dDevice, &pTempMesh ) ) )
314 {
315 SAFE_RELEASE( pTempMesh );
316 return E_FAIL;
317 }
318
319 DWORD dwOldFVF = 0;
320 dwOldFVF = m_pMesh->GetFVF();
321 SAFE_RELEASE( m_pMesh );
322 m_pMesh = pTempMesh;
323
324 // Compute normals if they are being requested and
325 // the old mesh does not have them.
326 if( !(dwOldFVF & D3DFVF_NORMAL) && dwFVF & D3DFVF_NORMAL )
327 {
328 D3DXComputeNormals( m_pMesh, NULL );
329 }
330 }
331
332 return S_OK;
333 }
334
335
336
337
338 //-----------------------------------------------------------------------------
339 // Convert the mesh to the format specified by the given vertex declarations.
340 //-----------------------------------------------------------------------------
SetVertexDecl(LPDIRECT3DDEVICE9 pd3dDevice,const D3DVERTEXELEMENT9 * pDecl,bool bAutoComputeNormals,bool bAutoComputeTangents,bool bSplitVertexForOptimalTangents)341 HRESULT CDXUTMesh::SetVertexDecl( LPDIRECT3DDEVICE9 pd3dDevice, const D3DVERTEXELEMENT9 *pDecl,
342 bool bAutoComputeNormals, bool bAutoComputeTangents,
343 bool bSplitVertexForOptimalTangents )
344 {
345 LPD3DXMESH pTempMesh = NULL;
346
347 if( m_pMesh )
348 {
349 if( FAILED( m_pMesh->CloneMesh( m_pMesh->GetOptions(), pDecl,
350 pd3dDevice, &pTempMesh ) ) )
351 {
352 SAFE_RELEASE( pTempMesh );
353 return E_FAIL;
354 }
355 }
356
357
358 // Check if the old declaration contains a normal.
359 bool bHadNormal = false;
360 bool bHadTangent = false;
361 D3DVERTEXELEMENT9 aOldDecl[MAX_FVF_DECL_SIZE];
362 if( m_pMesh && SUCCEEDED( m_pMesh->GetDeclaration( aOldDecl ) ) )
363 {
364 for( UINT index = 0; index < D3DXGetDeclLength( aOldDecl ); ++index )
365 {
366 if( aOldDecl[index].Usage == D3DDECLUSAGE_NORMAL )
367 {
368 bHadNormal = true;
369 }
370 if( aOldDecl[index].Usage == D3DDECLUSAGE_TANGENT )
371 {
372 bHadTangent = true;
373 }
374 }
375 }
376
377 // Check if the new declaration contains a normal.
378 bool bHaveNormalNow = false;
379 bool bHaveTangentNow = false;
380 D3DVERTEXELEMENT9 aNewDecl[MAX_FVF_DECL_SIZE];
381 if( pTempMesh && SUCCEEDED( pTempMesh->GetDeclaration( aNewDecl ) ) )
382 {
383 for( UINT index = 0; index < D3DXGetDeclLength( aNewDecl ); ++index )
384 {
385 if( aNewDecl[index].Usage == D3DDECLUSAGE_NORMAL )
386 {
387 bHaveNormalNow = true;
388 }
389 if( aNewDecl[index].Usage == D3DDECLUSAGE_TANGENT )
390 {
391 bHaveTangentNow = true;
392 }
393 }
394 }
395
396 SAFE_RELEASE( m_pMesh );
397
398 if( pTempMesh )
399 {
400 m_pMesh = pTempMesh;
401
402 if( !bHadNormal && bHaveNormalNow && bAutoComputeNormals )
403 {
404 // Compute normals in case the meshes have them
405 D3DXComputeNormals( m_pMesh, NULL );
406 }
407
408 if( bHaveNormalNow && !bHadTangent && bHaveTangentNow && bAutoComputeTangents )
409 {
410 ID3DXMesh* pNewMesh;
411 HRESULT hr;
412
413 DWORD *rgdwAdjacency = NULL;
414 rgdwAdjacency = new DWORD[m_pMesh->GetNumFaces() * 3];
415 if( rgdwAdjacency == NULL )
416 return E_OUTOFMEMORY;
417 V( m_pMesh->GenerateAdjacency(1e-6f,rgdwAdjacency) );
418
419 float fPartialEdgeThreshold;
420 float fSingularPointThreshold;
421 float fNormalEdgeThreshold;
422 if( bSplitVertexForOptimalTangents )
423 {
424 fPartialEdgeThreshold = 0.01f;
425 fSingularPointThreshold = 0.25f;
426 fNormalEdgeThreshold = 0.01f;
427 }
428 else
429 {
430 fPartialEdgeThreshold = -1.01f;
431 fSingularPointThreshold = 0.01f;
432 fNormalEdgeThreshold = -1.01f;
433 }
434
435 // Compute tangents, which are required for normal mapping
436 hr = D3DXComputeTangentFrameEx( m_pMesh,
437 D3DDECLUSAGE_TEXCOORD, 0,
438 D3DDECLUSAGE_TANGENT, 0,
439 D3DX_DEFAULT, 0,
440 D3DDECLUSAGE_NORMAL, 0,
441 0, rgdwAdjacency,
442 fPartialEdgeThreshold, fSingularPointThreshold, fNormalEdgeThreshold,
443 &pNewMesh, NULL );
444
445 SAFE_DELETE_ARRAY( rgdwAdjacency );
446 if( FAILED(hr) )
447 return hr;
448
449 SAFE_RELEASE( m_pMesh );
450 m_pMesh = pNewMesh;
451 }
452 }
453
454 return S_OK;
455 }
456
457
458
459
460 //-----------------------------------------------------------------------------
RestoreDeviceObjects(LPDIRECT3DDEVICE9 pd3dDevice)461 HRESULT CDXUTMesh::RestoreDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice )
462 {
463 return S_OK;
464 }
465
466
467
468
469 //-----------------------------------------------------------------------------
InvalidateDeviceObjects()470 HRESULT CDXUTMesh::InvalidateDeviceObjects()
471 {
472 SAFE_RELEASE( m_pIB );
473 SAFE_RELEASE( m_pVB );
474 SAFE_RELEASE( m_pDecl );
475
476 return S_OK;
477 }
478
479
480
481
482 //-----------------------------------------------------------------------------
Destroy()483 HRESULT CDXUTMesh::Destroy()
484 {
485 InvalidateDeviceObjects();
486 for( UINT i=0; i<m_dwNumMaterials; i++ )
487 SAFE_RELEASE( m_pTextures[i] );
488 SAFE_DELETE_ARRAY( m_pTextures );
489 SAFE_DELETE_ARRAY( m_pMaterials );
490 SAFE_DELETE_ARRAY( m_strMaterials );
491
492 SAFE_RELEASE( m_pMesh );
493
494 m_dwNumMaterials = 0L;
495
496 return S_OK;
497 }
498
499
500
501
502 //-----------------------------------------------------------------------------
Render(LPDIRECT3DDEVICE9 pd3dDevice,bool bDrawOpaqueSubsets,bool bDrawAlphaSubsets)503 HRESULT CDXUTMesh::Render( LPDIRECT3DDEVICE9 pd3dDevice, bool bDrawOpaqueSubsets,
504 bool bDrawAlphaSubsets )
505 {
506 if( NULL == m_pMesh )
507 return E_FAIL;
508
509 // Frist, draw the subsets without alpha
510 if( bDrawOpaqueSubsets )
511 {
512 for( DWORD i=0; i<m_dwNumMaterials; i++ )
513 {
514 if( m_bUseMaterials )
515 {
516 if( m_pMaterials[i].Diffuse.a < 1.0f )
517 continue;
518 pd3dDevice->SetMaterial( &m_pMaterials[i] );
519 pd3dDevice->SetTexture( 0, m_pTextures[i] );
520 }
521 m_pMesh->DrawSubset( i );
522 }
523 }
524
525 // Then, draw the subsets with alpha
526 if( bDrawAlphaSubsets && m_bUseMaterials )
527 {
528 for( DWORD i=0; i<m_dwNumMaterials; i++ )
529 {
530 if( m_pMaterials[i].Diffuse.a == 1.0f )
531 continue;
532
533 // Set the material and texture
534 pd3dDevice->SetMaterial( &m_pMaterials[i] );
535 pd3dDevice->SetTexture( 0, m_pTextures[i] );
536 m_pMesh->DrawSubset( i );
537 }
538 }
539
540 return S_OK;
541 }
542
543
544
545
546 //-----------------------------------------------------------------------------
Render(ID3DXEffect * pEffect,D3DXHANDLE hTexture,D3DXHANDLE hDiffuse,D3DXHANDLE hAmbient,D3DXHANDLE hSpecular,D3DXHANDLE hEmissive,D3DXHANDLE hPower,bool bDrawOpaqueSubsets,bool bDrawAlphaSubsets)547 HRESULT CDXUTMesh::Render( ID3DXEffect *pEffect,
548 D3DXHANDLE hTexture,
549 D3DXHANDLE hDiffuse,
550 D3DXHANDLE hAmbient,
551 D3DXHANDLE hSpecular,
552 D3DXHANDLE hEmissive,
553 D3DXHANDLE hPower,
554 bool bDrawOpaqueSubsets,
555 bool bDrawAlphaSubsets )
556 {
557 if( NULL == m_pMesh )
558 return E_FAIL;
559
560 UINT cPasses;
561 // Frist, draw the subsets without alpha
562 if( bDrawOpaqueSubsets )
563 {
564 pEffect->Begin( &cPasses, 0 );
565 for( UINT p = 0; p < cPasses; ++p )
566 {
567 pEffect->BeginPass( p );
568 for( DWORD i=0; i<m_dwNumMaterials; i++ )
569 {
570 if( m_bUseMaterials )
571 {
572 if( m_pMaterials[i].Diffuse.a < 1.0f )
573 continue;
574 if( hTexture )
575 pEffect->SetTexture( hTexture, m_pTextures[i] );
576 // D3DCOLORVALUE and D3DXVECTOR4 are data-wise identical.
577 // No conversion is needed.
578 if( hDiffuse )
579 pEffect->SetVector( hDiffuse, (D3DXVECTOR4*)&m_pMaterials[i].Diffuse );
580 if( hAmbient )
581 pEffect->SetVector( hAmbient, (D3DXVECTOR4*)&m_pMaterials[i].Ambient );
582 if( hSpecular )
583 pEffect->SetVector( hSpecular, (D3DXVECTOR4*)&m_pMaterials[i].Specular );
584 if( hEmissive )
585 pEffect->SetVector( hEmissive, (D3DXVECTOR4*)&m_pMaterials[i].Emissive );
586 if( hPower )
587 pEffect->SetFloat( hPower, m_pMaterials[i].Power );
588 pEffect->CommitChanges();
589 }
590 m_pMesh->DrawSubset( i );
591 }
592 pEffect->EndPass();
593 }
594 pEffect->End();
595 }
596
597 // Then, draw the subsets with alpha
598 if( bDrawAlphaSubsets && m_bUseMaterials )
599 {
600 pEffect->Begin( &cPasses, 0 );
601 for( UINT p = 0; p < cPasses; ++p )
602 {
603 pEffect->BeginPass( p );
604 for( DWORD i=0; i<m_dwNumMaterials; i++ )
605 {
606 if( m_bUseMaterials )
607 {
608 if( m_pMaterials[i].Diffuse.a == 1.0f )
609 continue;
610 if( hTexture )
611 pEffect->SetTexture( hTexture, m_pTextures[i] );
612 // D3DCOLORVALUE and D3DXVECTOR4 are data-wise identical.
613 // No conversion is needed.
614 if( hDiffuse )
615 pEffect->SetVector( hDiffuse, (D3DXVECTOR4*)&m_pMaterials[i].Diffuse );
616 if( hAmbient )
617 pEffect->SetVector( hAmbient, (D3DXVECTOR4*)&m_pMaterials[i].Ambient );
618 if( hSpecular )
619 pEffect->SetVector( hSpecular, (D3DXVECTOR4*)&m_pMaterials[i].Specular );
620 if( hEmissive )
621 pEffect->SetVector( hEmissive, (D3DXVECTOR4*)&m_pMaterials[i].Emissive );
622 if( hPower )
623 pEffect->SetFloat( hPower, m_pMaterials[i].Power );
624 pEffect->CommitChanges();
625 }
626 m_pMesh->DrawSubset( i );
627 }
628 pEffect->EndPass();
629 }
630 pEffect->End();
631 }
632
633 return S_OK;
634 }
635
RenderTokamak(ID3DXEffect * pEffect,D3DXHANDLE hDiffuse,D3DXVECTOR4 * pDiffuse,D3DXHANDLE hAmbient,D3DXVECTOR4 * pAmbient,D3DXHANDLE hSpecular,D3DXVECTOR4 * pSpecular,D3DXHANDLE hPower,float Power,bool bDrawOpaqueSubsets,bool bDrawAlphaSubsets)636 HRESULT CDXUTMesh::RenderTokamak( ID3DXEffect *pEffect,
637 D3DXHANDLE hDiffuse, D3DXVECTOR4* pDiffuse,
638 D3DXHANDLE hAmbient, D3DXVECTOR4* pAmbient,
639 D3DXHANDLE hSpecular, D3DXVECTOR4* pSpecular,
640 D3DXHANDLE hPower, float Power,
641 bool bDrawOpaqueSubsets,
642 bool bDrawAlphaSubsets )
643 {
644 if( NULL == m_pMesh )
645 return E_FAIL;
646
647 UINT cPasses;
648 // Frist, draw the subsets without alpha
649 if( bDrawOpaqueSubsets )
650 {
651 pEffect->Begin( &cPasses, 0 );
652 for( UINT p = 0; p < cPasses; ++p )
653 {
654 pEffect->BeginPass( p );
655 for( DWORD i=0; i<m_dwNumMaterials; i++ )
656 {
657 // D3DCOLORVALUE and D3DXVECTOR4 are data-wise identical.
658 // No conversion is needed.
659 if( hDiffuse && pDiffuse->w < 1.0f)
660 continue;
661
662 if( hDiffuse)
663 pEffect->SetVector( hDiffuse, pDiffuse );
664 if( hAmbient )
665 pEffect->SetVector( hAmbient, pAmbient );
666 if( hSpecular )
667 pEffect->SetVector( hSpecular, pSpecular );
668 if( hPower )
669 pEffect->SetFloat( hPower, Power );
670
671 pEffect->CommitChanges();
672
673 m_pMesh->DrawSubset( i );
674 }
675 pEffect->EndPass();
676 }
677 pEffect->End();
678 }
679
680 // Then, draw the subsets with alpha
681 if( bDrawAlphaSubsets && m_bUseMaterials )
682 {
683 pEffect->Begin( &cPasses, 0 );
684 for( UINT p = 0; p < cPasses; ++p )
685 {
686 pEffect->BeginPass( p );
687 for( DWORD i=0; i<m_dwNumMaterials; i++ )
688 {
689 if( hDiffuse == NULL || pDiffuse->w == 1.0f)
690 continue;
691
692 if( hDiffuse)
693 pEffect->SetVector( hDiffuse, pDiffuse );
694 if( hAmbient )
695 pEffect->SetVector( hAmbient, pAmbient );
696 if( hSpecular )
697 pEffect->SetVector( hSpecular, pSpecular );
698 if( hPower )
699 pEffect->SetFloat( hPower, Power );
700
701 pEffect->CommitChanges();
702
703 m_pMesh->DrawSubset( i );
704 }
705 pEffect->EndPass();
706 }
707 pEffect->End();
708 }
709
710 return S_OK;
711 }
712
713
714
715 //-----------------------------------------------------------------------------
CDXUTMeshFrame(LPCWSTR strName)716 CDXUTMeshFrame::CDXUTMeshFrame( LPCWSTR strName )
717 {
718 StringCchCopy( m_strName, 512, strName );
719 D3DXMatrixIdentity( &m_mat );
720 m_pMesh = NULL;
721
722 m_pChild = NULL;
723 m_pNext = NULL;
724 }
725
726
727
728
729 //-----------------------------------------------------------------------------
~CDXUTMeshFrame()730 CDXUTMeshFrame::~CDXUTMeshFrame()
731 {
732 SAFE_DELETE( m_pChild );
733 SAFE_DELETE( m_pNext );
734 }
735
736
737
738
739 //-----------------------------------------------------------------------------
EnumMeshes(bool (* EnumMeshCB)(CDXUTMesh *,void *),void * pContext)740 bool CDXUTMeshFrame::EnumMeshes( bool (*EnumMeshCB)(CDXUTMesh*,void*),
741 void* pContext )
742 {
743 if( m_pMesh )
744 EnumMeshCB( m_pMesh, pContext );
745 if( m_pChild )
746 m_pChild->EnumMeshes( EnumMeshCB, pContext );
747 if( m_pNext )
748 m_pNext->EnumMeshes( EnumMeshCB, pContext );
749
750 return TRUE;
751 }
752
753
754
755
756 //-----------------------------------------------------------------------------
FindMesh(LPCWSTR strMeshName)757 CDXUTMesh* CDXUTMeshFrame::FindMesh( LPCWSTR strMeshName )
758 {
759 CDXUTMesh* pMesh;
760
761 if( m_pMesh )
762 if( !lstrcmpi( m_pMesh->m_strName, strMeshName ) )
763 return m_pMesh;
764
765 if( m_pChild )
766 if( NULL != ( pMesh = m_pChild->FindMesh( strMeshName ) ) )
767 return pMesh;
768
769 if( m_pNext )
770 if( NULL != ( pMesh = m_pNext->FindMesh( strMeshName ) ) )
771 return pMesh;
772
773 return NULL;
774 }
775
776
777
778
779 //-----------------------------------------------------------------------------
FindFrame(LPCWSTR strFrameName)780 CDXUTMeshFrame* CDXUTMeshFrame::FindFrame( LPCWSTR strFrameName )
781 {
782 CDXUTMeshFrame* pFrame;
783
784 if( !lstrcmpi( m_strName, strFrameName ) )
785 return this;
786
787 if( m_pChild )
788 if( NULL != ( pFrame = m_pChild->FindFrame( strFrameName ) ) )
789 return pFrame;
790
791 if( m_pNext )
792 if( NULL != ( pFrame = m_pNext->FindFrame( strFrameName ) ) )
793 return pFrame;
794
795 return NULL;
796 }
797
798
799
800
801 //-----------------------------------------------------------------------------
Destroy()802 HRESULT CDXUTMeshFrame::Destroy()
803 {
804 if( m_pMesh ) m_pMesh->Destroy();
805 if( m_pChild ) m_pChild->Destroy();
806 if( m_pNext ) m_pNext->Destroy();
807
808 SAFE_DELETE( m_pMesh );
809 SAFE_DELETE( m_pNext );
810 SAFE_DELETE( m_pChild );
811
812 return S_OK;
813 }
814
815
816
817
818 //-----------------------------------------------------------------------------
RestoreDeviceObjects(LPDIRECT3DDEVICE9 pd3dDevice)819 HRESULT CDXUTMeshFrame::RestoreDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice )
820 {
821 if( m_pMesh ) m_pMesh->RestoreDeviceObjects( pd3dDevice );
822 if( m_pChild ) m_pChild->RestoreDeviceObjects( pd3dDevice );
823 if( m_pNext ) m_pNext->RestoreDeviceObjects( pd3dDevice );
824 return S_OK;
825 }
826
827
828
829
830 //-----------------------------------------------------------------------------
InvalidateDeviceObjects()831 HRESULT CDXUTMeshFrame::InvalidateDeviceObjects()
832 {
833 if( m_pMesh ) m_pMesh->InvalidateDeviceObjects();
834 if( m_pChild ) m_pChild->InvalidateDeviceObjects();
835 if( m_pNext ) m_pNext->InvalidateDeviceObjects();
836 return S_OK;
837 }
838
839
840
841
842 //-----------------------------------------------------------------------------
Render(LPDIRECT3DDEVICE9 pd3dDevice,bool bDrawOpaqueSubsets,bool bDrawAlphaSubsets,D3DXMATRIX * pmatWorldMatrix)843 HRESULT CDXUTMeshFrame::Render( LPDIRECT3DDEVICE9 pd3dDevice, bool bDrawOpaqueSubsets,
844 bool bDrawAlphaSubsets, D3DXMATRIX* pmatWorldMatrix )
845 {
846 // For pure devices, specify the world transform. If the world transform is not
847 // specified on pure devices, this function will fail.
848
849 D3DXMATRIX matSavedWorld, matWorld;
850
851 if ( NULL == pmatWorldMatrix )
852 pd3dDevice->GetTransform( D3DTS_WORLD, &matSavedWorld );
853 else
854 matSavedWorld = *pmatWorldMatrix;
855
856 D3DXMatrixMultiply( &matWorld, &m_mat, &matSavedWorld );
857 pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
858
859 if( m_pMesh )
860 m_pMesh->Render( pd3dDevice, bDrawOpaqueSubsets, bDrawAlphaSubsets );
861
862 if( m_pChild )
863 m_pChild->Render( pd3dDevice, bDrawOpaqueSubsets, bDrawAlphaSubsets, &matWorld );
864
865 pd3dDevice->SetTransform( D3DTS_WORLD, &matSavedWorld );
866
867 if( m_pNext )
868 m_pNext->Render( pd3dDevice, bDrawOpaqueSubsets, bDrawAlphaSubsets, &matSavedWorld );
869
870 return S_OK;
871 }
872
873
874
875
876 //-----------------------------------------------------------------------------
LoadFrame(LPDIRECT3DDEVICE9 pd3dDevice,LPD3DXFILEDATA pFileData,CDXUTMeshFrame * pParentFrame)877 HRESULT CDXUTMeshFile::LoadFrame( LPDIRECT3DDEVICE9 pd3dDevice,
878 LPD3DXFILEDATA pFileData,
879 CDXUTMeshFrame* pParentFrame )
880 {
881 LPD3DXFILEDATA pChildData = NULL;
882 GUID Guid;
883 SIZE_T cbSize;
884 CDXUTMeshFrame* pCurrentFrame;
885 HRESULT hr;
886
887 // Get the type of the object
888 if( FAILED( hr = pFileData->GetType( &Guid ) ) )
889 return hr;
890
891 if( Guid == TID_D3DRMMesh )
892 {
893 hr = LoadMesh( pd3dDevice, pFileData, pParentFrame );
894 if( FAILED(hr) )
895 return hr;
896 }
897 if( Guid == TID_D3DRMFrameTransformMatrix )
898 {
899 D3DXMATRIX* pmatMatrix;
900 hr = pFileData->Lock(&cbSize, (LPCVOID*)&pmatMatrix );
901 if( FAILED(hr) )
902 return hr;
903
904 // Update the parent's matrix with the new one
905 pParentFrame->SetMatrix( pmatMatrix );
906 }
907 if( Guid == TID_D3DRMFrame )
908 {
909 // Get the frame name
910 CHAR strAnsiName[512] = "";
911 WCHAR strName[512];
912 SIZE_T dwNameLength = 512;
913 SIZE_T cChildren;
914 if( FAILED( hr = pFileData->GetName( strAnsiName, &dwNameLength ) ) )
915 return hr;
916
917 MultiByteToWideChar( CP_ACP, 0, strAnsiName, -1, strName, 512 );
918 strName[511] = 0;
919
920 // Create the frame
921 pCurrentFrame = new CDXUTMeshFrame( strName );
922 if( pCurrentFrame == NULL )
923 return E_OUTOFMEMORY;
924
925 pCurrentFrame->m_pNext = pParentFrame->m_pChild;
926 pParentFrame->m_pChild = pCurrentFrame;
927
928 // Enumerate child objects
929 pFileData->GetChildren(&cChildren);
930 for (UINT iChild = 0; iChild < cChildren; iChild++)
931 {
932 // Query the child for its FileData
933 hr = pFileData->GetChild(iChild, &pChildData );
934 if( SUCCEEDED(hr) )
935 {
936 hr = LoadFrame( pd3dDevice, pChildData, pCurrentFrame );
937 SAFE_RELEASE( pChildData );
938 }
939
940 if( FAILED(hr) )
941 return hr;
942 }
943 }
944
945 return S_OK;
946 }
947
948
949
950
951 //-----------------------------------------------------------------------------
LoadMesh(LPDIRECT3DDEVICE9 pd3dDevice,LPD3DXFILEDATA pFileData,CDXUTMeshFrame * pParentFrame)952 HRESULT CDXUTMeshFile::LoadMesh( LPDIRECT3DDEVICE9 pd3dDevice,
953 LPD3DXFILEDATA pFileData,
954 CDXUTMeshFrame* pParentFrame )
955 {
956 // Currently only allowing one mesh per frame
957 if( pParentFrame->m_pMesh )
958 return E_FAIL;
959
960 // Get the mesh name
961 CHAR strAnsiName[512] = {0};
962 WCHAR strName[512];
963 SIZE_T dwNameLength = 512;
964 HRESULT hr;
965 if( FAILED( hr = pFileData->GetName( strAnsiName, &dwNameLength ) ) )
966 return hr;
967
968 MultiByteToWideChar( CP_ACP, 0, strAnsiName, -1, strName, 512 );
969 strName[511] = 0;
970
971 // Create the mesh
972 pParentFrame->m_pMesh = new CDXUTMesh( strName );
973 if( pParentFrame->m_pMesh == NULL )
974 return E_OUTOFMEMORY;
975 pParentFrame->m_pMesh->Create( pd3dDevice, pFileData );
976
977 return S_OK;
978 }
979
980
981
982
983 //-----------------------------------------------------------------------------
CreateFromResource(LPDIRECT3DDEVICE9 pd3dDevice,LPCWSTR strResource,LPCWSTR strType)984 HRESULT CDXUTMeshFile::CreateFromResource( LPDIRECT3DDEVICE9 pd3dDevice, LPCWSTR strResource, LPCWSTR strType )
985 {
986 LPD3DXFILE pDXFile = NULL;
987 LPD3DXFILEENUMOBJECT pEnumObj = NULL;
988 LPD3DXFILEDATA pFileData = NULL;
989 HRESULT hr;
990 SIZE_T cChildren;
991
992 // Create a x file object
993 if( FAILED( hr = D3DXFileCreate( &pDXFile ) ) )
994 return E_FAIL;
995
996 // Register templates for d3drm and patch extensions.
997 if( FAILED( hr = pDXFile->RegisterTemplates( (void*)D3DRM_XTEMPLATES,
998 D3DRM_XTEMPLATE_BYTES ) ) )
999 {
1000 SAFE_RELEASE( pDXFile );
1001 return E_FAIL;
1002 }
1003
1004 CHAR strTypeAnsi[MAX_PATH];
1005 CHAR strResourceAnsi[MAX_PATH];
1006
1007 WideCharToMultiByte( CP_ACP, 0, strType, -1, strTypeAnsi, MAX_PATH, NULL, NULL );
1008 strTypeAnsi[MAX_PATH-1] = 0;
1009
1010 WideCharToMultiByte( CP_ACP, 0, strResource, -1, strResourceAnsi, MAX_PATH, NULL, NULL );
1011 strResourceAnsi[MAX_PATH-1] = 0;
1012
1013 D3DXF_FILELOADRESOURCE dxlr;
1014 dxlr.hModule = NULL;
1015 dxlr.lpName = strResourceAnsi;
1016 dxlr.lpType = strTypeAnsi;
1017
1018 // Create enum object
1019 hr = pDXFile->CreateEnumObject( (void*)&dxlr, D3DXF_FILELOAD_FROMRESOURCE,
1020 &pEnumObj );
1021 if( FAILED(hr) )
1022 {
1023 SAFE_RELEASE( pDXFile );
1024 return hr;
1025 }
1026
1027 // Enumerate top level objects (which are always frames)
1028 pEnumObj->GetChildren(&cChildren);
1029 for (UINT iChild = 0; iChild < cChildren; iChild++)
1030 {
1031 hr = pEnumObj->GetChild(iChild, &pFileData);
1032 if (FAILED(hr))
1033 return hr;
1034
1035 hr = LoadFrame( pd3dDevice, pFileData, this );
1036 SAFE_RELEASE( pFileData );
1037 if( FAILED(hr) )
1038 {
1039 SAFE_RELEASE( pEnumObj );
1040 SAFE_RELEASE( pDXFile );
1041 return E_FAIL;
1042 }
1043 }
1044
1045 SAFE_RELEASE( pFileData );
1046 SAFE_RELEASE( pEnumObj );
1047 SAFE_RELEASE( pDXFile );
1048
1049 return S_OK;
1050 }
1051
1052
1053
1054
1055 //-----------------------------------------------------------------------------
Create(LPDIRECT3DDEVICE9 pd3dDevice,LPCWSTR strFilename)1056 HRESULT CDXUTMeshFile::Create( LPDIRECT3DDEVICE9 pd3dDevice, LPCWSTR strFilename )
1057 {
1058 LPD3DXFILE pDXFile = NULL;
1059 LPD3DXFILEENUMOBJECT pEnumObj = NULL;
1060 LPD3DXFILEDATA pFileData = NULL;
1061 HRESULT hr;
1062 SIZE_T cChildren;
1063
1064 // Create a x file object
1065 if( FAILED( hr = D3DXFileCreate( &pDXFile ) ) )
1066 return E_FAIL;
1067
1068 // Register templates for d3drm and patch extensions.
1069 if( FAILED( hr = pDXFile->RegisterTemplates( (void*)D3DRM_XTEMPLATES,
1070 D3DRM_XTEMPLATE_BYTES ) ) )
1071 {
1072 SAFE_RELEASE( pDXFile );
1073 return E_FAIL;
1074 }
1075
1076 // Find the path to the file, and convert it to ANSI (for the D3DXOF API)
1077 WCHAR strPath[MAX_PATH];
1078 CHAR strPathANSI[MAX_PATH];
1079 DXUTFindDXSDKMediaFileCch( strPath, sizeof(strPath) / sizeof(WCHAR), strFilename );
1080
1081
1082 WideCharToMultiByte( CP_ACP, 0, strPath, -1, strPathANSI, MAX_PATH, NULL, NULL );
1083 strPathANSI[MAX_PATH-1] = 0;
1084
1085
1086 // Create enum object
1087 hr = pDXFile->CreateEnumObject( (void*)strPathANSI, D3DXF_FILELOAD_FROMFILE,
1088 &pEnumObj );
1089 if( FAILED(hr) )
1090 {
1091 SAFE_RELEASE( pDXFile );
1092 return hr;
1093 }
1094
1095 // Enumerate top level objects (which are always frames)
1096 pEnumObj->GetChildren(&cChildren);
1097 for (UINT iChild = 0; iChild < cChildren; iChild++)
1098 {
1099 hr = pEnumObj->GetChild(iChild, &pFileData);
1100 if (FAILED(hr))
1101 return hr;
1102
1103 hr = LoadFrame( pd3dDevice, pFileData, this );
1104 SAFE_RELEASE( pFileData );
1105 if( FAILED(hr) )
1106 {
1107 SAFE_RELEASE( pEnumObj );
1108 SAFE_RELEASE( pDXFile );
1109 return E_FAIL;
1110 }
1111 }
1112
1113 SAFE_RELEASE( pFileData );
1114 SAFE_RELEASE( pEnumObj );
1115 SAFE_RELEASE( pDXFile );
1116
1117 return S_OK;
1118 }
1119
1120
1121
1122
1123 //-----------------------------------------------------------------------------
Render(LPDIRECT3DDEVICE9 pd3dDevice,D3DXMATRIX * pmatWorldMatrix)1124 HRESULT CDXUTMeshFile::Render( LPDIRECT3DDEVICE9 pd3dDevice, D3DXMATRIX* pmatWorldMatrix )
1125 {
1126
1127 // For pure devices, specify the world transform. If the world transform is not
1128 // specified on pure devices, this function will fail.
1129
1130 // Set up the world transformation
1131 D3DXMATRIX matSavedWorld, matWorld;
1132
1133 if ( NULL == pmatWorldMatrix )
1134 pd3dDevice->GetTransform( D3DTS_WORLD, &matSavedWorld );
1135 else
1136 matSavedWorld = *pmatWorldMatrix;
1137
1138 D3DXMatrixMultiply( &matWorld, &matSavedWorld, &m_mat );
1139 pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
1140
1141 // Render opaque subsets in the meshes
1142 if( m_pChild )
1143 m_pChild->Render( pd3dDevice, TRUE, FALSE, &matWorld );
1144
1145 // Enable alpha blending
1146 pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
1147 pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
1148 pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
1149
1150 // Render alpha subsets in the meshes
1151 if( m_pChild )
1152 m_pChild->Render( pd3dDevice, FALSE, TRUE, &matWorld );
1153
1154 // Restore state
1155 pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
1156 pd3dDevice->SetTransform( D3DTS_WORLD, &matSavedWorld );
1157
1158 return S_OK;
1159 }
1160
1161
1162
1163
1164