home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Game Programming for Teens / VBGPFT.cdr / DirectX8 / dx8a_sdk.exe / samples / multimedia / direct3d / stencilbuffer / shadowvolume / shadowvolume.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-04  |  25.1 KB  |  719 lines

  1. //-----------------------------------------------------------------------------
  2. // File: ShadowVolume.cpp
  3. //
  4. // Desc: Example code showing how to use stencil buffers to implement shadow
  5. //       volumes.
  6. //
  7. // Copyright (c) 1998-2000 Microsoft Corporation. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #define STRICT
  10. #include <math.h>
  11. #include <stdio.h>
  12. #include <D3DX8.h>
  13. #include "D3DApp.h"
  14. #include "D3DUtil.h"
  15. #include "D3DFile.h"
  16. #include "D3DFont.h"
  17. #include "DXUtil.h"
  18.  
  19.  
  20.  
  21.  
  22. //-----------------------------------------------------------------------------
  23. // External definitions and prototypes
  24. //-----------------------------------------------------------------------------
  25. inline DWORD FtoDW( FLOAT f ) { return *((DWORD*)&f); }
  26.  
  27. struct VERTEX
  28. {
  29.     D3DXVECTOR3 p;
  30.     D3DXVECTOR3 n;
  31.     FLOAT       tu, tv;
  32. };
  33.  
  34. struct SHADOWVERTEX
  35. {
  36.     D3DXVECTOR4 p;
  37.     D3DCOLOR    color;
  38. };
  39.  
  40. #define D3DFVF_VERTEX       (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
  41. #define D3DFVF_SHADOWVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)
  42.  
  43.  
  44.  
  45.  
  46. //-----------------------------------------------------------------------------
  47. // Name: struct ShadowVolume
  48. // Desc: A shadow volume object
  49. //-----------------------------------------------------------------------------
  50. class ShadowVolume
  51. {
  52.     D3DXVECTOR3 m_pVertices[32000]; // Vertex data for rendering shadow volume
  53.     DWORD       m_dwNumVertices;
  54.  
  55. public:
  56.     VOID    Reset() { m_dwNumVertices = 0L; }
  57.     HRESULT BuildFromMesh( LPD3DXMESH pObject, D3DXVECTOR3 vLight );
  58.     HRESULT Render( LPDIRECT3DDEVICE8 pd3dDevice );
  59. };
  60.  
  61.  
  62.  
  63.  
  64. //-----------------------------------------------------------------------------
  65. // Name: class CMyD3DApplication
  66. // Desc: Application class. The base class (CD3DApplication) provides the 
  67. //       generic functionality needed in all Direct3D samples. CMyD3DApplication 
  68. //       adds functionality specific to this sample program.
  69. //-----------------------------------------------------------------------------
  70. class CMyD3DApplication : public CD3DApplication
  71. {
  72.     CD3DFont*     m_pFont;
  73.     CD3DArcBall   m_ArcBall;
  74.  
  75.     CD3DMesh*     m_pAirplane;
  76.     CD3DMesh*     m_pTerrainObject;
  77.     ShadowVolume* m_pShadowVolume;
  78.  
  79.     D3DXMATRIX    m_matObjectMatrix;
  80.     D3DXMATRIX    m_matTerrainMatrix;
  81.  
  82.     LPDIRECT3DVERTEXBUFFER8 m_pBigSquareVB;
  83.     HRESULT DrawShadow();
  84.     HRESULT RenderShadow();
  85.  
  86.     HRESULT ConfirmDevice( D3DCAPS8*, DWORD, D3DFORMAT );
  87.  
  88. protected:
  89.     HRESULT OneTimeSceneInit();
  90.     HRESULT InitDeviceObjects();
  91.     HRESULT RestoreDeviceObjects();
  92.     HRESULT InvalidateDeviceObjects();
  93.     HRESULT DeleteDeviceObjects();
  94.     HRESULT Render();
  95.     HRESULT FrameMove();
  96.     HRESULT FinalCleanup();
  97.  
  98. public:
  99.     LRESULT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  100.  
  101.     CMyD3DApplication();
  102. };
  103.  
  104.  
  105.  
  106.  
  107. //-----------------------------------------------------------------------------
  108. // Name: WinMain()
  109. // Desc: Entry point to the program. Initializes everything, and goes into a
  110. //       message-processing loop. Idle time is used to render the scene.
  111. //-----------------------------------------------------------------------------
  112. INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
  113. {
  114.     CMyD3DApplication d3dApp;
  115.  
  116.     if( FAILED( d3dApp.Create( hInst ) ) )
  117.         return 0;
  118.  
  119.     return d3dApp.Run();
  120. }
  121.  
  122.  
  123.  
  124.  
  125. //-----------------------------------------------------------------------------
  126. // Name:
  127. // Desc:
  128. //-----------------------------------------------------------------------------
  129. HRESULT ShadowVolume::Render( LPDIRECT3DDEVICE8 pd3dDevice )
  130. {
  131.     pd3dDevice->SetVertexShader( D3DFVF_XYZ );
  132.  
  133.     return pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLELIST, m_dwNumVertices/3,
  134.                                         m_pVertices, sizeof(D3DXVECTOR3) );
  135. }
  136.  
  137.  
  138.  
  139.  
  140. //-----------------------------------------------------------------------------
  141. // Name: AddEdge()
  142. // Desc: Adds an edge to a list of silohuette edges of a shadow volume.
  143. //-----------------------------------------------------------------------------
  144. VOID AddEdge( WORD* pEdges, DWORD& dwNumEdges, WORD v0, WORD v1 )
  145. {
  146.     // Remove interior edges (which appear in the list twice)
  147.     for( DWORD i=0; i < dwNumEdges; i++ )
  148.     {
  149.         if( ( pEdges[2*i+0] == v0 && pEdges[2*i+1] == v1 ) ||
  150.             ( pEdges[2*i+0] == v1 && pEdges[2*i+1] == v0 ) )
  151.         {
  152.             if( dwNumEdges > 1 )
  153.             {
  154.                 pEdges[2*i+0] = pEdges[2*(dwNumEdges-1)+0];
  155.                 pEdges[2*i+1] = pEdges[2*(dwNumEdges-1)+1];
  156.             }
  157.             dwNumEdges--;
  158.             return;
  159.         }
  160.     }
  161.  
  162.     pEdges[2*dwNumEdges+0] = v0;
  163.     pEdges[2*dwNumEdges+1] = v1;
  164.     dwNumEdges++;
  165. }
  166.  
  167.  
  168.  
  169.  
  170. //-----------------------------------------------------------------------------
  171. // Name: BuildFromMesh()
  172. // Desc: Takes a mesh as input, and uses it to build a shadowvolume. The
  173. //       technique used considers each triangle of the mesh, and adds it's
  174. //       edges to a temporary list. The edge list is maintained, such that
  175. //       only silohuette edges are kept. Finally, the silohuette edges are
  176. //       extruded to make the shadow volume vertex list.
  177. //-----------------------------------------------------------------------------
  178. HRESULT ShadowVolume::BuildFromMesh( LPD3DXMESH pMesh, D3DXVECTOR3 vLight )
  179. {
  180.     // Note: the MESHVERTEX format depends on the FVF of the mesh
  181.     struct MESHVERTEX { D3DXVECTOR3 p, n; FLOAT tu, tv; };
  182.     DWORD dwFVF = pMesh->GetFVF();
  183.  
  184.     MESHVERTEX* pVertices;
  185.     WORD*       pIndices;
  186.  
  187.     // Lock the geometry buffers
  188.     pMesh->LockVertexBuffer( 0L, (BYTE**)&pVertices );
  189.     pMesh->LockIndexBuffer( 0L, (BYTE**)&pIndices );
  190.     DWORD dwNumVertices = pMesh->GetNumVertices();
  191.     DWORD dwNumFaces    = pMesh->GetNumFaces();
  192.  
  193.     // Allocate a temporary edge list
  194.     WORD* pEdges = new WORD[dwNumFaces*6];
  195.     DWORD dwNumEdges = 0;
  196.  
  197.     // For each face
  198.     for( DWORD i=0; i<dwNumFaces; i++ )
  199.     {
  200.         WORD wFace0 = pIndices[3*i+0];
  201.         WORD wFace1 = pIndices[3*i+1];
  202.         WORD wFace2 = pIndices[3*i+2];
  203.  
  204.         D3DXVECTOR3 v0 = pVertices[wFace0].p;
  205.         D3DXVECTOR3 v1 = pVertices[wFace1].p;
  206.         D3DXVECTOR3 v2 = pVertices[wFace2].p;
  207.  
  208.         // Transform vertices or transform light?
  209.         D3DXVECTOR3 vNormal;
  210.         D3DXVec3Cross( &vNormal, &(v2-v1), &(v1-v0) );
  211.  
  212.         if( D3DXVec3Dot( &vNormal, &vLight ) >= 0.0f )
  213.         {
  214.             AddEdge( pEdges, dwNumEdges, wFace0, wFace1 );
  215.             AddEdge( pEdges, dwNumEdges, wFace1, wFace2 );
  216.             AddEdge( pEdges, dwNumEdges, wFace2, wFace0 );
  217.         }
  218.     }
  219.  
  220.     for( i=0; i<dwNumEdges; i++ )
  221.     {
  222.         D3DXVECTOR3 v1 = pVertices[pEdges[2*i+0]].p;
  223.         D3DXVECTOR3 v2 = pVertices[pEdges[2*i+1]].p;
  224.         D3DXVECTOR3 v3 = v1 - vLight*10;
  225.         D3DXVECTOR3 v4 = v2 - vLight*10;
  226.  
  227.         // Add a quad (two triangles) to the vertex list
  228.         m_pVertices[m_dwNumVertices++] = v1;
  229.         m_pVertices[m_dwNumVertices++] = v2;
  230.         m_pVertices[m_dwNumVertices++] = v3;
  231.  
  232.         m_pVertices[m_dwNumVertices++] = v2;
  233.         m_pVertices[m_dwNumVertices++] = v4;
  234.         m_pVertices[m_dwNumVertices++] = v3;
  235.     }
  236.     // Delete the temporary edge list
  237.     delete pEdges;
  238.  
  239.     // Unlock the geometry buffers
  240.     pMesh->UnlockVertexBuffer();
  241.     pMesh->UnlockIndexBuffer();
  242.  
  243.     return S_OK;
  244. }
  245.  
  246.  
  247.  
  248.  
  249. //-----------------------------------------------------------------------------
  250. // Name: CMyD3DApplication()
  251. // Desc: Application constructor. Sets attributes for the app.
  252. //-----------------------------------------------------------------------------
  253. CMyD3DApplication::CMyD3DApplication()
  254. {
  255.     m_strWindowTitle    = _T("ShadowVolume: RealTime Shadows Using The StencilBuffer");
  256.     m_bUseDepthBuffer   = TRUE;
  257.     m_dwMinDepthBits    = 16;
  258.     m_dwMinStencilBits  = 4;
  259.     m_bShowCursorWhenFullscreen = TRUE;
  260.  
  261.     m_pFont           = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD );
  262.     m_pAirplane       = new CD3DMesh();
  263.     m_pTerrainObject  = new CD3DMesh();
  264.     m_pShadowVolume   = NULL;
  265.     m_pBigSquareVB    = NULL;
  266. }
  267.  
  268.  
  269.  
  270.  
  271. //-----------------------------------------------------------------------------
  272. // Name: OneTimeSceneInit()
  273. // Desc: Called during initial app startup, this function performs all the
  274. //       permanent initialization.
  275. //-----------------------------------------------------------------------------
  276. HRESULT CMyD3DApplication::OneTimeSceneInit()
  277. {
  278.     // Construct a shadow volume object;
  279.     m_pShadowVolume = new ShadowVolume();
  280.  
  281.     // Set cursor to indicate that user can move the object with the mouse
  282. #ifdef _WIN64
  283.     SetClassLongPtr( m_hWnd, GCLP_HCURSOR, (LONG_PTR)LoadCursor( NULL, IDC_SIZEALL ) );
  284. #else
  285.     SetClassLong( m_hWnd, GCL_HCURSOR, (LONG)LoadCursor( NULL, IDC_SIZEALL ) );
  286. #endif
  287.     return S_OK;
  288. }
  289.  
  290.  
  291.  
  292.  
  293. //-----------------------------------------------------------------------------
  294. // Name: FrameMove()
  295. // Desc: Called once per frame, the call is the entry point for animating
  296. //       the scene.
  297. //-----------------------------------------------------------------------------
  298. HRESULT CMyD3DApplication::FrameMove()
  299. {
  300.     // Setup the world spin matrix
  301.     D3DXMatrixTranslation( &m_matTerrainMatrix, 0.0f, 0.0f, 0.0f );
  302.  
  303.     // Setup viewing postion from ArcBall
  304.     D3DXMatrixInverse( &m_matObjectMatrix, NULL, m_ArcBall.GetRotationMatrix() );
  305.     D3DXMatrixMultiply( &m_matObjectMatrix, &m_matObjectMatrix, m_ArcBall.GetTranslationMatrix() );
  306.  
  307.     // Move the light
  308.     FLOAT Lx =   5;
  309.     FLOAT Ly =   5;
  310.     FLOAT Lz =  -5;
  311.     D3DLIGHT8 light;
  312.     D3DUtil_InitLight( light, D3DLIGHT_POINT, Lx, Ly, Lz );
  313.     light.Attenuation0 = 0.9f;
  314.     light.Attenuation1 = 0.0f;
  315.     m_pd3dDevice->SetLight( 0, &light );
  316.  
  317.     // Transform the light vector to be in object space
  318.     D3DXVECTOR3 vLight;
  319.     D3DXMATRIX m;
  320.     D3DXMatrixInverse( &m, NULL, &m_matObjectMatrix );
  321.     vLight.x = Lx*m._11 + Ly*m._21 + Lz*m._31 + m._41;
  322.     vLight.y = Lx*m._12 + Ly*m._22 + Lz*m._32 + m._42;
  323.     vLight.z = Lx*m._13 + Ly*m._23 + Lz*m._33 + m._43;
  324.  
  325.     // Build the shadow volume
  326.     m_pShadowVolume->Reset();
  327.     m_pShadowVolume->BuildFromMesh( m_pAirplane->GetSysMemMesh(), vLight );
  328.  
  329.     return S_OK;
  330. }
  331.  
  332.  
  333.  
  334.  
  335. //-----------------------------------------------------------------------------
  336. // Name: RenderShadow()
  337. // Desc:
  338. //-----------------------------------------------------------------------------
  339. HRESULT CMyD3DApplication::RenderShadow()
  340. {
  341.     // Disable z-buffer writes (note: z-testing still occurs), and enable the
  342.     // stencil-buffer
  343.     m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE,  FALSE );
  344.     m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE, TRUE );
  345.  
  346.     // Dont bother with interpolating color
  347.     m_pd3dDevice->SetRenderState( D3DRS_SHADEMODE,     D3DSHADE_FLAT );
  348.  
  349.     // Set up stencil compare fuction, reference value, and masks.
  350.     // Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true.
  351.     // Note: since we set up the stencil-test to always pass, the STENCILFAIL
  352.     // renderstate is really not needed.
  353.     m_pd3dDevice->SetRenderState( D3DRS_STENCILFUNC,  D3DCMP_ALWAYS );
  354.     m_pd3dDevice->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
  355.     m_pd3dDevice->SetRenderState( D3DRS_STENCILFAIL,  D3DSTENCILOP_KEEP );
  356.  
  357.     // If ztest passes, inc/decrement stencil buffer value
  358.     m_pd3dDevice->SetRenderState( D3DRS_STENCILREF,       0x1 );
  359.     m_pd3dDevice->SetRenderState( D3DRS_STENCILMASK,      0xffffffff );
  360.     m_pd3dDevice->SetRenderState( D3DRS_STENCILWRITEMASK, 0xffffffff );
  361.     m_pd3dDevice->SetRenderState( D3DRS_STENCILPASS,      D3DSTENCILOP_INCR );
  362.  
  363.     // Make sure that no pixels get drawn to the frame buffer
  364.     m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  365.     m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_ZERO );
  366.     m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
  367.  
  368.     // Draw front-side of shadow volume in stencil/z only
  369.     m_pd3dDevice->SetTransform( D3DTS_WORLD, &m_matObjectMatrix );
  370.     m_pShadowVolume->Render( m_pd3dDevice );
  371.  
  372.     // Now reverse cull order so back sides of shadow volume are written.
  373.     m_pd3dDevice->SetRenderState( D3DRS_CULLMODE,   D3DCULL_CW );
  374.  
  375.     // Decrement stencil buffer value
  376.     m_pd3dDevice->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_DECR );
  377.  
  378.     // Draw back-side of shadow volume in stencil/z only
  379.     m_pd3dDevice->SetTransform( D3DTS_WORLD, &m_matObjectMatrix );
  380.     m_pShadowVolume->Render( m_pd3dDevice );
  381.  
  382.     // Restore render states
  383.     m_pd3dDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );
  384.     m_pd3dDevice->SetRenderState( D3DRS_CULLMODE,  D3DCULL_CCW );
  385.     m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE,     TRUE );
  386.     m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    FALSE );
  387.     m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
  388.  
  389.     return S_OK;
  390. }
  391.  
  392.  
  393.  
  394.  
  395. //-----------------------------------------------------------------------------
  396. // Name: DrawShadow()
  397. // Desc: Draws a big gray polygon over scene according to the mask in the
  398. //       stencil buffer. (Any pixel with stencil==1 is in the shadow.)
  399. //-----------------------------------------------------------------------------
  400. HRESULT CMyD3DApplication::DrawShadow()
  401. {
  402.     // Set renderstates (disable z-buffering, enable stencil, disable fog, and
  403.     // turn on alphablending)
  404.     m_pd3dDevice->SetRenderState( D3DRS_ZENABLE,          FALSE );
  405.     m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    TRUE );
  406.     m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE,        FALSE );
  407.     m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  408.     m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
  409.     m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  410.  
  411.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  412.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  413.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  414.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  415.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
  416.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
  417.  
  418.     // Only write where stencil val >= 1 (count indicates # of shadows that
  419.     // overlap that pixel)
  420.     m_pd3dDevice->SetRenderState( D3DRS_STENCILREF,  0x1 );
  421.     m_pd3dDevice->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_LESSEQUAL );
  422.     m_pd3dDevice->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_KEEP );
  423.  
  424.     // Draw a big, gray square
  425.     m_pd3dDevice->SetVertexShader( D3DFVF_SHADOWVERTEX );
  426.     m_pd3dDevice->SetStreamSource( 0, m_pBigSquareVB, sizeof(SHADOWVERTEX) );
  427.     m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
  428.  
  429.     // Restore render states
  430.     m_pd3dDevice->SetRenderState( D3DRS_ZENABLE,          TRUE );
  431.     m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    FALSE );
  432.     m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE,        TRUE );
  433.     m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
  434.  
  435.     return S_OK;
  436. }
  437.  
  438.  
  439.  
  440.  
  441. //-----------------------------------------------------------------------------
  442. // Name: Render()
  443. // Desc: Called once per frame, the call is the entry point for 3d
  444. //       rendering. This function sets up render states, clears the
  445. //       viewport, and renders the scene.
  446. //-----------------------------------------------------------------------------
  447. HRESULT CMyD3DApplication::Render()
  448. {
  449.     // Clear the viewport, zbuffer, and stencil buffer
  450.     m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,
  451.                          0xff0000ff, 1.0f, 0L );
  452.  
  453.     // Begin the scene
  454.     if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
  455.     {
  456.         m_pd3dDevice->SetTransform( D3DTS_WORLD, &m_matTerrainMatrix );
  457.         m_pTerrainObject->Render( m_pd3dDevice );
  458.  
  459.         m_pd3dDevice->SetTransform( D3DTS_WORLD, &m_matObjectMatrix );
  460.         m_pAirplane->Render( m_pd3dDevice );
  461.  
  462. /*
  463.         // Draw shadow volume
  464.         m_pd3dDevice->SetTransform( D3DTS_WORLD, &m_matObjectMatrix );
  465.         m_pShadowVolume->Render( m_pd3dDevice );
  466. */
  467.  
  468.         // Render the shadow volume into the stenicl buffer, then add it into
  469.         // the scene
  470.         RenderShadow();
  471.         DrawShadow();
  472.  
  473.         // Output statistics
  474.         m_pFont->DrawText( 2,  0, D3DCOLOR_ARGB(255,255,255,0), m_strFrameStats );
  475.         m_pFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats );
  476.  
  477.         // End the scene.
  478.         m_pd3dDevice->EndScene();
  479.      }
  480.  
  481.     return S_OK;
  482. }
  483.  
  484.  
  485.  
  486.  
  487. //-----------------------------------------------------------------------------
  488. // Name: InitDeviceObjects()
  489. // Desc: Initialize scene objects.
  490. //-----------------------------------------------------------------------------
  491. HRESULT CMyD3DApplication::InitDeviceObjects()
  492. {
  493.     // Initialize the font's internal textures
  494.     m_pFont->InitDeviceObjects( m_pd3dDevice );
  495.  
  496.     // Load an object to cast the shadow
  497.     if( FAILED( m_pAirplane->Create( m_pd3dDevice, _T("airplane 2.x") ) ) )
  498.         return D3DAPPERR_MEDIANOTFOUND;
  499.  
  500.     // Load some terrain
  501.     if( FAILED( m_pTerrainObject->Create( m_pd3dDevice, _T("SeaFloor.x") ) ) )
  502.         return D3DAPPERR_MEDIANOTFOUND;
  503.  
  504.     // Set a reasonable vertex type
  505.     m_pAirplane->SetFVF( m_pd3dDevice, D3DFVF_VERTEX );
  506.     m_pTerrainObject->SetFVF( m_pd3dDevice, D3DFVF_VERTEX );
  507.  
  508.     // Tweak the terrain vertices
  509.     {
  510.         LPDIRECT3DVERTEXBUFFER8 pVB;
  511.         VERTEX* pVertices;
  512.         DWORD   dwNumVertices = m_pTerrainObject->GetSysMemMesh()->GetNumVertices();
  513.  
  514.         // Lock the vertex buffer to access the terrain geometry
  515.         m_pTerrainObject->GetSysMemMesh()->GetVertexBuffer( &pVB );
  516.         pVB->Lock( 0, 0, (BYTE**)&pVertices, 0 );
  517.  
  518.         // Add some more bumpiness to the terrain object
  519.         for( DWORD i=0; i<dwNumVertices; i++ )
  520.         {
  521.             pVertices[i].p.y  += 1*(rand()/(FLOAT)RAND_MAX);
  522.             pVertices[i].p.y  += 2*(rand()/(FLOAT)RAND_MAX);
  523.             pVertices[i].p.y  += 1*(rand()/(FLOAT)RAND_MAX);
  524.         }
  525.  
  526.         // Release the vertex buffer
  527.         pVB->Unlock();
  528.         pVB->Release();
  529.     }
  530.  
  531.     // Create a big square for rendering the stencilbuffer contents
  532.     if( FAILED( m_pd3dDevice->CreateVertexBuffer( 4*sizeof(SHADOWVERTEX),
  533.                                        D3DUSAGE_WRITEONLY, D3DFVF_SHADOWVERTEX,
  534.                                        D3DPOOL_MANAGED, &m_pBigSquareVB ) ) )
  535.         return E_FAIL;
  536.  
  537.     return S_OK;
  538. }
  539.  
  540.  
  541.  
  542.  
  543. //-----------------------------------------------------------------------------
  544. // Name: RestoreDeviceObjects()
  545. // Desc: Restore device-memory objects and state after a device is created or
  546. //       resized.
  547. //-----------------------------------------------------------------------------
  548. HRESULT CMyD3DApplication::RestoreDeviceObjects()
  549. {
  550.     m_pFont->RestoreDeviceObjects();
  551.  
  552.     // Initialize the vertex buffers for the file-based objects
  553.     m_pAirplane->RestoreDeviceObjects( m_pd3dDevice );
  554.     m_pTerrainObject->RestoreDeviceObjects( m_pd3dDevice );
  555.  
  556.     // Create and set up the shine materials w/ textures
  557.     D3DMATERIAL8 mtrl;
  558.     D3DUtil_InitMaterial( mtrl, 1.0f, 1.0f, 1.0f );
  559.     m_pd3dDevice->SetMaterial( &mtrl );
  560.  
  561.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  562.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  563.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  564.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  565.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  566.  
  567.     m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
  568.     m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, TRUE );
  569.     m_pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE, FALSE );
  570.  
  571.     // Set the transform matrices
  572.     D3DXVECTOR3 vEyePt    = D3DXVECTOR3( 0.0f, 10.0f, -20.0f );
  573.     D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f,  0.0f,   0.0f  );
  574.     D3DXVECTOR3 vUpVec    = D3DXVECTOR3( 0.0f,  1.0f,   0.0f  );
  575.     D3DXMATRIX matWorld, matView, matProj;
  576.  
  577.     D3DXMatrixIdentity( &matWorld );
  578.     D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
  579.     FLOAT fAspect = m_d3dsdBackBuffer.Width / (FLOAT)m_d3dsdBackBuffer.Height;
  580.     D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect, 1.0f, 100.0f );
  581.  
  582.     m_pd3dDevice->SetTransform( D3DTS_WORLD,      &matWorld );
  583.     m_pd3dDevice->SetTransform( D3DTS_VIEW,       &matView );
  584.     m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
  585.  
  586.     // Turn on fog
  587.     FLOAT fFogStart =  30.0f;
  588.     FLOAT fFogEnd   =  80.0f;
  589.     m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE,      TRUE );
  590.     m_pd3dDevice->SetRenderState( D3DRS_FOGCOLOR,       0xff0000ff );
  591.     m_pd3dDevice->SetRenderState( D3DRS_FOGTABLEMODE,   D3DFOG_NONE );
  592.     m_pd3dDevice->SetRenderState( D3DRS_FOGVERTEXMODE,  D3DFOG_LINEAR );
  593.     m_pd3dDevice->SetRenderState( D3DRS_RANGEFOGENABLE, FALSE );
  594.     m_pd3dDevice->SetRenderState( D3DRS_FOGSTART,       FtoDW(fFogStart) );
  595.     m_pd3dDevice->SetRenderState( D3DRS_FOGEND,         FtoDW(fFogEnd) );
  596.  
  597.     // Set the ArcBall parameters
  598.     m_ArcBall.SetWindow( m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height, 2.0f );
  599.     m_ArcBall.SetRadius( 5.0f );
  600.  
  601.     m_pd3dDevice->LightEnable( 0, TRUE );
  602.     m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
  603.     m_pd3dDevice->SetRenderState( D3DRS_AMBIENT,  0x00303030 );
  604.  
  605.     // Set the size of the big square shadow
  606.     SHADOWVERTEX* v;
  607.     FLOAT sx = (FLOAT)m_d3dsdBackBuffer.Width;
  608.     FLOAT sy = (FLOAT)m_d3dsdBackBuffer.Height;
  609.     m_pBigSquareVB->Lock( 0, 0, (BYTE**)&v, 0 );
  610.     v[0].p = D3DXVECTOR4(  0, sy, 0.0f, 1.0f );
  611.     v[1].p = D3DXVECTOR4(  0,  0, 0.0f, 1.0f );
  612.     v[2].p = D3DXVECTOR4( sx, sy, 0.0f, 1.0f );
  613.     v[3].p = D3DXVECTOR4( sx,  0, 0.0f, 1.0f );
  614.     v[0].color = 0x7f000000;
  615.     v[1].color = 0x7f000000;
  616.     v[2].color = 0x7f000000;
  617.     v[3].color = 0x7f000000;
  618.     m_pBigSquareVB->Unlock();
  619.  
  620.     return S_OK;
  621. }
  622.  
  623.  
  624.  
  625.  
  626. //-----------------------------------------------------------------------------
  627. // Name: InvalidateDeviceObjects()
  628. // Desc: Called when the device-dependent objects are about to be lost.
  629. //-----------------------------------------------------------------------------
  630. HRESULT CMyD3DApplication::InvalidateDeviceObjects()
  631. {
  632.     m_pFont->InvalidateDeviceObjects();
  633.     m_pAirplane->InvalidateDeviceObjects();
  634.     m_pTerrainObject->InvalidateDeviceObjects();
  635.     return S_OK;
  636. }
  637.  
  638.  
  639.  
  640.  
  641. //-----------------------------------------------------------------------------
  642. // Name: DeleteDeviceObjects()
  643. // Desc: Called when the app is exiting, or the device is being changed,
  644. //       this function deletes any device dependent objects.
  645. //-----------------------------------------------------------------------------
  646. HRESULT CMyD3DApplication::DeleteDeviceObjects()
  647. {
  648.     m_pFont->DeleteDeviceObjects();
  649.     m_pAirplane->Destroy();
  650.     m_pTerrainObject->Destroy();
  651.  
  652.     SAFE_RELEASE( m_pBigSquareVB );
  653.  
  654.     return S_OK;
  655. }
  656.  
  657.  
  658.  
  659.  
  660. //-----------------------------------------------------------------------------
  661. // Name: FinalCleanup()
  662. // Desc: Called before the app exits, this function gives the app the chance
  663. //       to cleanup after itself.
  664. //-----------------------------------------------------------------------------
  665. HRESULT CMyD3DApplication::FinalCleanup()
  666. {
  667.     SAFE_DELETE( m_pFont );
  668.     SAFE_DELETE( m_pAirplane );
  669.     SAFE_DELETE( m_pTerrainObject );
  670.     SAFE_DELETE( m_pShadowVolume );
  671.  
  672.     return S_OK;
  673. }
  674.  
  675.  
  676.  
  677.  
  678. //-----------------------------------------------------------------------------
  679. // Name: ConfirmDevice()
  680. // Desc: Called during device intialization, this code checks the device
  681. //       for some minimum set of capabilities
  682. //-----------------------------------------------------------------------------
  683. HRESULT CMyD3DApplication::ConfirmDevice( D3DCAPS8* pCaps, DWORD dwBehavior,
  684.                                           D3DFORMAT Format )
  685. {
  686.     // Make sure device supports point lights
  687.     if( (dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING ) ||
  688.         (dwBehavior & D3DCREATE_MIXED_VERTEXPROCESSING ) )
  689.     {
  690.         if( 0 == ( pCaps->VertexProcessingCaps & D3DVTXPCAPS_POSITIONALLIGHTS ) )
  691.             return E_FAIL;
  692.     }
  693.  
  694.     return S_OK;
  695. }
  696.  
  697.  
  698.  
  699.  
  700. //-----------------------------------------------------------------------------
  701. // Name: MsgProc()
  702. // Desc: Message proc function to handle key and menu input
  703. //-----------------------------------------------------------------------------
  704. LRESULT CMyD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
  705.                                     LPARAM lParam )
  706. {
  707.     // Pass mouse messages to the ArcBall so it can build internal matrices
  708.     m_ArcBall.HandleMouseMessages( hWnd, uMsg, wParam, lParam );
  709.  
  710.     // Trap the context menu
  711.     if( WM_CONTEXTMENU == uMsg )
  712.         return 0;
  713.  
  714.     return CD3DApplication::MsgProc( hWnd, uMsg, wParam, lParam );
  715. }
  716.  
  717.  
  718.  
  719.