source: GTP/trunk/App/Demos/Illum/Glow/Common/DXUTMesh.cpp @ 846

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