home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Common / DXUTMesh.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-28  |  32.8 KB  |  1,054 lines

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