www.pudn.com > D3DShadow.rar > Shadow.cpp


#include  
#include  
#include  
#include "d3dfile.h" 
#include "d3dutil.h" 
 
//----------------------------------------------------------------------------- 
// External definitions and prototypes 
//----------------------------------------------------------------------------- 
inline DWORD FtoDW( FLOAT f ) { return *((DWORD*)&f); } 
 
struct VERTEX 
{ 
    D3DXVECTOR3 p; 
    D3DXVECTOR3 n; 
    FLOAT       tu, tv; 
 
    static const DWORD FVF; 
}; 
const DWORD VERTEX::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1; 
 
struct SHADOWVERTEX 
{ 
    D3DXVECTOR4 p; 
    D3DCOLOR    color; 
 
    static const DWORD FVF; 
}; 
const DWORD SHADOWVERTEX::FVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE; 
 
//----------------------------------------------------------------------------- 
// Name: struct ShadowVolume 
// Desc: A shadow volume object 
//----------------------------------------------------------------------------- 
class ShadowVolume 
{ 
    D3DXVECTOR3 m_pVertices[32000]; // Vertex data for rendering shadow volume 
    DWORD       m_dwNumVertices; 
 
public: 
    VOID    Reset() { m_dwNumVertices = 0L; } 
    HRESULT BuildFromMesh( LPD3DXMESH pObject, D3DXVECTOR3 vLight ); 
    HRESULT Render( LPDIRECT3DDEVICE9 pd3dDevice ); 
}; 
 
//----------------------------------------------------------------------------- 
// Global variables 
//----------------------------------------------------------------------------- 
LPDIRECT3D9             g_pD3D           = NULL; // Used to create the D3DDevice 
LPDIRECT3DDEVICE9       g_pd3dDevice     = NULL; // Our rendering device 
 
LPD3DXMESH              g_pMesh          = NULL; // Our mesh object in sysmem 
D3DMATERIAL9*           g_pMeshMaterials = NULL; // Materials for our mesh 
LPDIRECT3DTEXTURE9*     g_pMeshTextures  = NULL; // Textures for our mesh 
DWORD                   g_dwNumMaterials = 0L;   // Number of mesh materials 
 
CD3DMesh*     g_pObjectMesh; 
CD3DMesh*     g_pGroundMesh; 
D3DXMATRIXA16    g_pObjectMatrix; 
D3DXMATRIXA16    g_pGroundMatrix; 
 
ShadowVolume* g_pShadowVolume; 
LPDIRECT3DVERTEXBUFFER9 m_pBigSquareVB; 
 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
HRESULT ShadowVolume::Render( LPDIRECT3DDEVICE9 pd3dDevice ) 
{ 
    pd3dDevice->SetFVF( D3DFVF_XYZ ); 
 
    return pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLELIST, m_dwNumVertices/3, 
                                        m_pVertices, sizeof(D3DXVECTOR3) ); 
} 
 
 
//----------------------------------------------------------------------------- 
// Name: AddEdge() 
// Desc: Adds an edge to a list of silohuette edges of a shadow volume. 
//----------------------------------------------------------------------------- 
VOID AddEdge( WORD* pEdges, DWORD& dwNumEdges, WORD v0, WORD v1 ) 
{ 
    // Remove interior edges (which appear in the list twice) 
    for( DWORD i=0; i < dwNumEdges; i++ ) 
    { 
        if( ( pEdges[2*i+0] == v0 && pEdges[2*i+1] == v1 ) || 
            ( pEdges[2*i+0] == v1 && pEdges[2*i+1] == v0 ) ) 
        { 
            if( dwNumEdges > 1 ) 
            { 
                pEdges[2*i+0] = pEdges[2*(dwNumEdges-1)+0]; 
                pEdges[2*i+1] = pEdges[2*(dwNumEdges-1)+1]; 
            } 
            dwNumEdges--; 
            return; 
        } 
    } 
 
    pEdges[2*dwNumEdges+0] = v0; 
    pEdges[2*dwNumEdges+1] = v1; 
    dwNumEdges++; 
} 
 
//----------------------------------------------------------------------------- 
// Name: BuildFromMesh() 
// Desc: Takes a mesh as input, and uses it to build a shadowvolume. The 
//       technique used considers each triangle of the mesh, and adds it's 
//       edges to a temporary list. The edge list is maintained, such that 
//       only silohuette edges are kept. Finally, the silohuette edges are 
//       extruded to make the shadow volume vertex list. 
//----------------------------------------------------------------------------- 
HRESULT ShadowVolume::BuildFromMesh( LPD3DXMESH pMesh, D3DXVECTOR3 vLight ) 
{ 
    // Note: the MESHVERTEX format depends on the FVF of the mesh 
    struct MESHVERTEX { D3DXVECTOR3 p, n; FLOAT tu, tv; }; 
 
    MESHVERTEX* pVertices; 
    WORD*       pIndices; 
 
    // Lock the geometry buffers 
    pMesh->LockVertexBuffer( 0L, (LPVOID*)&pVertices ); 
    pMesh->LockIndexBuffer( 0L, (LPVOID*)&pIndices ); 
    DWORD dwNumFaces    = pMesh->GetNumFaces(); 
 
    // Allocate a temporary edge list 
    WORD* pEdges = new WORD[dwNumFaces*6]; 
    if( pEdges == NULL ) 
    { 
        pMesh->UnlockVertexBuffer(); 
        pMesh->UnlockIndexBuffer(); 
        return E_OUTOFMEMORY; 
    } 
    DWORD dwNumEdges = 0; 
 
    // For each face 
    for( DWORD i=0; i= 0.0f ) 
        { 
            AddEdge( pEdges, dwNumEdges, wFace0, wFace1 ); 
            AddEdge( pEdges, dwNumEdges, wFace1, wFace2 ); 
            AddEdge( pEdges, dwNumEdges, wFace2, wFace0 ); 
        } 
    } 
 
    for( i=0; iUnlockVertexBuffer(); 
    pMesh->UnlockIndexBuffer(); 
 
    return S_OK; 
} 
 
//----------------------------------------------------------------------------- 
// Name: RenderShadow() 
// Desc: 
//----------------------------------------------------------------------------- 
HRESULT RenderShadow() 
{ 
    // Disable z-buffer writes (note: z-testing still occurs), and enable the 
    // stencil-buffer 
    g_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE,  FALSE ); 
    g_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE, TRUE ); 
 
    // Dont bother with interpolating color 
    g_pd3dDevice->SetRenderState( D3DRS_SHADEMODE,     D3DSHADE_FLAT ); 
 
    // Set up stencil compare fuction, reference value, and masks. 
    // Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true. 
    // Note: since we set up the stencil-test to always pass, the STENCILFAIL 
    // renderstate is really not needed. 
    g_pd3dDevice->SetRenderState( D3DRS_STENCILFUNC,  D3DCMP_ALWAYS ); 
    g_pd3dDevice->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP ); 
    g_pd3dDevice->SetRenderState( D3DRS_STENCILFAIL,  D3DSTENCILOP_KEEP ); 
 
    // If ztest passes, inc/decrement stencil buffer value 
    g_pd3dDevice->SetRenderState( D3DRS_STENCILREF,       0x1 ); 
    g_pd3dDevice->SetRenderState( D3DRS_STENCILMASK,      0xffffffff ); 
    g_pd3dDevice->SetRenderState( D3DRS_STENCILWRITEMASK, 0xffffffff ); 
    g_pd3dDevice->SetRenderState( D3DRS_STENCILPASS,      D3DSTENCILOP_INCR ); 
 
    // Make sure that no pixels get drawn to the frame buffer 
    g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); 
    g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_ZERO ); 
    g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE ); 
 
	{ 
        // Draw front-side of shadow volume in stencil/z only 
        g_pd3dDevice->SetTransform( D3DTS_WORLD, &g_pObjectMatrix ); 
        g_pShadowVolume->Render( g_pd3dDevice ); 
 
        // Now reverse cull order so back sides of shadow volume are written. 
        g_pd3dDevice->SetRenderState( D3DRS_CULLMODE,   D3DCULL_CW ); 
 
        // Decrement stencil buffer value 
        g_pd3dDevice->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_DECR ); 
 
        // Draw back-side of shadow volume in stencil/z only 
        g_pd3dDevice->SetTransform( D3DTS_WORLD, &g_pObjectMatrix ); 
        g_pShadowVolume->Render( g_pd3dDevice ); 
    } 
 
    // Restore render states 
    g_pd3dDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD ); 
    g_pd3dDevice->SetRenderState( D3DRS_CULLMODE,  D3DCULL_CCW ); 
    g_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE,     TRUE ); 
    g_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    FALSE ); 
    g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); 
 
    return S_OK; 
} 
 
//----------------------------------------------------------------------------- 
// Name: DrawShadow() 
// Desc: Draws a big gray polygon over scene according to the mask in the 
//       stencil buffer. (Any pixel with stencil==1 is in the shadow.) 
//----------------------------------------------------------------------------- 
HRESULT DrawShadow() 
{ 
    // Set renderstates (disable z-buffering, enable stencil, disable fog, and 
    // turn on alphablending) 
    g_pd3dDevice->SetRenderState( D3DRS_ZENABLE,          FALSE ); 
    g_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    TRUE ); 
    g_pd3dDevice->SetRenderState( D3DRS_FOGENABLE,        FALSE ); 
    g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); 
    g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA ); 
    g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); 
 
    g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); 
    g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); 
    g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,  D3DTOP_MODULATE);//D3DTOP_SELECTARG2);// D3DTOP_MODULATE ); 
 
    g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); 
    g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); 
    g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE ); 
 
    // Only write where stencil val >= 1 (count indicates # of shadows that 
    // overlap that pixel) 
    g_pd3dDevice->SetRenderState( D3DRS_STENCILREF,  0x1 ); 
    g_pd3dDevice->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_LESSEQUAL ); 
    g_pd3dDevice->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_KEEP ); 
 
    // Draw a big, gray square 
    g_pd3dDevice->SetFVF( SHADOWVERTEX::FVF ); 
    g_pd3dDevice->SetStreamSource( 0, m_pBigSquareVB, 0, sizeof(SHADOWVERTEX) ); 
    g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 ); 
 
    // Restore render states 
    g_pd3dDevice->SetRenderState( D3DRS_ZENABLE,          TRUE ); 
    g_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    FALSE ); 
    g_pd3dDevice->SetRenderState( D3DRS_FOGENABLE,        FALSE ); 
    g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); 
 
    return S_OK; 
} 
 
 
//----------------------------------------------------------------------------- 
// Name: InitD3D() 
// Desc: Initializes Direct3D 
//----------------------------------------------------------------------------- 
HRESULT InitD3D( HWND hWnd ) 
{ 
    // Create the D3D object. 
    if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ) 
        return E_FAIL; 
 
    // Set up the structure used to create the D3DDevice. Since we are now 
    // using more complex geometry, we will create a device with a zbuffer. 
    D3DPRESENT_PARAMETERS d3dpp;  
    ZeroMemory( &d3dpp, sizeof(d3dpp) ); 
    d3dpp.Windowed = TRUE; 
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; 
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; 
    d3dpp.EnableAutoDepthStencil = TRUE; 
    d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; 
 
    // Create the D3DDevice 
    if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, 
                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING, 
                                      &d3dpp, &g_pd3dDevice ) ) ) 
    { 
        return E_FAIL; 
    } 
    // Turn on the zbuffer 
    g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE ); 
 
    // Turn on ambient lighting  
    g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff ); 
 
    return S_OK; 
} 
 
//----------------------------------------------------------------------------- 
// Name: InitGeometry() 
// Desc: Load the mesh and build the material and texture arrays 
//----------------------------------------------------------------------------- 
HRESULT InitGeometry() 
{ 
	g_pObjectMesh= new CD3DMesh(); 
    if( FAILED( g_pObjectMesh->Create( g_pd3dDevice, _T("man.x") ) ) ) 
        return E_FAIL; 
	g_pObjectMesh->SetFVF( g_pd3dDevice,VERTEX::FVF ); 
	g_pObjectMesh->RestoreDeviceObjects( g_pd3dDevice); 
 
	g_pGroundMesh= new CD3DMesh(); 
    if( FAILED( g_pGroundMesh->Create( g_pd3dDevice, _T("hill.x") ) ) ) 
        return E_FAIL; 
	g_pGroundMesh->SetFVF( g_pd3dDevice, VERTEX::FVF ); 
	g_pGroundMesh->RestoreDeviceObjects( g_pd3dDevice); 
     
	g_pShadowVolume = new ShadowVolume();	 
	 
	// We need to extract the material properties and texture names from the  
    // pD3DXMtrlBuffer 
    // Create a big square for rendering the stencilbuffer contents 
    if( FAILED( g_pd3dDevice->CreateVertexBuffer( 4*sizeof(SHADOWVERTEX), 
                                       D3DUSAGE_WRITEONLY, SHADOWVERTEX::FVF, 
                                       D3DPOOL_MANAGED, &m_pBigSquareVB, NULL ) ) ) 
        return E_FAIL; 
	SHADOWVERTEX* v; 
    FLOAT sx = (FLOAT)580; 
    FLOAT sy = (FLOAT)600; 
 
    m_pBigSquareVB->Lock( 0, 0, (void**)&v, 0 ); 
    v[0].p = D3DXVECTOR4(  0, sy, 0.0f, 1.0f ); 
    v[1].p = D3DXVECTOR4(  0,  0, 0.0f, 1.0f ); 
    v[2].p = D3DXVECTOR4( sx, sy, 0.0f, 1.0f ); 
    v[3].p = D3DXVECTOR4( sx,  0, 0.0f, 1.0f ); 
    v[0].color = 0x7f000000; 
    v[1].color = 0x7f000000; 
    v[2].color = 0x7f000000; 
    v[3].color = 0x7f000000; 
    m_pBigSquareVB->Unlock(); 
 
    return S_OK; 
} 
 
VOID SetupLights() 
{ 
    // Set up a material. The material here just has the diffuse and ambient 
    // colors set to yellow. Note that only one material can be used at a time. 
    D3DMATERIAL9 mtrl; 
    ZeroMemory( &mtrl, sizeof(D3DMATERIAL9) ); 
    mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f; 
    mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f; 
    mtrl.Diffuse.b = mtrl.Ambient.b = 1.0f; 
    mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f; 
    g_pd3dDevice->SetMaterial( &mtrl ); 
//set up lights 
    D3DXVECTOR3 vecDir; 
    D3DLIGHT9 light; 
    ZeroMemory( &light, sizeof(D3DLIGHT9) ); 
    light.Type       = D3DLIGHT_DIRECTIONAL; 
    light.Diffuse.r  = 1.0f; 
    light.Diffuse.g  = 1.0f; 
    light.Diffuse.b  = 1.0f; 
    vecDir = D3DXVECTOR3(10,10,-10); 
     
	D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vecDir ); 
    light.Range       = 5000.0f; 
    g_pd3dDevice->SetLight( 0, &light ); 
    g_pd3dDevice->LightEnable( 0, TRUE ); 
    g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE ); 
 
    // Finally, turn on some ambient light. 
    g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x00404040 ); 
} 
 
 
 
//----------------------------------------------------------------------------- 
// Name: Cleanup() 
// Desc: Releases all previously initialized objects 
//----------------------------------------------------------------------------- 
VOID Cleanup() 
{ 
	if (g_pObjectMesh) 
		delete g_pObjectMesh; 
	if (g_pGroundMesh) 
		delete g_pGroundMesh; 
 
	if(m_pBigSquareVB) 
		m_pBigSquareVB->Release(); 
	if(g_pShadowVolume ) 
		delete g_pShadowVolume ; 
 
    if( g_pd3dDevice != NULL ) 
        g_pd3dDevice->Release(); 
 
    if( g_pD3D != NULL ) 
        g_pD3D->Release(); 
} 
 
 
 
//----------------------------------------------------------------------------- 
// Name: SetupMatrices() 
// Desc: Sets up the world, view, and projection transform matrices. 
//----------------------------------------------------------------------------- 
VOID SetupMatrices() 
{ 
    // For our world matrix, we will just leave it as the identity 
    D3DXMATRIXA16 matWorld; 
    D3DXMatrixRotationZ( &g_pObjectMatrix, 0);//timeGetTime()/1000.0f ); 
//	D3DXMatrixTranslation(&g_pObjectMatrix,0,0,10); 
	static float step=100.f; 
	g_pObjectMatrix.m[3][2]=step; 
	 
	D3DXMatrixRotationZ( &g_pGroundMatrix, 0 ); 
	//g_pObjectMatrix 
    //g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); 
 
    // Set up our view matrix. A view matrix can be defined given an eye point, 
    // a point to lookat, and a direction for which way is up. Here, we set the 
    // eye five units back along the z-axis and up three units, look at the  
    // origin, and define "up" to be in the y-direction. 
	// D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f ); 
    D3DXVECTOR3 vEyePt( 100.0f, -100.0f,100.0f ); 
 
    D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 42.0f ); 
    D3DXVECTOR3 vUpVec( 0.0f, .0f, 1.0f ); 
    D3DXMATRIXA16 matView; 
    D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec ); 
    g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView ); 
 
    // For the projection matrix, we set up a perspective transform (which 
    // transforms geometry from 3D view space to 2D viewport space, with 
    // a perspective divide making objects smaller in the distance). To build 
    // a perpsective transform, we need the field of view (1/4 pi is common), 
    // the aspect ratio, and the near and far clipping planes (which define at 
    // what distances geometry should be no longer be rendered). 
    D3DXMATRIXA16 matProj; 
    //D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f ); 
    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 10000.0f ); 
 
    g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj ); 
} 
 
 
 
void Update() 
{ 
    // Move the light  
    FLOAT Lx =   200*cosf(timeGetTime()/1000.0f); 
    FLOAT Ly =   200*sinf(timeGetTime()/1000.0f); 
    FLOAT Lz =  400; 
    D3DLIGHT9 light; 
    D3DUtil_InitLight( light, D3DLIGHT_POINT, Lx, Ly, Lz ); 
    light.Attenuation0 = 0.9f; 
    light.Attenuation1 = 0.0f; 
    g_pd3dDevice->SetLight( 0, &light ); 
 
    // Transform the light vector to be in object space 
    D3DXVECTOR3 vLight; 
    D3DXMATRIXA16 m; 
    D3DXMatrixInverse( &m, NULL, &g_pObjectMatrix);//m_matObjectMatrix ); 
    vLight.x = Lx*m._11 + Ly*m._21 + Lz*m._31 + m._41; 
    vLight.y = Lx*m._12 + Ly*m._22 + Lz*m._32 + m._42; 
    vLight.z = Lx*m._13 + Ly*m._23 + Lz*m._33 + m._43; 
 
    // Build the shadow volume 
    g_pShadowVolume->Reset(); 
    g_pShadowVolume->BuildFromMesh( g_pObjectMesh->GetSysMemMesh(), vLight ); 
 
    g_pd3dDevice->LightEnable( 0, TRUE ); 
    g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE ); 
 
    // Finally, turn on some ambient light. 
    g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x00a0a0a0 ); 
 
} 
 
 
//----------------------------------------------------------------------------- 
// Name: Render() 
// Desc: Draws the scene 
//----------------------------------------------------------------------------- 
VOID Render() 
{ 
    // Clear the backbuffer and the zbuffer 
    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,  
                         D3DCOLOR_XRGB(0,0,255), 1.0f, 0 ); 
     
    // Begin the scene 
    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) ) 
    { 
        // Setup the world, view, and projection matrices 
        SetupMatrices(); 
//		SetupLights(); 
		Update(); 
        // Meshes are divided into subsets, one for each material. Render them in 
        // a loop 
		g_pd3dDevice->SetTransform( D3DTS_WORLD, &g_pGroundMatrix ); 
		g_pGroundMesh->Render(g_pd3dDevice); 
		g_pd3dDevice->SetTransform( D3DTS_WORLD, &g_pObjectMatrix ); 
		g_pObjectMesh->Render(g_pd3dDevice); 
 
		RenderShadow(); 
		DrawShadow(); 
        // End the scene 
        g_pd3dDevice->EndScene(); 
    } 
 
    // Present the backbuffer contents to the display 
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL ); 
} 
 
 
 
//----------------------------------------------------------------------------- 
// Name: MsgProc() 
// Desc: The window's message handler 
//----------------------------------------------------------------------------- 
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) 
{ 
    switch( msg ) 
    { 
        case WM_DESTROY: 
            Cleanup(); 
            PostQuitMessage( 0 ); 
            return 0; 
    } 
 
    return DefWindowProc( hWnd, msg, wParam, lParam ); 
} 
 
 
 
 
//----------------------------------------------------------------------------- 
// Name: WinMain() 
// Desc: The application's entry point 
//----------------------------------------------------------------------------- 
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT ) 
{ 
    // Register the window class 
    WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,  
                      GetModuleHandle(NULL), NULL, NULL, NULL, NULL, 
                      "D3D Tutorial", NULL }; 
    RegisterClassEx( &wc ); 
 
    // Create the application's window 
    HWND hWnd = CreateWindow( "D3D Tutorial", "D3D Tutorial :shadow volume",  
                              WS_OVERLAPPEDWINDOW, 0, 0, 580, 600, 
                              GetDesktopWindow(), NULL, wc.hInstance, NULL ); 
 
    // Initialize Direct3D 
    if( SUCCEEDED( InitD3D( hWnd ) ) ) 
    {  
        // Create the scene geometry 
        if( SUCCEEDED( InitGeometry() ) ) 
        { 
            // Show the window 
            ShowWindow( hWnd, SW_SHOWDEFAULT ); 
            UpdateWindow( hWnd ); 
 
            // Enter the message loop 
            MSG msg;  
            ZeroMemory( &msg, sizeof(msg) ); 
            while( msg.message!=WM_QUIT ) 
            { 
                if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) 
                { 
                    TranslateMessage( &msg ); 
                    DispatchMessage( &msg ); 
                } 
                else 
                    Render(); 
            } 
        } 
    } 
 
    UnregisterClass( "D3D Tutorial", wc.hInstance ); 
    return 0; 
}