DXUTMesh.cpp
上传用户:junlon
上传日期:2022-01-05
资源大小:39075k
文件大小:34k
源码类别:

DirextX编程

开发平台:

Visual C++

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