www.pudn.com > d3d_grass.rar > Grass.cpp
#define STRICT #include#include #include #include #include #include #include "D3DApp.h" #include "D3DFile.h" #include "D3DFont.h" #include "D3DUtil.h" #include "DXUtil.h" #include "resource.h" /* regular vert with tex coord */ typedef struct { FLOAT x, y, z; FLOAT tu1, tv1; } VERTEX; DWORD dwVertexDecl[] = { D3DVSD_STREAM( 0 ), D3DVSD_REG( 0, D3DVSDT_FLOAT3 ), // Position D3DVSD_REG( 7, D3DVSDT_FLOAT2 ), // Tex coord D3DVSD_END() }; #define D3DFVF_VERTEX (D3DFVF_XYZ|D3DFVF_TEX1) static VERTEX g_Vertices[]= { // x y z tu1 tv1 { -10.0f, 0.0f, 0.0f, 1.0f, 1.0f }, { 10.0f, 0.0f, 0.0f, 0.01f, 1.0f }, { 10.0f, 0.0f, -10.0f, 0.01f, 0.01f }, { -10.0f, 0.0f, 0.0f, 1.0f, 1.0f }, { 10.0f, 0.0f, -10.0f, 0.01f, 0.01f }, { -10.0f, 0.0f, -10.0f, 1.0f, 0.01f }, }; static VERTEX g_GroundVertices[]= { // x y z tu1 tv1 { -60.0f, 30.0f, 0.0f, 10.0f, 10.0f }, { 60.0f, 30.0f, 0.0f, 0.0f, 10.0f }, { 60.0f, -30.0f, 0.0f, 0.0f, 0.0f }, { -60.0f, -30.0f, 0.0f, 10.0f, 0.0f }, }; //----------------------------------------------------------------------------- // Name: class CMyD3DApplication // Desc: Application class. The base class (CD3DApplication) provides the // generic functionality needed in all Direct3D samples. CMyD3DApplication // adds functionality specific to this sample program. //----------------------------------------------------------------------------- class CMyD3DApplication : public CD3DApplication { CD3DFont* m_pStatsFont; CD3DFont* m_pSmallFont; DWORD m_iNumQuads; LPDIRECT3DVERTEXBUFFER8 m_pQuadsVB; LPDIRECT3DVERTEXBUFFER8 m_pGroundQuadVB; LPDIRECT3DTEXTURE8 m_pTex; LPDIRECT3DTEXTURE8 m_pGroundTex; DWORD m_dwVShader; DWORD m_dwPShader; D3DXMATRIX m_matWorld, m_matView, m_matProj; D3DXMATRIX m_matInitial; BOOL m_bShowHelp; BOOL m_bVertexShader; BOOL m_bPixelShader; BOOL m_bZBuffer; protected: HRESULT InitDeviceObjects(); HRESULT RestoreDeviceObjects(); HRESULT InvalidateDeviceObjects(); HRESULT DeleteDeviceObjects(); HRESULT Render(); HRESULT FrameMove(); HRESULT FinalCleanup(); public: LRESULT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); CMyD3DApplication(); }; //----------------------------------------------------------------------------- // Name: WinMain() // Desc: Entry point to the program. Initializes everything, and goes into a // message-processing loop. Idle time is used to render the scene. //----------------------------------------------------------------------------- INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT ) { CMyD3DApplication d3dApp; if( FAILED( d3dApp.Create( hInst ) ) ) return 0; return d3dApp.Run(); } //----------------------------------------------------------------------------- // Name: CMyD3DApplication() // Desc: Application constructor. Sets attributes for the app. //----------------------------------------------------------------------------- CMyD3DApplication::CMyD3DApplication() { m_strWindowTitle = _T("Grass"); m_bUseDepthBuffer = TRUE; m_pStatsFont = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD ); m_pSmallFont = new CD3DFont( _T("Arial"), 9, D3DFONT_BOLD ); m_pQuadsVB = NULL; m_pGroundQuadVB = NULL; m_pTex = NULL; m_pGroundTex = NULL; m_dwVShader = 0; m_dwPShader = 0; m_bShowHelp = FALSE; m_bVertexShader = TRUE; m_bPixelShader = TRUE; m_bZBuffer = TRUE; D3DXMatrixIdentity( &m_matInitial ); m_iNumQuads = 400; } //----------------------------------------------------------------------------- // Name: FrameMove() // Desc: Called once per frame, the call is the entry point for animating // the scene. //----------------------------------------------------------------------------- HRESULT CMyD3DApplication::FrameMove() { float r = (float) rand()/RAND_MAX; m_matWorld = m_matInitial; // Set up the vertex shader constants { // c0 - commonConst ( 0.0, 0.5, 1.0, 2.0); // c1 - appConst( time, 0.0, 0.0, 0.0); // c4 - Composite World-View-Projection Matrix // c8 - sin9 ( -1/3!, 1/5!, -1/7!, 1/9! ) // c10 - frcFixup ( 1.07, 0.0, 0.0, 0.0) // c11 - waveDistortx ( 3.0, 0.4, 0.0, 0.3) // c12 - waveDistorty ( 3.0, 0.4, 0.0, 0.3) // c13 - waveDistortz ( -1.0, -0.133, -0.333, -0.10) // c14 - waveDirx ( -0.006, -0.012, 0.024, 0.048) // c15 - waveDiry ( -0.003, -0.006, -0.012, -0.048) // c16 - waveSpeed ( 0.3, 0.6, 0.7, 1.4) // c17 - piVector (4.0, pi/2, pi, pi*2) // c18 - lightingWaveScale ( 0.35, 0.10, 0.10, 0.03); // c19 - lightingScaleBias ( 0.6, 0.7, 0.2, 0.0); D3DXVECTOR4 c0( 0.0f, 0.5f, 1.0f, 2.0f); D3DXVECTOR4 c1( (float)m_fTime, 0.0f, 0.0f, 0.0f); D3DXVECTOR4 c8( -0.16161616f, 0.0083333f, -0.00019841f, 0.000002755731f); D3DXVECTOR4 c10( 1.07f, 0.0f, 0.0f, 0.0f); D3DXVECTOR4 c11( 3.0f, 0.4f, 0.0f, 0.3f); D3DXVECTOR4 c12( 3.0f, 0.4f, 0.0f, 0.3f); D3DXVECTOR4 c13( -1.0f, -0.133f, -0.333f, -0.10f); D3DXVECTOR4 c14( -0.006f, -0.012f, 0.024f, 0.048f); D3DXVECTOR4 c15( -0.003f, -0.006f, -0.012f, -0.048f); D3DXVECTOR4 c16( 0.3f, 0.6f, 0.7f, 1.4f); D3DXVECTOR4 c17( 4.0f, 1.57079632f, 3.14159265f, 6.28318530f); D3DXVECTOR4 c18( 0.35f, 0.10f, 0.10f, 0.03f); D3DXVECTOR4 c19( 0.6f, 0.7f, 0.2f, 0.0f); m_pd3dDevice->SetVertexShaderConstant( 0, c0, 1 ); m_pd3dDevice->SetVertexShaderConstant( 1, c1, 1 ); m_pd3dDevice->SetVertexShaderConstant( 8, c8, 1 ); m_pd3dDevice->SetVertexShaderConstant( 10, c10, 1 ); m_pd3dDevice->SetVertexShaderConstant( 11, c11, 1 ); m_pd3dDevice->SetVertexShaderConstant( 12, c12, 1 ); m_pd3dDevice->SetVertexShaderConstant( 13, c13, 1 ); m_pd3dDevice->SetVertexShaderConstant( 14, c14, 1 ); m_pd3dDevice->SetVertexShaderConstant( 15, c15, 1 ); m_pd3dDevice->SetVertexShaderConstant( 16, c16, 1 ); m_pd3dDevice->SetVertexShaderConstant( 17, c17, 1 ); m_pd3dDevice->SetVertexShaderConstant( 18, c18, 1 ); m_pd3dDevice->SetVertexShaderConstant( 19, c19, 1 ); D3DXMATRIX mat; D3DXMatrixMultiply( &mat, &m_matView, &m_matProj ); D3DXMatrixMultiply( &mat, &m_matWorld, &mat ); D3DXMatrixTranspose( &mat, &mat ); m_pd3dDevice->SetVertexShaderConstant( 4, &mat, 4 ); } return S_OK; } //----------------------------------------------------------------------------- // Name: Render() // Desc: Called once per frame, the call is the entry point for 3d // rendering. This function sets up render states, clears the // viewport, and renders the scene. //----------------------------------------------------------------------------- HRESULT CMyD3DApplication::Render() { // Clear the viewport m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x004010C0, 1.0f, 0L ); // Begin the scene if( SUCCEEDED( m_pd3dDevice->BeginScene() ) ) { // Render the ground plane m_pd3dDevice->SetStreamSource( 0, m_pGroundQuadVB, sizeof(VERTEX) ); m_pd3dDevice->SetTexture(0, m_pGroundTex); m_pd3dDevice->SetVertexShader( D3DFVF_VERTEX ); m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, 2 ); // Render the waving grass m_pd3dDevice->SetStreamSource( 0, m_pQuadsVB, sizeof(VERTEX) ); m_pd3dDevice->SetTransform( D3DTS_WORLD, &m_matWorld ); m_pd3dDevice->SetTexture(0, m_pTex); m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, m_bZBuffer ); if (m_bVertexShader) m_pd3dDevice->SetVertexShader( m_dwVShader ); else m_pd3dDevice->SetVertexShader( D3DFVF_VERTEX ); if (m_bPixelShader) m_pd3dDevice->SetPixelShader( m_dwPShader ); m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, m_iNumQuads*2 ); // Show frame rate m_pStatsFont->DrawText( 2, 0, D3DCOLOR_ARGB(255,255,255,0), m_strFrameStats ); m_pStatsFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats ); if( m_bShowHelp ) { m_pSmallFont->DrawText( 2, 40, D3DCOLOR_ARGB(255,255,255,255), _T("Keyboard controls:") ); m_pSmallFont->DrawText( 20, 60, D3DCOLOR_ARGB(255,255,255,255), _T("Toggle Vertex Shader\n") _T("Toggle Pixel Shader\n") _T("Help\nChange device\nExit") ); m_pSmallFont->DrawText( 210, 60, D3DCOLOR_ARGB(255,255,255,255), _T("V\n") _T("P\n") _T("F1\nF2\nEsc") ); } else { m_pSmallFont->DrawText( 2, 40, D3DCOLOR_ARGB(255,255,255,255), _T("Press F1 for help") ); } // End the scene. m_pd3dDevice->EndScene(); } return S_OK; } //----------------------------------------------------------------------------- // Name: InitDeviceObjects() // Desc: Initialize scene objects. //----------------------------------------------------------------------------- HRESULT CMyD3DApplication::InitDeviceObjects() { HRESULT hr; hr = D3DXCreateTextureFromFile(m_pd3dDevice, "media\\thingrass0000.tga", &m_pTex); hr = D3DXCreateTextureFromFile(m_pd3dDevice, "media\\grass_ground.tga", &m_pGroundTex); m_pStatsFont->InitDeviceObjects( m_pd3dDevice ); m_pSmallFont->InitDeviceObjects( m_pd3dDevice ); return S_OK; } //----------------------------------------------------------------------------- // Name: RestoreDeviceObjects() // Desc: Initialize scene objects. //----------------------------------------------------------------------------- HRESULT CMyD3DApplication::RestoreDeviceObjects() { m_pStatsFont->RestoreDeviceObjects(); m_pSmallFont->RestoreDeviceObjects(); m_pd3dDevice->SetTexture(0, m_pTex); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE ); m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF, (DWORD)0x000000FF); m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE ); m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); // Set the transform matrices D3DXVECTOR3 vEyePt = D3DXVECTOR3( 0.0f, -20.0f, -10.0f ); D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f, 0.0f, -5.0f ); D3DXVECTOR3 vUpVec = D3DXVECTOR3( 0.0f, 0.0f, -1.0f ); D3DXMatrixIdentity( &m_matWorld ); D3DXMatrixLookAtLH( &m_matView, &vEyePt, &vLookatPt, &vUpVec ); FLOAT fAspect = m_d3dsdBackBuffer.Width / (FLOAT)m_d3dsdBackBuffer.Height; D3DXMatrixPerspectiveFovLH( &m_matProj, D3DX_PI/2, fAspect, 1.0f, 1000.0f ); m_pd3dDevice->SetTransform( D3DTS_WORLD, &m_matWorld ); m_pd3dDevice->SetTransform( D3DTS_VIEW, &m_matView ); m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &m_matProj ); D3DXMATRIX mat; D3DXMatrixIdentity( &m_matInitial); // Create grass quads VB HRESULT hr; hr = m_pd3dDevice->CreateVertexBuffer( m_iNumQuads*6*sizeof(VERTEX), D3DUSAGE_WRITEONLY, D3DFVF_VERTEX, D3DPOOL_MANAGED, &m_pQuadsVB ); if( FAILED(hr) ) return hr; VERTEX* pVertices = NULL; hr = m_pQuadsVB->Lock( 0, m_iNumQuads*6*sizeof(VERTEX), (BYTE**)&pVertices, 0 ); if( FAILED(hr) ) return hr; for( DWORD j=0; j< m_iNumQuads; j++ ) { // Generate each quad at random position, orientation, height D3DXMATRIX matRandom; D3DXMatrixIdentity( &matRandom); float scale = 40.0f; float angle = ((float)rand()/RAND_MAX - 0.5f) * 8.0f; float dx = ((float)rand()/RAND_MAX - 0.5f) * scale*2; float dy = ((float)rand()/RAND_MAX - 0.5f) * scale; float heightScale = ((float)rand()/RAND_MAX - 0.5f) / 2.0f + 1.0f; D3DXMatrixRotationZ( &mat, D3DX_PI * angle); D3DXMatrixMultiply( &matRandom, &matRandom, &mat ); D3DXMatrixTranslation( &mat, dx, dy, 0.0f); D3DXMatrixMultiply( &matRandom, &matRandom, &mat ); D3DXMatrixScaling( &mat, 1.0f, 1.0f, heightScale); D3DXMatrixMultiply( &matRandom, &matRandom, &mat ); // Apply the transformation to each vertex of the quad for( DWORD i=0; i< 6; i++ ) { D3DXVECTOR4 pos, outPos; pos.x = g_Vertices[i].x; pos.y = g_Vertices[i].y; pos.z = g_Vertices[i].z; D3DXVec3Transform(&outPos, &(const struct D3DXVECTOR3)pos, &(CONST D3DXMATRIX)matRandom); DWORD index = j * 6 + i; pVertices[index].x = outPos.x; pVertices[index].y = outPos.y; pVertices[index].z = outPos.z; pVertices[index].tu1 = g_Vertices[i].tu1; pVertices[index].tv1 = g_Vertices[i].tv1; } } m_pQuadsVB->Unlock(); // Create ground quad VB hr = m_pd3dDevice->CreateVertexBuffer( 4*sizeof(VERTEX), D3DUSAGE_WRITEONLY, D3DFVF_VERTEX, D3DPOOL_MANAGED, &m_pGroundQuadVB ); if( FAILED(hr) ) return hr; pVertices = NULL; hr = m_pGroundQuadVB->Lock( 0, 4*sizeof(VERTEX), (BYTE**)&pVertices, 0 ); if( FAILED(hr) ) return hr; for( DWORD i=0; i<4; i++ ) pVertices[i] = g_GroundVertices[i]; m_pGroundQuadVB->Unlock(); // Create vertex shader { LPD3DXBUFFER pCode; // Assemble the vertex shader from the file if( FAILED( hr = D3DXAssembleShaderFromFile( "shaders\\grass.vsh", 0, NULL, &pCode, NULL ) ) ) return hr; // Create the vertex shader hr = m_pd3dDevice->CreateVertexShader( dwVertexDecl, (DWORD*)pCode->GetBufferPointer(), &m_dwVShader, 0 ); pCode->Release(); if( FAILED(hr) ) return hr; } // Create pixel shader { LPD3DXBUFFER pCode; // Assemble the pixel shader from the file if( FAILED( hr = D3DXAssembleShaderFromFile( "shaders\\grass.psh", 0, NULL, &pCode, NULL ) ) ) return hr; // Create the pixel shader hr = m_pd3dDevice->CreatePixelShader( (DWORD*)pCode->GetBufferPointer(), &m_dwPShader); pCode->Release(); if( FAILED(hr) ) return hr; } return S_OK; } //----------------------------------------------------------------------------- // Name: InvalidateDeviceObjects() // Desc: Called when the app is exiting, or the device is being changed, // this function deletes any device dependent objects. //----------------------------------------------------------------------------- HRESULT CMyD3DApplication::InvalidateDeviceObjects() { SAFE_RELEASE( m_pQuadsVB ); SAFE_RELEASE( m_pGroundQuadVB ); m_pd3dDevice->DeleteVertexShader( m_dwVShader ); m_pd3dDevice->DeletePixelShader( m_dwPShader ); m_pStatsFont->InvalidateDeviceObjects(); m_pSmallFont->InvalidateDeviceObjects(); return S_OK; } //----------------------------------------------------------------------------- // Name: DeleteDeviceObjects() // Desc: Called when the app is exiting, or the device is being changed, // this function deletes any device dependent objects. //----------------------------------------------------------------------------- HRESULT CMyD3DApplication::DeleteDeviceObjects() { SAFE_RELEASE( m_pQuadsVB ); SAFE_RELEASE( m_pGroundQuadVB ); m_pd3dDevice->SetTexture(0, NULL); SAFE_RELEASE( m_pTex ); SAFE_RELEASE( m_pGroundTex ); m_pStatsFont->DeleteDeviceObjects(); m_pSmallFont->DeleteDeviceObjects(); return S_OK; } //----------------------------------------------------------------------------- // Name: FinalCleanup() // Desc: Called before the app exits, this function gives the app the chance // to cleanup after itself. //----------------------------------------------------------------------------- HRESULT CMyD3DApplication::FinalCleanup() { SAFE_DELETE( m_pStatsFont ); SAFE_DELETE( m_pSmallFont ); return S_OK; } //----------------------------------------------------------------------------- // Name: MsgProc() // Desc: Message proc function to handle key and menu input //----------------------------------------------------------------------------- LRESULT CMyD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { // Trap context menu if( WM_CONTEXTMENU == uMsg ) return 0; // Perform commands when keys are released if( WM_KEYUP == uMsg ) { switch( wParam ) { case 'V': m_bVertexShader = !m_bVertexShader; break; case 'P': m_bPixelShader = !m_bPixelShader; break; case VK_F1: m_bShowHelp = !m_bShowHelp; break; } } return CD3DApplication::MsgProc( hWnd, uMsg, wParam, lParam ); }