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