home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / Direct3D / Billboard / billboard.cpp next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  19.4 KB  |  566 lines

  1. //-----------------------------------------------------------------------------
  2. // File: Billboard.cpp
  3. //
  4. // Desc: Example code showing how to do billboarding. The sample uses
  5. //       billboarding to draw some trees.
  6. //
  7. //       Note: This implementation is for billboards that are fixed to rotate
  8. //       about the Y-axis, which is good for things like trees. For
  9. //       unconstrained billboards, like explosions in a flight sim, the
  10. //       technique is the same, but the the billboards are positioned slightly
  11. //       differently. Try using the inverse of the view matrix, TL-vertices, or
  12. //       some other technique.
  13. //
  14. // Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved.
  15. //-----------------------------------------------------------------------------
  16. #define STRICT
  17. #include <basetsd.h>
  18. #include <stdio.h>
  19. #include <math.h>
  20. #include <D3DX8.h>
  21. #include "D3DApp.h"
  22. #include "D3DFile.h"
  23. #include "D3DFont.h"
  24. #include "D3DUtil.h"
  25. #include "DXUtil.h"
  26.  
  27.  
  28.  
  29.  
  30. //-----------------------------------------------------------------------------
  31. // Defines, constants, and global variables
  32. //-----------------------------------------------------------------------------
  33. #define NUM_TREES 500
  34.  
  35. // Need global access to the eye direction used by the callback to sort trees
  36. D3DXVECTOR3 g_vDir;
  37.  
  38. // Simple function to define "hilliness" for terrain
  39. inline FLOAT HeightField( FLOAT x, FLOAT y )
  40. {
  41.     return 9*(cosf(x/20+0.2f)*cosf(y/15-0.2f)+1.0f);
  42. }
  43.  
  44. // Custom vertex type for the trees
  45. struct TREEVERTEX
  46. {
  47.     D3DXVECTOR3 p;      // Vertex position
  48.     DWORD       color;  // Vertex color
  49.     FLOAT       tu, tv; // Vertex texture coordinates
  50. };
  51.  
  52. #define D3DFVF_TREEVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
  53.  
  54. // Tree textures to use
  55. TCHAR* g_strTreeTextures[] =
  56. {
  57.     _T("Tree02S.tga"),
  58.     _T("Tree35S.tga"),
  59.     _T("Tree01S.tga"),
  60. };
  61.  
  62. #define NUMTREETEXTURES 3
  63.  
  64.  
  65.  
  66.  
  67. //-----------------------------------------------------------------------------
  68. // Name: Tree
  69. // Desc: Simple structure to hold data for rendering a tree
  70. //-----------------------------------------------------------------------------
  71. struct Tree
  72. {
  73.     TREEVERTEX  v[4];           // Four corners of billboard quad
  74.     D3DXVECTOR3 vPos;           // Origin of tree
  75.     DWORD       dwTreeTexture;  // Which texture map to use
  76.     DWORD       dwOffset;       // Offset into vertex buffer of tree's vertices
  77. };
  78.  
  79.  
  80.  
  81.  
  82. //-----------------------------------------------------------------------------
  83. // Name: class CMyD3DApplication
  84. // Desc: Application class. The base class (CD3DApplication) provides the 
  85. //       generic functionality needed in all Direct3D samples. CMyD3DApplication 
  86. //       adds functionality specific to this sample program.
  87. //-----------------------------------------------------------------------------
  88. class CMyD3DApplication : public CD3DApplication
  89. {
  90.     CD3DFont*     m_pFont;              // Font for drawing text
  91.     CD3DMesh*     m_pTerrain;           // Terrain object
  92.     CD3DMesh*     m_pSkyBox;            // Skybox background object
  93.  
  94.     LPDIRECT3DVERTEXBUFFER8 m_pTreeVB;  // Vertex buffer for rendering a tree
  95.     LPDIRECT3DTEXTURE8      m_pTreeTextures[NUMTREETEXTURES]; // Tree images
  96.     D3DXMATRIX    m_matBillboardMatrix; // Used for billboard orientation
  97.     Tree          m_Trees[NUM_TREES];   // Array of tree info
  98.  
  99.     HRESULT ConfirmDevice( D3DCAPS8*, DWORD, D3DFORMAT );
  100.     HRESULT DrawBackground();
  101.     HRESULT DrawTrees();
  102.  
  103. protected:
  104.     HRESULT OneTimeSceneInit();
  105.     HRESULT InitDeviceObjects();
  106.     HRESULT RestoreDeviceObjects();
  107.     HRESULT InvalidateDeviceObjects();
  108.     HRESULT DeleteDeviceObjects();
  109.     HRESULT FinalCleanup();
  110.     HRESULT Render();
  111.     HRESULT FrameMove();
  112.  
  113. public:
  114.     CMyD3DApplication();
  115. };
  116.  
  117.  
  118. CMyD3DApplication g_d3dApp;
  119.  
  120. //-----------------------------------------------------------------------------
  121. // Name: WinMain()
  122. // Desc: Entry point to the program. Initializes everything, and goes into a
  123. //       message-processing loop. Idle time is used to render the scene.
  124. //-----------------------------------------------------------------------------
  125. INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
  126. {
  127.  
  128.     if( FAILED( g_d3dApp.Create( hInst ) ) )
  129.         return 0;
  130.  
  131.     return g_d3dApp.Run();
  132. }
  133.  
  134.  
  135.  
  136.  
  137. //-----------------------------------------------------------------------------
  138. // Name: CMyD3DApplication()
  139. // Desc: Application constructor. Sets attributes for the app.
  140. //-----------------------------------------------------------------------------
  141. CMyD3DApplication::CMyD3DApplication()
  142. {
  143.     m_strWindowTitle    = _T("Billboard: D3D Billboarding Example");
  144.     m_bUseDepthBuffer   = TRUE;
  145.  
  146.     m_pFont        = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD );
  147.     m_pSkyBox      = new CD3DMesh();
  148.     m_pTerrain     = new CD3DMesh();
  149.     m_pTreeVB      = NULL;
  150.  
  151.     for( DWORD i=0; i<NUMTREETEXTURES; i++ )
  152.         m_pTreeTextures[i] = NULL;
  153. }
  154.  
  155.  
  156.  
  157.  
  158. //-----------------------------------------------------------------------------
  159. // Name: OneTimeSceneInit()
  160. // Desc: Called during initial app startup, this function performs all the
  161. //       permanent initialization.
  162. //-----------------------------------------------------------------------------
  163. HRESULT CMyD3DApplication::OneTimeSceneInit()
  164. {
  165.     // Initialize the tree data
  166.     for( WORD i=0; i<NUM_TREES; i++ )
  167.     {
  168.         // Position the trees randomly
  169.         FLOAT fTheta  = 2.0f*D3DX_PI*(FLOAT)rand()/RAND_MAX;
  170.         FLOAT fRadius = 25.0f + 55.0f * (FLOAT)rand()/RAND_MAX;
  171.         m_Trees[i].vPos.x  = fRadius * sinf(fTheta);
  172.         m_Trees[i].vPos.z  = fRadius * cosf(fTheta);
  173.         m_Trees[i].vPos.y  = HeightField( m_Trees[i].vPos.x, m_Trees[i].vPos.z );
  174.  
  175.         // Size the trees randomly
  176.         FLOAT fWidth  = 1.0f + 0.2f * (FLOAT)(rand()-rand())/RAND_MAX;
  177.         FLOAT fHeight = 1.4f + 0.4f * (FLOAT)(rand()-rand())/RAND_MAX;
  178.  
  179.         // Each tree is a random color between red and green
  180.         DWORD r = (255-190) + (DWORD)(190*(FLOAT)(rand())/RAND_MAX);
  181.         DWORD g = (255-190) + (DWORD)(190*(FLOAT)(rand())/RAND_MAX);
  182.         DWORD b = 0;
  183.         DWORD dwColor = 0xff000000 + (r<<16) + (g<<8) + (b<<0);
  184.  
  185.         m_Trees[i].v[0].p     = D3DXVECTOR3(-fWidth, 0*fHeight, 0.0f );
  186.         m_Trees[i].v[0].color = dwColor;
  187.         m_Trees[i].v[0].tu    = 0.0f;   m_Trees[i].v[0].tv = 1.0f;
  188.         m_Trees[i].v[1].p     = D3DXVECTOR3(-fWidth, 2*fHeight, 0.0f  );
  189.         m_Trees[i].v[1].color = dwColor;
  190.         m_Trees[i].v[1].tu    = 0.0f;   m_Trees[i].v[1].tv = 0.0f;
  191.         m_Trees[i].v[2].p     = D3DXVECTOR3( fWidth, 0*fHeight, 0.0f  );
  192.         m_Trees[i].v[2].color = dwColor;
  193.         m_Trees[i].v[2].tu    = 1.0f;   m_Trees[i].v[2].tv = 1.0f;
  194.         m_Trees[i].v[3].p     = D3DXVECTOR3( fWidth, 2*fHeight, 0.0f  );
  195.         m_Trees[i].v[3].color = dwColor;
  196.         m_Trees[i].v[3].tu    = 1.0f;   m_Trees[i].v[3].tv = 0.0f;
  197.  
  198.         // Pick a random texture for the tree
  199.         m_Trees[i].dwTreeTexture = (DWORD)( ( NUMTREETEXTURES * rand() ) / (FLOAT)RAND_MAX );
  200.     }
  201.  
  202.     return S_OK;
  203. }
  204.  
  205.  
  206.  
  207.  
  208. //-----------------------------------------------------------------------------
  209. // Name: TreeSortCB()
  210. // Desc: Callback function for sorting trees in back-to-front order
  211. //-----------------------------------------------------------------------------
  212. int TreeSortCB( const VOID* arg1, const VOID* arg2 )
  213. {
  214.     Tree* p1 = (Tree*)arg1;
  215.     Tree* p2 = (Tree*)arg2;
  216.     
  217.     FLOAT d1 = p1->vPos.x * g_vDir.x + p1->vPos.z * g_vDir.z;
  218.     FLOAT d2 = p2->vPos.x * g_vDir.x + p2->vPos.z * g_vDir.z;
  219.     if (d1 < d2)
  220.         return +1;
  221.  
  222.     return -1;
  223. }
  224.  
  225.  
  226.  
  227.  
  228. //-----------------------------------------------------------------------------
  229. // Name: FrameMove()
  230. // Desc: Called once per frame, the call is the entry point for animating
  231. //       the scene.
  232. //-----------------------------------------------------------------------------
  233. HRESULT CMyD3DApplication::FrameMove()
  234. {
  235.     // Get the eye and lookat points from the camera's path
  236.     D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
  237.     D3DXVECTOR3 vEyePt;
  238.     D3DXVECTOR3 vLookatPt;
  239.  
  240.     vEyePt.x = 30.0f*cosf( 0.8f * ( m_fTime ) );
  241.     vEyePt.z = 30.0f*sinf( 0.8f * ( m_fTime ) );
  242.     vEyePt.y = 4 + HeightField( vEyePt.x, vEyePt.z );
  243.  
  244.     vLookatPt.x = 30.0f*cosf( 0.8f * ( m_fTime + 0.5f ) );
  245.     vLookatPt.z = 30.0f*sinf( 0.8f * ( m_fTime + 0.5f ) );
  246.     vLookatPt.y = vEyePt.y - 1.0f;
  247.  
  248.     // Set the app view matrix for normal viewing
  249.     D3DXMATRIX matView;
  250.     D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
  251.     m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
  252.  
  253.     // Set up a rotation matrix to orient the billboard towards the camera.
  254.     D3DXVECTOR3 vDir = vLookatPt - vEyePt;
  255.     if( vDir.x > 0.0f )
  256.         D3DXMatrixRotationY( &m_matBillboardMatrix, -atanf(vDir.z/vDir.x)+D3DX_PI/2 );
  257.     else
  258.         D3DXMatrixRotationY( &m_matBillboardMatrix, -atanf(vDir.z/vDir.x)-D3DX_PI/2 );
  259.  
  260.     // Sort trees in back-to-front order
  261.     g_vDir = vDir;
  262.     qsort( m_Trees, NUM_TREES, sizeof(Tree), TreeSortCB );
  263.  
  264.     return S_OK;
  265. }
  266.  
  267.  
  268.  
  269.  
  270. //-----------------------------------------------------------------------------
  271. // Name: DrawTrees()
  272. // Desc:
  273. //-----------------------------------------------------------------------------
  274. HRESULT CMyD3DApplication::DrawTrees()
  275. {
  276.     // Set diffuse blending for alpha set in vertices.
  277.     m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE,   TRUE );
  278.     m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
  279.     m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  280.  
  281.     // Enable alpha testing (skips pixels with less than a certain alpha.)
  282.     if( m_d3dCaps.AlphaCmpCaps & D3DPCMPCAPS_GREATEREQUAL )
  283.     {
  284.         m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
  285.         m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF,        0x08 );
  286.         m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
  287.     }
  288.  
  289.     // Loop through and render all trees
  290.     m_pd3dDevice->SetStreamSource( 0, m_pTreeVB, sizeof(TREEVERTEX) );
  291.     m_pd3dDevice->SetVertexShader( D3DFVF_TREEVERTEX );
  292.     for( DWORD i=0; i<NUM_TREES; i++ )
  293.     {
  294.         // Set the tree texture
  295.         m_pd3dDevice->SetTexture( 0, m_pTreeTextures[m_Trees[i].dwTreeTexture] );
  296.  
  297.         // Translate the billboard into place
  298.         m_matBillboardMatrix._41 = m_Trees[i].vPos.x;
  299.         m_matBillboardMatrix._42 = m_Trees[i].vPos.y;
  300.         m_matBillboardMatrix._43 = m_Trees[i].vPos.z;
  301.         m_pd3dDevice->SetTransform( D3DTS_WORLD, &m_matBillboardMatrix );
  302.  
  303.         // Render the billboard
  304.         m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, m_Trees[i].dwOffset, 2 );
  305.     }
  306.  
  307.     // Restore state
  308.     D3DXMATRIX  matWorld;
  309.     D3DXMatrixIdentity( &matWorld );
  310.     m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
  311.     m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE,    FALSE );
  312.     m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE,   FALSE );
  313.  
  314.     return S_OK;
  315. }
  316.  
  317.  
  318.  
  319.  
  320. //-----------------------------------------------------------------------------
  321. // Name: Render()
  322. // Desc: Called once per frame, the call is the entry point for 3d
  323. //       rendering. This function sets up render states, clears the
  324. //       viewport, and renders the scene.
  325. //-----------------------------------------------------------------------------
  326. HRESULT CMyD3DApplication::Render()
  327. {
  328.     // Clear the viewport
  329.     m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0L );
  330.  
  331.     // Begin the scene
  332.     if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
  333.     {
  334.         // Render the Skybox
  335.         {
  336.             // Center view matrix for skybox and disable zbuffer
  337.             D3DXMATRIX matView, matViewSave;
  338.             m_pd3dDevice->GetTransform( D3DTS_VIEW, &matViewSave );
  339.             matView = matViewSave;
  340.             matView._41 = 0.0f; matView._42 = -0.3f; matView._43 = 0.0f;
  341.             m_pd3dDevice->SetTransform( D3DTS_VIEW,      &matView );
  342.             m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
  343.             // Some cards do not disable writing to Z when 
  344.             // D3DRS_ZENABLE is FALSE. So do it explicitly
  345.             m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
  346.  
  347.             // Render the skybox
  348.             m_pSkyBox->Render( m_pd3dDevice );
  349.  
  350.             // Restore the render states
  351.             m_pd3dDevice->SetTransform( D3DTS_VIEW,      &matViewSave );
  352.             m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
  353.             m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE);
  354.         }
  355.  
  356.         // Draw the terrain
  357.         m_pTerrain->Render( m_pd3dDevice );
  358.  
  359.         // Draw the trees
  360.         DrawTrees();
  361.  
  362.         // Output statistics
  363.         m_pFont->DrawText( 2,  0, D3DCOLOR_ARGB(255,255,255,0), m_strFrameStats );
  364.         m_pFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats );
  365.  
  366.         // End the scene.
  367.         m_pd3dDevice->EndScene();
  368.     }
  369.  
  370.     return S_OK;
  371. }
  372.  
  373.  
  374.  
  375.  
  376. //-----------------------------------------------------------------------------
  377. // Name: InitDeviceObjects()
  378. // Desc: This creates all device-dependent managed objects, such as managed
  379. //       textures and managed vertex buffers.
  380. //-----------------------------------------------------------------------------
  381. HRESULT CMyD3DApplication::InitDeviceObjects()
  382. {
  383.     // Initialize the font's internal textures
  384.     m_pFont->InitDeviceObjects( m_pd3dDevice );
  385.  
  386.     // Create the tree textures
  387.     for( DWORD i=0; i<NUMTREETEXTURES; i++ )
  388.     {
  389.         if( FAILED( D3DUtil_CreateTexture( m_pd3dDevice, g_strTreeTextures[i],
  390.                                            &m_pTreeTextures[i] ) ) )
  391.             return D3DAPPERR_MEDIANOTFOUND;
  392.     }
  393.  
  394.     // Create a quad for rendering each tree
  395.     if( FAILED( m_pd3dDevice->CreateVertexBuffer( NUM_TREES*4*sizeof(TREEVERTEX),
  396.                                                   D3DUSAGE_WRITEONLY, D3DFVF_TREEVERTEX,
  397.                                                   D3DPOOL_MANAGED, &m_pTreeVB ) ) )
  398.     {
  399.         return E_FAIL;
  400.     }
  401.  
  402.     // Copy tree mesh data into vertexbuffer
  403.     TREEVERTEX* v;
  404.     m_pTreeVB->Lock( 0, 0, (BYTE**)&v, 0 );
  405.  
  406.     INT iTree;
  407.     DWORD dwOffset = 0;
  408.     for( iTree = 0; iTree < NUM_TREES; iTree++ )
  409.     {
  410.         memcpy( &v[dwOffset], m_Trees[iTree].v, 4*sizeof(TREEVERTEX) );
  411.         m_Trees[iTree].dwOffset = dwOffset;
  412.         dwOffset += 4;
  413.     }
  414.  
  415.     m_pTreeVB->Unlock();
  416.  
  417.     // Load the skybox
  418.     if( FAILED( m_pSkyBox->Create( m_pd3dDevice, _T("SkyBox2.x") ) ) )
  419.         return D3DAPPERR_MEDIANOTFOUND;
  420.  
  421.     // Load the terrain
  422.     if( FAILED( m_pTerrain->Create( m_pd3dDevice, _T("SeaFloor.x") ) ) )
  423.         return D3DAPPERR_MEDIANOTFOUND;
  424.  
  425.     // Add some "hilliness" to the terrain
  426.     LPDIRECT3DVERTEXBUFFER8 pVB;
  427.     if( SUCCEEDED( m_pTerrain->GetSysMemMesh()->GetVertexBuffer( &pVB ) ) )
  428.     {
  429.         struct VERTEX { FLOAT x,y,z,tu,tv; };
  430.         VERTEX* pVertices;
  431.         DWORD   dwNumVertices = m_pTerrain->GetSysMemMesh()->GetNumVertices();
  432.  
  433.         pVB->Lock( 0, 0, (BYTE**)&pVertices, 0 );
  434.  
  435.         for( DWORD i=0; i<dwNumVertices; i++ )
  436.             pVertices[i].y = HeightField( pVertices[i].x, pVertices[i].z );
  437.  
  438.         pVB->Unlock();
  439.         pVB->Release();
  440.     }
  441.  
  442.     return S_OK;
  443. }
  444.  
  445.  
  446.  
  447.  
  448. //-----------------------------------------------------------------------------
  449. // Name: RestoreDeviceObjects()
  450. // Desc: Restore device-memory objects and state after a device is created or
  451. //       resized.
  452. //-----------------------------------------------------------------------------
  453. HRESULT CMyD3DApplication::RestoreDeviceObjects()
  454. {
  455.     // Restore the device objects for the meshes and fonts
  456.     m_pTerrain->RestoreDeviceObjects( m_pd3dDevice );
  457.     m_pSkyBox->RestoreDeviceObjects( m_pd3dDevice );
  458.     m_pFont->RestoreDeviceObjects();
  459.  
  460.     // Set the transform matrices (view and world are updated per frame)
  461.     D3DXMATRIX matProj;
  462.     FLOAT fAspect = m_d3dsdBackBuffer.Width / (FLOAT)m_d3dsdBackBuffer.Height;
  463.     D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect, 1.0f, 100.0f );
  464.     m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
  465.  
  466.     // Set up the default texture states
  467.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_SELECTARG1 );
  468.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  469.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );
  470.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  471.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  472.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  473.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSU,  D3DTADDRESS_CLAMP );
  474.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSV,  D3DTADDRESS_CLAMP );
  475.  
  476.     m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, TRUE );
  477.     m_pd3dDevice->SetRenderState( D3DRS_ZENABLE,      TRUE );
  478.     m_pd3dDevice->SetRenderState( D3DRS_LIGHTING,     FALSE );
  479.  
  480.     return S_OK;
  481. }
  482.  
  483.  
  484.  
  485.  
  486. //-----------------------------------------------------------------------------
  487. // Name: InvalidateDeviceObjects()
  488. // Desc: Called when the device-dependent objects are about to be lost.
  489. //-----------------------------------------------------------------------------
  490. HRESULT CMyD3DApplication::InvalidateDeviceObjects()
  491. {
  492.     m_pTerrain->InvalidateDeviceObjects();
  493.     m_pSkyBox->InvalidateDeviceObjects();
  494.     m_pFont->InvalidateDeviceObjects();
  495.  
  496.     return S_OK;
  497. }
  498.  
  499.  
  500.  
  501.  
  502. //-----------------------------------------------------------------------------
  503. // Name: DeleteDeviceObjects()
  504. // Desc: Called when the app is exiting, or the device is being changed,
  505. //       this function deletes any device dependent objects.
  506. //-----------------------------------------------------------------------------
  507. HRESULT CMyD3DApplication::DeleteDeviceObjects()
  508. {
  509.     m_pFont->DeleteDeviceObjects();
  510.  
  511.     m_pTerrain->Destroy();
  512.     m_pSkyBox->Destroy();
  513.  
  514.     for( DWORD i=0; i<NUMTREETEXTURES; i++ )
  515.         SAFE_RELEASE( m_pTreeTextures[i] );
  516.  
  517.     SAFE_RELEASE( m_pTreeVB )
  518.  
  519.     return S_OK;
  520. }
  521.  
  522.  
  523.  
  524.  
  525. //-----------------------------------------------------------------------------
  526. // Name: FinalCleanup()
  527. // Desc: Called before the app exits, this function gives the app the chance
  528. //       to cleanup after itself.
  529. //-----------------------------------------------------------------------------
  530. HRESULT CMyD3DApplication::FinalCleanup()
  531. {
  532.     SAFE_DELETE( m_pFont );
  533.     SAFE_DELETE( m_pTerrain );
  534.     SAFE_DELETE( m_pSkyBox );
  535.  
  536.     return S_OK;
  537. }
  538.  
  539.  
  540.  
  541.  
  542. //-----------------------------------------------------------------------------
  543. // Name: ConfirmDevice()
  544. // Desc: Called during device intialization, this code checks the device
  545. //       for some minimum set of capabilities
  546. //-----------------------------------------------------------------------------
  547. HRESULT CMyD3DApplication::ConfirmDevice( D3DCAPS8* pCaps, DWORD dwBehavior,
  548.                                           D3DFORMAT Format )
  549. {
  550.     if( dwBehavior & D3DCREATE_PUREDEVICE )
  551.         return E_FAIL; // GetTransform doesn't work on PUREDEVICE
  552.  
  553.     // This sample uses alpha textures and/or straight alpha. Make sure the
  554.     // device supports them
  555.     if( pCaps->TextureCaps & D3DPTEXTURECAPS_ALPHAPALETTE )
  556.         return S_OK;
  557.     if( pCaps->TextureCaps & D3DPTEXTURECAPS_ALPHA )
  558.         return S_OK;
  559.  
  560.     return E_FAIL;
  561. }
  562.  
  563.  
  564.  
  565.  
  566.