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

  1. //-----------------------------------------------------------------------------
  2. // File: VertexBlend.cpp
  3. //
  4. // Desc: Example code showing how to do a skinning effect, using the vertex
  5. //       blending feature of Direct3D. Normally, Direct3D transforms each
  6. //       vertex through the world matrix. The vertex blending feature,
  7. //       however, uses mulitple world matrices and a per-vertex blend factor
  8. //       to transform each vertex.
  9. //
  10. // Copyright (c) 1997-2000 Microsoft Corporation. All rights reserved.
  11. //-----------------------------------------------------------------------------
  12. #define STRICT
  13. #include <math.h>
  14. #include <stdio.h>
  15. #include <D3DX8.h>
  16. #include "D3DApp.h"
  17. #include "D3DFile.h"
  18. #include "D3DFont.h"
  19. #include "D3DUtil.h"
  20. #include "DXUtil.h"
  21. #include "resource.h"
  22.  
  23.  
  24.  
  25.  
  26. //-----------------------------------------------------------------------------
  27. // Name: struct BLENDVERTEX
  28. // Desc: Custom vertex which includes a blending factor
  29. //-----------------------------------------------------------------------------
  30. struct BLENDVERTEX
  31. {
  32.     D3DXVECTOR3 v;       // Referenced as v0 in the vertex shader
  33.     FLOAT       blend;   // Referenced as v1.x in the vertex shader
  34.     D3DXVECTOR3 n;       // Referenced as v3 in the vertex shader
  35.     FLOAT       tu, tv;  // Referenced as v7 in the vertex shader
  36. };
  37.  
  38. #define D3DFVF_BLENDVERTEX (D3DFVF_XYZB1|D3DFVF_NORMAL|D3DFVF_TEX1)
  39.  
  40.  
  41.  
  42.  
  43. //-----------------------------------------------------------------------------
  44. // Name: class CMyD3DApplication
  45. // Desc: Application class. The base class (CD3DApplication) provides the 
  46. //       generic functionality needed in all Direct3D samples. CMyD3DApplication 
  47. //       adds functionality specific to this sample program.
  48. //-----------------------------------------------------------------------------
  49. class CMyD3DApplication : public CD3DApplication
  50. {
  51.     CD3DFont*    m_pFont;
  52.     CD3DMesh*    m_pObject;           // Object to use for vertex blending
  53.     DWORD        m_dwNumVertices;
  54.     DWORD        m_dwNumFaces;
  55.     LPDIRECT3DVERTEXBUFFER8 m_pVB;    
  56.     LPDIRECT3DINDEXBUFFER8  m_pIB;
  57.  
  58.     D3DXMATRIX   m_matUpperArm;       // Vertex blending matrices
  59.     D3DXMATRIX   m_matLowerArm;
  60.  
  61.     DWORD        m_dwVertexShader;    // Vertex shader
  62.     BOOL         m_bUseVertexShader;
  63.  
  64. protected:
  65.     HRESULT OneTimeSceneInit();
  66.     HRESULT InitDeviceObjects();
  67.     HRESULT RestoreDeviceObjects();
  68.     HRESULT InvalidateDeviceObjects();
  69.     HRESULT DeleteDeviceObjects();
  70.     HRESULT Render();
  71.     HRESULT FrameMove();
  72.     HRESULT FinalCleanup();
  73.     HRESULT ConfirmDevice( D3DCAPS8*, DWORD, D3DFORMAT );
  74.     LRESULT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  75.  
  76. public:
  77.     CMyD3DApplication();
  78. };
  79.  
  80.  
  81.  
  82.  
  83. //-----------------------------------------------------------------------------
  84. // Name: WinMain()
  85. // Desc: Entry point to the program. Initializes everything, and goes into a
  86. //       message-processing loop. Idle time is used to render the scene.
  87. //-----------------------------------------------------------------------------
  88. INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
  89. {
  90.     CMyD3DApplication d3dApp;
  91.     
  92.     if( FAILED( d3dApp.Create( hInst ) ) )
  93.         return 0;
  94.  
  95.     return d3dApp.Run();
  96. }
  97.  
  98.  
  99.  
  100.  
  101. //-----------------------------------------------------------------------------
  102. // Name: CMyD3DApplication()
  103. // Desc: Application constructor. Sets attributes for the app.
  104. //-----------------------------------------------------------------------------
  105. CMyD3DApplication::CMyD3DApplication()
  106. {
  107.     m_strWindowTitle    = _T("VertexBlend: Surface Skinning Example");
  108.     m_bUseDepthBuffer   = TRUE;
  109.  
  110.     m_pFont             = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD );
  111.     m_pObject           = new CD3DMesh();
  112.     m_pVB               = NULL;
  113.     m_pIB               = NULL;
  114.     m_dwVertexShader    = 0L;
  115.     m_bUseVertexShader  = FALSE;
  116. }
  117.  
  118.  
  119.  
  120.  
  121. //-----------------------------------------------------------------------------
  122. // Name: OneTimeSceneInit()
  123. // Desc: Called during initial app startup, this function performs all the
  124. //       permanent initialization.
  125. //-----------------------------------------------------------------------------
  126. HRESULT CMyD3DApplication::OneTimeSceneInit()
  127. {
  128.     return S_OK;
  129. }
  130.  
  131.  
  132.  
  133.  
  134. //-----------------------------------------------------------------------------
  135. // Name: FrameMove()
  136. // Desc: Called once per frame, the call is the entry point for animating
  137. //       the scene.
  138. //-----------------------------------------------------------------------------
  139. HRESULT CMyD3DApplication::FrameMove()
  140. {
  141.     // Set the vertex blending matrices for this frame
  142.     D3DXVECTOR3 vAxis( 2+sinf(m_fTime*3.1f), 2+sinf(m_fTime*3.3f), sinf(m_fTime*3.5f) ); 
  143.     D3DXMatrixRotationAxis( &m_matLowerArm, &vAxis, sinf(3*m_fTime) );
  144.     D3DXMatrixIdentity( &m_matUpperArm );
  145.  
  146.     // Set the vertex shader constants. Note: outside of the blend matrices,
  147.     // most of these values don't change, so don't need to really be set every
  148.     // frame. It's just done here for clarity
  149.     {
  150.         // Some basic constants
  151.         D3DXVECTOR4 vZero(0,0,0,0);
  152.         D3DXVECTOR4 vOne(1,1,1,1);
  153.  
  154.         // Lighting vector (normalized) and material colors. (Use red light
  155.         // to show difference from non-vertex shader case.)
  156.         D3DXVECTOR4 vLight( 0.5f, 1.0f, -1.0f, 0.0f );
  157.         D3DXVec4Normalize( &vLight, &vLight );
  158.         FLOAT       fDiffuse[] = { 1.00f, 1.00f, 0.00f, 0.00f };
  159.         FLOAT       fAmbient[] = { 0.25f, 0.25f, 0.25f, 0.25f };
  160.  
  161.         // Vertex shader operations use transposed matrices
  162.         D3DXMATRIX matWorld0Transpose, matWorld1Transpose;
  163.         D3DXMATRIX matView, matProj, matViewProj, matViewProjTranspose;
  164.         m_pd3dDevice->GetTransform( D3DTS_VIEW,       &matView );
  165.         m_pd3dDevice->GetTransform( D3DTS_PROJECTION, &matProj );
  166.         D3DXMatrixMultiply( &matViewProj, &matView, &matProj );
  167.         D3DXMatrixTranspose( &matWorld0Transpose, &m_matUpperArm );
  168.         D3DXMatrixTranspose( &matWorld1Transpose, &m_matLowerArm );
  169.         D3DXMatrixTranspose( &matViewProjTranspose, &matViewProj );
  170.  
  171.         // Set the vertex shader constants
  172.         m_pd3dDevice->SetVertexShaderConstant(  0, &vZero,    1 );
  173.         m_pd3dDevice->SetVertexShaderConstant(  1, &vOne,     1 );
  174.         m_pd3dDevice->SetVertexShaderConstant(  4, &matWorld0Transpose,   4 );
  175.         m_pd3dDevice->SetVertexShaderConstant(  8, &matWorld1Transpose,   4 );
  176.         m_pd3dDevice->SetVertexShaderConstant( 12, &matViewProjTranspose, 4 );
  177.         m_pd3dDevice->SetVertexShaderConstant( 20, &vLight,   1 );
  178.         m_pd3dDevice->SetVertexShaderConstant( 21, &fDiffuse, 1 );
  179.         m_pd3dDevice->SetVertexShaderConstant( 22, &fAmbient, 1 );
  180.     }
  181.  
  182.     return S_OK;
  183. }
  184.  
  185.  
  186.  
  187.  
  188. //-----------------------------------------------------------------------------
  189. // Name: Render()
  190. // Desc: Called once per frame, the call is the entry point for 3d
  191. //       rendering. This function sets up render states, clears the
  192. //       viewport, and renders the scene.
  193. //-----------------------------------------------------------------------------
  194. HRESULT CMyD3DApplication::Render()
  195. {
  196.     // Clear the backbuffer
  197.     m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 
  198.                          0x000000ff, 1.0f, 0L );
  199.  
  200.     // Begin the scene
  201.     if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
  202.     {
  203.         if( m_bUseVertexShader )        
  204.         {
  205.             m_pd3dDevice->SetVertexShader( m_dwVertexShader );
  206.             m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(BLENDVERTEX) );
  207.             m_pd3dDevice->SetIndices( m_pIB, 0 );
  208.             m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, m_dwNumVertices,
  209.                                                 0, m_dwNumFaces );
  210.         }
  211.         else
  212.         {
  213.             // Enable vertex blending using API
  214.             m_pd3dDevice->SetTransform( D3DTS_WORLD,  &m_matUpperArm );
  215.             m_pd3dDevice->SetTransform( D3DTS_WORLD1, &m_matLowerArm );
  216.             m_pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND, D3DVBF_1WEIGHTS );
  217.  
  218.             // Display the object
  219.             m_pObject->Render( m_pd3dDevice );
  220.         }
  221.  
  222.         // Output statistics
  223.         m_pFont->DrawText( 2,  0, D3DCOLOR_ARGB(255,255,255,0), m_strFrameStats );
  224.         m_pFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats );
  225.  
  226.         if( m_bUseVertexShader )
  227.             m_pFont->DrawText( 2, 40, D3DCOLOR_ARGB(255,255,255,255), _T("Using vertex shader") );
  228.         else
  229.             m_pFont->DrawText( 2, 40, D3DCOLOR_ARGB(255,255,255,255), _T("Using D3DRS_VERTEXBLEND") );
  230.  
  231.         // End the scene.
  232.         m_pd3dDevice->EndScene();
  233.     }
  234.  
  235.     return S_OK;
  236. }
  237.  
  238.  
  239.  
  240.  
  241. //-----------------------------------------------------------------------------
  242. // Name: InitDeviceObjects()
  243. // Desc: Initialize scene objects.
  244. //-----------------------------------------------------------------------------
  245. HRESULT CMyD3DApplication::InitDeviceObjects()
  246. {
  247.     // Initialize the font's internal textures
  248.     m_pFont->InitDeviceObjects( m_pd3dDevice );
  249.  
  250.     // Load an object to render
  251.     if( FAILED( m_pObject->Create( m_pd3dDevice, _T("mslogo.x") ) ) )
  252.         return D3DAPPERR_MEDIANOTFOUND;
  253.  
  254.     if( ( ( m_dwCreateFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING ) ||
  255.           ( m_dwCreateFlags & D3DCREATE_MIXED_VERTEXPROCESSING ) ) &&
  256.         m_d3dCaps.VertexShaderVersion < D3DVS_VERSION(1,0) )
  257.     {
  258.         // No VS available, so don't try to use it or allow user to
  259.         // switch to it
  260.         m_bUseVertexShader = FALSE;
  261.         EnableMenuItem( GetMenu( m_hWnd ), IDM_USEVERTEXSHADER, MF_GRAYED );
  262.     }
  263.     else if( m_d3dCaps.MaxVertexBlendMatrices < 2 )
  264.     {
  265.         // No blend matrices available, so don't try to use them or 
  266.         // allow user to switch to them
  267.         m_bUseVertexShader = TRUE;
  268.         EnableMenuItem( GetMenu( m_hWnd ), IDM_USEVERTEXSHADER, MF_GRAYED );
  269.     }
  270.     else
  271.     {
  272.         // Both techniques available, so default to blend matrices and 
  273.         // allow the user to switch techniques
  274.         m_bUseVertexShader = FALSE;
  275.         EnableMenuItem( GetMenu( m_hWnd ), IDM_USEVERTEXSHADER, MF_ENABLED );
  276.     }
  277.  
  278.     // Set a custom FVF for the mesh
  279.     m_pObject->SetFVF( m_pd3dDevice, D3DFVF_BLENDVERTEX );
  280.  
  281.     // Add blending weights to the mesh
  282.     {
  283.         // Gain acces to the mesh's vertices
  284.         LPDIRECT3DVERTEXBUFFER8 pVB;
  285.         BLENDVERTEX* pVertices;
  286.         DWORD        dwNumVertices = m_pObject->GetSysMemMesh()->GetNumVertices();
  287.         m_pObject->GetSysMemMesh()->GetVertexBuffer( &pVB );
  288.         pVB->Lock( 0, 0, (BYTE**)&pVertices, 0 );
  289.  
  290.         // Calculate the min/max z values for all the vertices
  291.         FLOAT fMinX =  1e10f;
  292.         FLOAT fMaxX = -1e10f;
  293.  
  294.         for( DWORD i=0; i<dwNumVertices; i++ )
  295.         {
  296.             if( pVertices[i].v.x < fMinX ) 
  297.                 fMinX = pVertices[i].v.x;
  298.             if( pVertices[i].v.x > fMaxX ) 
  299.                 fMaxX = pVertices[i].v.x;
  300.         }
  301.  
  302.         for( i=0; i<dwNumVertices; i++ )
  303.         {
  304.             // Set the blend factors for the vertices
  305.             FLOAT a = ( pVertices[i].v.x - fMinX ) / ( fMaxX - fMinX );
  306.             pVertices[i].blend = 1.0f-sinf(a*D3DX_PI*1.0f);
  307.         }
  308.  
  309.         // Done with the mesh's vertex buffer data
  310.         pVB->Unlock();
  311.         pVB->Release();
  312.     }
  313.  
  314.     return S_OK;
  315. }
  316.  
  317.  
  318.  
  319.  
  320. //-----------------------------------------------------------------------------
  321. // Name: RestoreDeviceObjects()
  322. // Desc: Restore device-memory objects and state after a device is created or
  323. //       resized.
  324. //-----------------------------------------------------------------------------
  325. HRESULT CMyD3DApplication::RestoreDeviceObjects()
  326. {
  327.     m_pFont->RestoreDeviceObjects();
  328.  
  329.     // Restore mesh's local memory objects
  330.     m_pObject->RestoreDeviceObjects( m_pd3dDevice );
  331.  
  332.     // Get access to the mesh vertex and index buffers
  333.     m_pObject->GetLocalMesh()->GetVertexBuffer( &m_pVB );
  334.     m_pObject->GetLocalMesh()->GetIndexBuffer( &m_pIB );
  335.     m_dwNumVertices = m_pObject->GetLocalMesh()->GetNumVertices();
  336.     m_dwNumFaces    = m_pObject->GetLocalMesh()->GetNumFaces();
  337.  
  338.     if( ( m_dwCreateFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING ) ||
  339.         m_d3dCaps.VertexShaderVersion >= D3DVS_VERSION(1,0) )
  340.     {
  341.         // Setup the vertex declaration
  342.         DWORD adwDecl[50];
  343.         D3DXDeclaratorFromFVF( D3DFVF_BLENDVERTEX, adwDecl );
  344.  
  345.         // Create vertex shader from a file
  346.         if( FAILED( D3DUtil_CreateVertexShader( m_pd3dDevice, 
  347.                                                 _T("Blend.vsh"), adwDecl,
  348.                                                 &m_dwVertexShader ) ) )
  349.         {
  350.             return E_FAIL;
  351.         }
  352.     }
  353.     // Set miscellaneous render states
  354.     m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
  355.     m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x00404040 );
  356.  
  357.     // Set the projection matrix
  358.     D3DXMATRIX matProj;
  359.     FLOAT fAspect = m_d3dsdBackBuffer.Width / (FLOAT)m_d3dsdBackBuffer.Height;
  360.     D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect, 1.0f, 10000.0f );
  361.     m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
  362.  
  363.     // Set the app view matrix for normal viewing
  364.     D3DXVECTOR3 vEyePt    = D3DXVECTOR3( 0.0f,-5.0f,-10.0f );
  365.     D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f, 0.0f,  0.0f );
  366.     D3DXVECTOR3 vUpVec    = D3DXVECTOR3( 0.0f, 1.0f,  0.0f );
  367.     D3DXMATRIX matView;
  368.     D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
  369.     m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
  370.  
  371.     // Create a directional light. (Use yellow light to distinguish from
  372.     // vertex shader case.)
  373.     D3DLIGHT8 light;
  374.     D3DUtil_InitLight( light, D3DLIGHT_DIRECTIONAL, -0.5f, -1.0f, 1.0f );
  375.     light.Diffuse.r = 1.0f;
  376.     light.Diffuse.g = 1.0f;
  377.     light.Diffuse.b = 0.0f;
  378.     m_pd3dDevice->SetLight( 0, &light );
  379.     m_pd3dDevice->LightEnable( 0, TRUE );
  380.     m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
  381.  
  382.     return S_OK;
  383. }
  384.  
  385.  
  386.  
  387.  
  388. //-----------------------------------------------------------------------------
  389. // Name: InvalidateDeviceObjects()
  390. // Desc: Called when the device-dependent objects are about to be lost.
  391. //-----------------------------------------------------------------------------
  392. HRESULT CMyD3DApplication::InvalidateDeviceObjects()
  393. {
  394.     m_pFont->InvalidateDeviceObjects();
  395.     m_pObject->InvalidateDeviceObjects();
  396.  
  397.     if( m_dwVertexShader != 0 )
  398.         m_pd3dDevice->DeleteVertexShader( m_dwVertexShader );
  399.  
  400.     SAFE_RELEASE( m_pVB );
  401.     SAFE_RELEASE( m_pIB );
  402.  
  403.     return S_OK;
  404. }
  405.  
  406.  
  407.  
  408.  
  409. //-----------------------------------------------------------------------------
  410. // Name: DeleteDeviceObjects()
  411. // Desc: Called when the app is exiting, or the device is being changed,
  412. //       this function deletes any device dependent objects.
  413. //-----------------------------------------------------------------------------
  414. HRESULT CMyD3DApplication::DeleteDeviceObjects()
  415. {
  416.     m_pFont->DeleteDeviceObjects();
  417.     m_pObject->Destroy();
  418.  
  419.     return S_OK;
  420. }
  421.  
  422.  
  423.  
  424.  
  425. //-----------------------------------------------------------------------------
  426. // Name: FinalCleanup()
  427. // Desc: Called before the app exits, this function gives the app the chance
  428. //       to cleanup after itself.
  429. //-----------------------------------------------------------------------------
  430. HRESULT CMyD3DApplication::FinalCleanup()
  431. {
  432.     SAFE_DELETE( m_pFont );
  433.     SAFE_DELETE( m_pObject );
  434.  
  435.     return S_OK;
  436. }
  437.  
  438.  
  439.  
  440.  
  441. //-----------------------------------------------------------------------------
  442. // Name: ConfirmDevice()
  443. // Desc: Called during device intialization, this code checks the device
  444. //       for some minimum set of capabilities
  445. //-----------------------------------------------------------------------------
  446. HRESULT CMyD3DApplication::ConfirmDevice( D3DCAPS8* pCaps, DWORD dwBehavior, 
  447.                                           D3DFORMAT Format )
  448. {
  449.     if( dwBehavior & D3DCREATE_PUREDEVICE )
  450.         return E_FAIL; // GetTransform doesn't work on PUREDEVICE
  451.  
  452.     // Check that the device supports at least one of the two techniques
  453.     // used in this sample: either a vertex shader, or at least two blend
  454.     // matrices and a directional light.
  455.  
  456.     if( (dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING ) ||
  457.         (dwBehavior & D3DCREATE_MIXED_VERTEXPROCESSING ) )
  458.     {
  459.         if( pCaps->VertexShaderVersion >= D3DVS_VERSION(1,0) )
  460.             return S_OK;
  461.     }
  462.     else
  463.     {
  464.         // Software vertex processing always supports vertex shaders
  465.         return S_OK;
  466.     }
  467.  
  468.     // Check that the device can blend vertices with at least two matrices
  469.     // (Software can always do up to 4 blend matrices)
  470.     if( pCaps->MaxVertexBlendMatrices < 2 )
  471.         return E_FAIL;
  472.  
  473.     // If this is a TnL device, make sure it supports directional lights
  474.     if( (dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING ) ||
  475.         (dwBehavior & D3DCREATE_MIXED_VERTEXPROCESSING ) )
  476.     {
  477.         if( !(pCaps->VertexProcessingCaps & D3DVTXPCAPS_DIRECTIONALLIGHTS ) )
  478.             return E_FAIL;
  479.     }
  480.  
  481.     return S_OK;
  482. }
  483.  
  484.  
  485.  
  486.  
  487. //-----------------------------------------------------------------------------
  488. // Name: MsgProc()
  489. // Desc: Message proc function to handle key and menu input
  490. //-----------------------------------------------------------------------------
  491. LRESULT CMyD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
  492.                                     LPARAM lParam )
  493. {
  494.     // Handle menu commands
  495.     if( WM_COMMAND == uMsg )
  496.     {
  497.         switch( LOWORD(wParam) )
  498.         {
  499.             case IDM_USEVERTEXSHADER:
  500.                 m_bUseVertexShader = !m_bUseVertexShader;
  501.                 CheckMenuItem( GetMenu(hWnd), IDM_USEVERTEXSHADER,
  502.                                m_bUseVertexShader ? MF_CHECKED : MF_UNCHECKED );
  503.                 break;
  504.         }
  505.     }
  506.  
  507.     // Pass remaining messages to default handler
  508.     return CD3DApplication::MsgProc( hWnd, uMsg, wParam, lParam );
  509. }
  510.  
  511.  
  512.  
  513.