source: GTP-Internal/trunk/App/Demos/Illum/Ocean/Common/DXUTMesh.cpp @ 1777

Revision 1777, 34.2 KB checked in by szirmay, 18 years ago (diff)
Line 
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//-----------------------------------------------------------------------------
20CDXUTMesh::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//-----------------------------------------------------------------------------
41CDXUTMesh::~CDXUTMesh()
42{
43    Destroy();
44}
45
46
47
48
49//-----------------------------------------------------------------------------
50HRESULT 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//-----------------------------------------------------------------------------
109HRESULT 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//-----------------------------------------------------------------------------
158HRESULT 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//-----------------------------------------------------------------------------
207HRESULT 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//-----------------------------------------------------------------------------
306HRESULT 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//-----------------------------------------------------------------------------
341HRESULT 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//-----------------------------------------------------------------------------
461HRESULT CDXUTMesh::RestoreDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice )
462{
463    return S_OK;
464}
465
466
467
468
469//-----------------------------------------------------------------------------
470HRESULT 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//-----------------------------------------------------------------------------
483HRESULT 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//-----------------------------------------------------------------------------
503HRESULT 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//-----------------------------------------------------------------------------
547HRESULT 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
636
637
638
639//-----------------------------------------------------------------------------
640CDXUTMeshFrame::CDXUTMeshFrame( LPCWSTR strName )
641{
642    StringCchCopy( m_strName, 512, strName );
643    D3DXMatrixIdentity( &m_mat );
644    m_pMesh  = NULL;
645
646    m_pChild = NULL;
647    m_pNext  = NULL;
648}
649
650
651
652
653//-----------------------------------------------------------------------------
654CDXUTMeshFrame::~CDXUTMeshFrame()
655{
656    SAFE_DELETE( m_pChild );
657    SAFE_DELETE( m_pNext );
658}
659
660
661
662
663//-----------------------------------------------------------------------------
664bool CDXUTMeshFrame::EnumMeshes( bool (*EnumMeshCB)(CDXUTMesh*,void*),
665                            void* pContext )
666{
667    if( m_pMesh )
668        EnumMeshCB( m_pMesh, pContext );
669    if( m_pChild )
670        m_pChild->EnumMeshes( EnumMeshCB, pContext );
671    if( m_pNext )
672        m_pNext->EnumMeshes( EnumMeshCB, pContext );
673
674    return TRUE;
675}
676
677
678
679
680//-----------------------------------------------------------------------------
681CDXUTMesh* CDXUTMeshFrame::FindMesh( LPCWSTR strMeshName )
682{
683    CDXUTMesh* pMesh;
684
685    if( m_pMesh )
686        if( !lstrcmpi( m_pMesh->m_strName, strMeshName ) )
687            return m_pMesh;
688
689    if( m_pChild )
690        if( NULL != ( pMesh = m_pChild->FindMesh( strMeshName ) ) )
691            return pMesh;
692
693    if( m_pNext )
694        if( NULL != ( pMesh = m_pNext->FindMesh( strMeshName ) ) )
695            return pMesh;
696
697    return NULL;
698}
699
700
701
702
703//-----------------------------------------------------------------------------
704CDXUTMeshFrame* CDXUTMeshFrame::FindFrame( LPCWSTR strFrameName )
705{
706    CDXUTMeshFrame* pFrame;
707
708    if( !lstrcmpi( m_strName, strFrameName ) )
709        return this;
710
711    if( m_pChild )
712        if( NULL != ( pFrame = m_pChild->FindFrame( strFrameName ) ) )
713            return pFrame;
714
715    if( m_pNext )
716        if( NULL != ( pFrame = m_pNext->FindFrame( strFrameName ) ) )
717            return pFrame;
718
719    return NULL;
720}
721
722
723
724
725//-----------------------------------------------------------------------------
726HRESULT CDXUTMeshFrame::Destroy()
727{
728    if( m_pMesh )  m_pMesh->Destroy();
729    if( m_pChild ) m_pChild->Destroy();
730    if( m_pNext )  m_pNext->Destroy();
731
732    SAFE_DELETE( m_pMesh );
733    SAFE_DELETE( m_pNext );
734    SAFE_DELETE( m_pChild );
735
736    return S_OK;
737}
738
739
740
741
742//-----------------------------------------------------------------------------
743HRESULT CDXUTMeshFrame::RestoreDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice )
744{
745    if( m_pMesh )  m_pMesh->RestoreDeviceObjects( pd3dDevice );
746    if( m_pChild ) m_pChild->RestoreDeviceObjects( pd3dDevice );
747    if( m_pNext )  m_pNext->RestoreDeviceObjects( pd3dDevice );
748    return S_OK;
749}
750
751
752
753
754//-----------------------------------------------------------------------------
755HRESULT CDXUTMeshFrame::InvalidateDeviceObjects()
756{
757    if( m_pMesh )  m_pMesh->InvalidateDeviceObjects();
758    if( m_pChild ) m_pChild->InvalidateDeviceObjects();
759    if( m_pNext )  m_pNext->InvalidateDeviceObjects();
760    return S_OK;
761}
762
763
764
765
766//-----------------------------------------------------------------------------
767HRESULT CDXUTMeshFrame::Render( LPDIRECT3DDEVICE9 pd3dDevice, bool bDrawOpaqueSubsets,
768                           bool bDrawAlphaSubsets, D3DXMATRIX* pmatWorldMatrix )
769{
770    // For pure devices, specify the world transform. If the world transform is not
771    // specified on pure devices, this function will fail.
772
773    D3DXMATRIX matSavedWorld, matWorld;
774
775    if ( NULL == pmatWorldMatrix )
776        pd3dDevice->GetTransform( D3DTS_WORLD, &matSavedWorld );
777    else
778        matSavedWorld = *pmatWorldMatrix;
779
780    D3DXMatrixMultiply( &matWorld, &m_mat, &matSavedWorld );
781    pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
782
783    if( m_pMesh )
784        m_pMesh->Render( pd3dDevice, bDrawOpaqueSubsets, bDrawAlphaSubsets );
785
786    if( m_pChild )
787        m_pChild->Render( pd3dDevice, bDrawOpaqueSubsets, bDrawAlphaSubsets, &matWorld );
788
789    pd3dDevice->SetTransform( D3DTS_WORLD, &matSavedWorld );
790
791    if( m_pNext )
792        m_pNext->Render( pd3dDevice, bDrawOpaqueSubsets, bDrawAlphaSubsets, &matSavedWorld );
793
794    return S_OK;
795}
796
797
798
799
800//-----------------------------------------------------------------------------
801HRESULT CDXUTMeshFile::LoadFrame( LPDIRECT3DDEVICE9 pd3dDevice,
802                             LPD3DXFILEDATA pFileData,
803                             CDXUTMeshFrame* pParentFrame )
804{
805    LPD3DXFILEDATA   pChildData = NULL;
806    GUID Guid;
807    SIZE_T      cbSize;
808    CDXUTMeshFrame*  pCurrentFrame;
809    HRESULT     hr;
810
811    // Get the type of the object
812    if( FAILED( hr = pFileData->GetType( &Guid ) ) )
813        return hr;
814
815    if( Guid == TID_D3DRMMesh )
816    {
817        hr = LoadMesh( pd3dDevice, pFileData, pParentFrame );
818        if( FAILED(hr) )
819            return hr;
820    }
821    if( Guid == TID_D3DRMFrameTransformMatrix )
822    {
823        D3DXMATRIX* pmatMatrix;
824        hr = pFileData->Lock(&cbSize, (LPCVOID*)&pmatMatrix );
825        if( FAILED(hr) )
826            return hr;
827
828        // Update the parent's matrix with the new one
829        pParentFrame->SetMatrix( pmatMatrix );
830    }
831    if( Guid == TID_D3DRMFrame )
832    {
833        // Get the frame name
834        CHAR  strAnsiName[512] = "";
835        WCHAR strName[512];
836        SIZE_T dwNameLength = 512;
837        SIZE_T cChildren;
838        if( FAILED( hr = pFileData->GetName( strAnsiName, &dwNameLength ) ) )
839            return hr;
840
841        MultiByteToWideChar( CP_ACP, 0, strAnsiName, -1, strName, 512 );
842        strName[511] = 0;
843
844        // Create the frame
845        pCurrentFrame = new CDXUTMeshFrame( strName );
846        if( pCurrentFrame == NULL )
847            return E_OUTOFMEMORY;
848
849        pCurrentFrame->m_pNext = pParentFrame->m_pChild;
850        pParentFrame->m_pChild = pCurrentFrame;
851
852        // Enumerate child objects
853        pFileData->GetChildren(&cChildren);
854        for (UINT iChild = 0; iChild < cChildren; iChild++)
855        {
856            // Query the child for its FileData
857            hr = pFileData->GetChild(iChild, &pChildData );
858            if( SUCCEEDED(hr) )
859            {
860                hr = LoadFrame( pd3dDevice, pChildData, pCurrentFrame );
861                SAFE_RELEASE( pChildData );
862            }
863
864            if( FAILED(hr) )
865                return hr;
866        }
867    }
868
869    return S_OK;
870}
871
872
873
874
875//-----------------------------------------------------------------------------
876HRESULT CDXUTMeshFile::LoadMesh( LPDIRECT3DDEVICE9 pd3dDevice,
877                            LPD3DXFILEDATA pFileData,
878                            CDXUTMeshFrame* pParentFrame )
879{
880    // Currently only allowing one mesh per frame
881    if( pParentFrame->m_pMesh )
882        return E_FAIL;
883
884    // Get the mesh name
885    CHAR  strAnsiName[512] = {0};
886    WCHAR strName[512];
887    SIZE_T dwNameLength = 512;
888    HRESULT hr;
889    if( FAILED( hr = pFileData->GetName( strAnsiName, &dwNameLength ) ) )
890        return hr;
891
892    MultiByteToWideChar( CP_ACP, 0, strAnsiName, -1, strName, 512 );
893    strName[511] = 0;
894
895    // Create the mesh
896    pParentFrame->m_pMesh = new CDXUTMesh( strName );
897    if( pParentFrame->m_pMesh == NULL )
898        return E_OUTOFMEMORY;
899    pParentFrame->m_pMesh->Create( pd3dDevice, pFileData );
900
901    return S_OK;
902}
903
904
905
906
907//-----------------------------------------------------------------------------
908HRESULT CDXUTMeshFile::CreateFromResource( LPDIRECT3DDEVICE9 pd3dDevice, LPCWSTR strResource, LPCWSTR strType )
909{
910    LPD3DXFILE           pDXFile   = NULL;
911    LPD3DXFILEENUMOBJECT pEnumObj  = NULL;
912    LPD3DXFILEDATA       pFileData = NULL;
913    HRESULT hr;
914    SIZE_T cChildren;
915
916    // Create a x file object
917    if( FAILED( hr = D3DXFileCreate( &pDXFile ) ) )
918        return E_FAIL;
919
920    // Register templates for d3drm and patch extensions.
921    if( FAILED( hr = pDXFile->RegisterTemplates( (void*)D3DRM_XTEMPLATES,
922                                                 D3DRM_XTEMPLATE_BYTES ) ) )
923    {
924        SAFE_RELEASE( pDXFile );
925        return E_FAIL;
926    }
927   
928    CHAR strTypeAnsi[MAX_PATH];
929    CHAR strResourceAnsi[MAX_PATH];
930
931    WideCharToMultiByte( CP_ACP, 0, strType, -1, strTypeAnsi, MAX_PATH, NULL, NULL );
932    strTypeAnsi[MAX_PATH-1] = 0;
933
934    WideCharToMultiByte( CP_ACP, 0, strResource, -1, strResourceAnsi, MAX_PATH, NULL, NULL );
935    strResourceAnsi[MAX_PATH-1] = 0;
936
937    D3DXF_FILELOADRESOURCE dxlr;
938    dxlr.hModule = NULL;
939    dxlr.lpName = strResourceAnsi;
940    dxlr.lpType = strTypeAnsi;
941
942    // Create enum object
943    hr = pDXFile->CreateEnumObject( (void*)&dxlr, D3DXF_FILELOAD_FROMRESOURCE,
944                                    &pEnumObj );
945    if( FAILED(hr) )
946    {
947        SAFE_RELEASE( pDXFile );
948        return hr;
949    }
950
951    // Enumerate top level objects (which are always frames)
952    pEnumObj->GetChildren(&cChildren);
953    for (UINT iChild = 0; iChild < cChildren; iChild++)
954    {
955        hr = pEnumObj->GetChild(iChild, &pFileData);
956        if (FAILED(hr))
957            return hr;
958
959        hr = LoadFrame( pd3dDevice, pFileData, this );
960        SAFE_RELEASE( pFileData );
961        if( FAILED(hr) )
962        {
963            SAFE_RELEASE( pEnumObj );
964            SAFE_RELEASE( pDXFile );
965            return E_FAIL;
966        }
967    }
968
969    SAFE_RELEASE( pFileData );
970    SAFE_RELEASE( pEnumObj );
971    SAFE_RELEASE( pDXFile );
972
973    return S_OK;
974}
975
976
977
978
979//-----------------------------------------------------------------------------
980HRESULT CDXUTMeshFile::Create( LPDIRECT3DDEVICE9 pd3dDevice, LPCWSTR strFilename )
981{
982    LPD3DXFILE           pDXFile   = NULL;
983    LPD3DXFILEENUMOBJECT pEnumObj  = NULL;
984    LPD3DXFILEDATA       pFileData = NULL;
985    HRESULT hr;
986    SIZE_T cChildren;
987
988    // Create a x file object
989    if( FAILED( hr = D3DXFileCreate( &pDXFile ) ) )
990        return E_FAIL;
991
992    // Register templates for d3drm and patch extensions.
993    if( FAILED( hr = pDXFile->RegisterTemplates( (void*)D3DRM_XTEMPLATES,
994                                                 D3DRM_XTEMPLATE_BYTES ) ) )
995    {
996        SAFE_RELEASE( pDXFile );
997        return E_FAIL;
998    }
999
1000    // Find the path to the file, and convert it to ANSI (for the D3DXOF API)
1001    WCHAR strPath[MAX_PATH];
1002    CHAR  strPathANSI[MAX_PATH];
1003    DXUTFindDXSDKMediaFileCch( strPath, sizeof(strPath) / sizeof(WCHAR), strFilename );
1004   
1005   
1006    WideCharToMultiByte( CP_ACP, 0, strPath, -1, strPathANSI, MAX_PATH, NULL, NULL );
1007    strPathANSI[MAX_PATH-1] = 0;
1008
1009   
1010    // Create enum object
1011    hr = pDXFile->CreateEnumObject( (void*)strPathANSI, D3DXF_FILELOAD_FROMFILE,
1012                                    &pEnumObj );
1013    if( FAILED(hr) )
1014    {
1015        SAFE_RELEASE( pDXFile );
1016        return hr;
1017    }
1018
1019    // Enumerate top level objects (which are always frames)
1020    pEnumObj->GetChildren(&cChildren);
1021    for (UINT iChild = 0; iChild < cChildren; iChild++)
1022    {
1023        hr = pEnumObj->GetChild(iChild, &pFileData);
1024        if (FAILED(hr))
1025            return hr;
1026
1027        hr = LoadFrame( pd3dDevice, pFileData, this );
1028        SAFE_RELEASE( pFileData );
1029        if( FAILED(hr) )
1030        {
1031            SAFE_RELEASE( pEnumObj );
1032            SAFE_RELEASE( pDXFile );
1033            return E_FAIL;
1034        }
1035    }
1036
1037    SAFE_RELEASE( pFileData );
1038    SAFE_RELEASE( pEnumObj );
1039    SAFE_RELEASE( pDXFile );
1040
1041    return S_OK;
1042}
1043
1044
1045
1046
1047//-----------------------------------------------------------------------------
1048HRESULT CDXUTMeshFile::Render( LPDIRECT3DDEVICE9 pd3dDevice, D3DXMATRIX* pmatWorldMatrix )
1049{
1050
1051    // For pure devices, specify the world transform. If the world transform is not
1052    // specified on pure devices, this function will fail.
1053
1054    // Set up the world transformation
1055    D3DXMATRIX matSavedWorld, matWorld;
1056
1057    if ( NULL == pmatWorldMatrix )
1058        pd3dDevice->GetTransform( D3DTS_WORLD, &matSavedWorld );
1059    else
1060        matSavedWorld = *pmatWorldMatrix;
1061
1062    D3DXMatrixMultiply( &matWorld, &matSavedWorld, &m_mat );
1063    pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
1064
1065    // Render opaque subsets in the meshes
1066    if( m_pChild )
1067        m_pChild->Render( pd3dDevice, TRUE, FALSE, &matWorld );
1068
1069    // Enable alpha blending
1070    pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
1071    pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
1072    pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
1073
1074    // Render alpha subsets in the meshes
1075    if( m_pChild )
1076        m_pChild->Render( pd3dDevice, FALSE, TRUE, &matWorld );
1077
1078    // Restore state
1079    pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
1080    pd3dDevice->SetTransform( D3DTS_WORLD, &matSavedWorld );
1081
1082    return S_OK;
1083}
1084
1085
1086
1087
Note: See TracBrowser for help on using the repository browser.