d3dutil.cpp
上传用户:sycq158
上传日期:2008-10-22
资源大小:15361k
文件大小:43k
源码类别:

游戏

开发平台:

Visual C++

  1. //-----------------------------------------------------------------------------
  2. // File: D3DUtil.cpp
  3. //
  4. // Desc: Shortcut macros and functions for using DX objects
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved
  7. //-----------------------------------------------------------------------------
  8. #include "dxstdafx.h"
  9. #ifndef WM_MOUSEWHEEL  
  10. #define WM_MOUSEWHEEL                   0x020A
  11. #endif
  12. //-----------------------------------------------------------------------------
  13. // Name: D3DUtil_GetCubeMapViewMatrix()
  14. // Desc: Returns a view matrix for rendering to a face of a cubemap.
  15. //-----------------------------------------------------------------------------
  16. D3DXMATRIX D3DUtil_GetCubeMapViewMatrix( DWORD dwFace )
  17. {
  18.     D3DXVECTOR3 vEyePt   = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  19.     D3DXVECTOR3 vLookDir;
  20.     D3DXVECTOR3 vUpDir;
  21.     switch( dwFace )
  22.     {
  23.         case D3DCUBEMAP_FACE_POSITIVE_X:
  24.             vLookDir = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
  25.             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  26.             break;
  27.         case D3DCUBEMAP_FACE_NEGATIVE_X:
  28.             vLookDir = D3DXVECTOR3(-1.0f, 0.0f, 0.0f );
  29.             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  30.             break;
  31.         case D3DCUBEMAP_FACE_POSITIVE_Y:
  32.             vLookDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  33.             vUpDir   = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
  34.             break;
  35.         case D3DCUBEMAP_FACE_NEGATIVE_Y:
  36.             vLookDir = D3DXVECTOR3( 0.0f,-1.0f, 0.0f );
  37.             vUpDir   = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
  38.             break;
  39.         case D3DCUBEMAP_FACE_POSITIVE_Z:
  40.             vLookDir = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
  41.             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  42.             break;
  43.         case D3DCUBEMAP_FACE_NEGATIVE_Z:
  44.             vLookDir = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
  45.             vUpDir   = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  46.             break;
  47.     }
  48.     // Set the view transform for this cubemap surface
  49.     D3DXMATRIXA16 mView;
  50.     D3DXMatrixLookAtLH( &mView, &vEyePt, &vLookDir, &vUpDir );
  51.     return mView;
  52. }
  53. //-----------------------------------------------------------------------------
  54. // Name: D3DUtil_GetRotationFromCursor()
  55. // Desc: Returns a quaternion for the rotation implied by the window's cursor
  56. //       position.
  57. //-----------------------------------------------------------------------------
  58. D3DXQUATERNION D3DUtil_GetRotationFromCursor( HWND hWnd,
  59.                                               FLOAT fTrackBallRadius )
  60. {
  61.     POINT pt;
  62.     RECT  rc;
  63.     GetCursorPos( &pt );
  64.     GetClientRect( hWnd, &rc );
  65.     ScreenToClient( hWnd, &pt );
  66.     FLOAT sx = ( ( ( 2.0f * pt.x ) / (rc.right-rc.left) ) - 1 );
  67.     FLOAT sy = ( ( ( 2.0f * pt.y ) / (rc.bottom-rc.top) ) - 1 );
  68.     FLOAT sz;
  69.     if( sx == 0.0f && sy == 0.0f )
  70.         return D3DXQUATERNION( 0.0f, 0.0f, 0.0f, 1.0f );
  71.     FLOAT d2 = sqrtf( sx*sx + sy*sy );
  72.     if( d2 < fTrackBallRadius * 0.70710678118654752440 ) // Inside sphere
  73.         sz = sqrtf( fTrackBallRadius*fTrackBallRadius - d2*d2 );
  74.     else                                                 // On hyperbola
  75.         sz = (fTrackBallRadius*fTrackBallRadius) / (2.0f*d2);
  76.     // Get two points on trackball's sphere
  77.     D3DXVECTOR3 p1( sx, sy, sz );
  78.     D3DXVECTOR3 p2( 0.0f, 0.0f, fTrackBallRadius );
  79.     // Get axis of rotation, which is cross product of p1 and p2
  80.     D3DXVECTOR3 vAxis;
  81.     D3DXVec3Cross( &vAxis, &p1, &p2);
  82.     // Calculate angle for the rotation about that axis
  83.     D3DXVECTOR3 vecDiff = p2-p1;
  84.     FLOAT t = D3DXVec3Length( &vecDiff ) / ( 2.0f*fTrackBallRadius );
  85.     if( t > +1.0f) t = +1.0f;
  86.     if( t < -1.0f) t = -1.0f;
  87.     FLOAT fAngle = 2.0f * asinf( t );
  88.     // Convert axis to quaternion
  89.     D3DXQUATERNION quat;
  90.     D3DXQuaternionRotationAxis( &quat, &vAxis, fAngle );
  91.     return quat;
  92. }
  93. //-----------------------------------------------------------------------------
  94. // Name: D3DUtil_SetDeviceCursor
  95. // Desc: Gives the D3D device a cursor with image and hotspot from hCursor.
  96. //-----------------------------------------------------------------------------
  97. HRESULT D3DUtil_SetDeviceCursor( LPDIRECT3DDEVICE9 pd3dDevice, HCURSOR hCursor,
  98.                                  BOOL bAddWatermark )
  99. {
  100.     HRESULT hr = E_FAIL;
  101.     ICONINFO iconinfo;
  102.     BOOL bBWCursor;
  103.     LPDIRECT3DSURFACE9 pCursorSurface = NULL;
  104.     HDC hdcColor = NULL;
  105.     HDC hdcMask = NULL;
  106.     HDC hdcScreen = NULL;
  107.     BITMAP bm;
  108.     DWORD dwWidth;
  109.     DWORD dwHeightSrc;
  110.     DWORD dwHeightDest;
  111.     COLORREF crColor;
  112.     COLORREF crMask;
  113.     UINT x;
  114.     UINT y;
  115.     BITMAPINFO bmi;
  116.     COLORREF* pcrArrayColor = NULL;
  117.     COLORREF* pcrArrayMask = NULL;
  118.     DWORD* pBitmap;
  119.     HGDIOBJ hgdiobjOld;
  120.     ZeroMemory( &iconinfo, sizeof(iconinfo) );
  121.     if( !GetIconInfo( hCursor, &iconinfo ) )
  122.         goto End;
  123.     if (0 == GetObject((HGDIOBJ)iconinfo.hbmMask, sizeof(BITMAP), (LPVOID)&bm))
  124.         goto End;
  125.     dwWidth = bm.bmWidth;
  126.     dwHeightSrc = bm.bmHeight;
  127.     if( iconinfo.hbmColor == NULL )
  128.     {
  129.         bBWCursor = TRUE;
  130.         dwHeightDest = dwHeightSrc / 2;
  131.     }
  132.     else 
  133.     {
  134.         bBWCursor = FALSE;
  135.         dwHeightDest = dwHeightSrc;
  136.     }
  137.     // Create a surface for the fullscreen cursor
  138.     if( FAILED( hr = pd3dDevice->CreateOffscreenPlainSurface( dwWidth, dwHeightDest, 
  139.         D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pCursorSurface, NULL ) ) )
  140.     {
  141.         goto End;
  142.     }
  143.     pcrArrayMask = new DWORD[dwWidth * dwHeightSrc];
  144.     ZeroMemory(&bmi, sizeof(bmi));
  145.     bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
  146.     bmi.bmiHeader.biWidth = dwWidth;
  147.     bmi.bmiHeader.biHeight = dwHeightSrc;
  148.     bmi.bmiHeader.biPlanes = 1;
  149.     bmi.bmiHeader.biBitCount = 32;
  150.     bmi.bmiHeader.biCompression = BI_RGB;
  151.     hdcScreen = GetDC( NULL );
  152.     hdcMask = CreateCompatibleDC( hdcScreen );
  153.     if( hdcMask == NULL )
  154.     {
  155.         hr = E_FAIL;
  156.         goto End;
  157.     }
  158.     hgdiobjOld = SelectObject(hdcMask, iconinfo.hbmMask);
  159.     GetDIBits(hdcMask, iconinfo.hbmMask, 0, dwHeightSrc, 
  160.         pcrArrayMask, &bmi, DIB_RGB_COLORS);
  161.     SelectObject(hdcMask, hgdiobjOld);
  162.     if (!bBWCursor)
  163.     {
  164.         pcrArrayColor = new DWORD[dwWidth * dwHeightDest];
  165.         hdcColor = CreateCompatibleDC( hdcScreen );
  166.         if( hdcColor == NULL )
  167.         {
  168.             hr = E_FAIL;
  169.             goto End;
  170.         }
  171.         SelectObject(hdcColor, iconinfo.hbmColor);
  172.         GetDIBits(hdcColor, iconinfo.hbmColor, 0, dwHeightDest, 
  173.             pcrArrayColor, &bmi, DIB_RGB_COLORS);
  174.     }
  175.     // Transfer cursor image into the surface
  176.     D3DLOCKED_RECT lr;
  177.     pCursorSurface->LockRect( &lr, NULL, 0 );
  178.     pBitmap = (DWORD*)lr.pBits;
  179.     for( y = 0; y < dwHeightDest; y++ )
  180.     {
  181.         for( x = 0; x < dwWidth; x++ )
  182.         {
  183.             if (bBWCursor)
  184.             {
  185.                 crColor = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x];
  186.                 crMask = pcrArrayMask[dwWidth*(dwHeightSrc-1-y) + x];
  187.             }
  188.             else
  189.             {
  190.                 crColor = pcrArrayColor[dwWidth*(dwHeightDest-1-y) + x];
  191.                 crMask = pcrArrayMask[dwWidth*(dwHeightDest-1-y) + x];
  192.             }
  193.             if (crMask == 0)
  194.                 pBitmap[dwWidth*y + x] = 0xff000000 | crColor;
  195.             else
  196.                 pBitmap[dwWidth*y + x] = 0x00000000;
  197.             // It may be helpful to make the D3D cursor look slightly 
  198.             // different from the Windows cursor so you can distinguish 
  199.             // between the two when developing/testing code.  When
  200.             // bAddWatermark is TRUE, the following code adds some
  201.             // small grey "D3D" characters to the upper-left corner of
  202.             // the D3D cursor image.
  203.             if( bAddWatermark && x < 12 && y < 5 )
  204.             {
  205.                 // 11.. 11.. 11.. .... CCC0
  206.                 // 1.1. ..1. 1.1. .... A2A0
  207.                 // 1.1. .1.. 1.1. .... A4A0
  208.                 // 1.1. ..1. 1.1. .... A2A0
  209.                 // 11.. 11.. 11.. .... CCC0
  210.                 const WORD wMask[5] = { 0xccc0, 0xa2a0, 0xa4a0, 0xa2a0, 0xccc0 };
  211.                 if( wMask[y] & (1 << (15 - x)) )
  212.                 {
  213.                     pBitmap[dwWidth*y + x] |= 0xff808080;
  214.                 }
  215.             }
  216.         }
  217.     }
  218.     pCursorSurface->UnlockRect();
  219.     // Set the device cursor
  220.     if( FAILED( hr = pd3dDevice->SetCursorProperties( iconinfo.xHotspot, 
  221.         iconinfo.yHotspot, pCursorSurface ) ) )
  222.     {
  223.         goto End;
  224.     }
  225.     hr = S_OK;
  226. End:
  227.     if( iconinfo.hbmMask != NULL )
  228.         DeleteObject( iconinfo.hbmMask );
  229.     if( iconinfo.hbmColor != NULL )
  230.         DeleteObject( iconinfo.hbmColor );
  231.     if( hdcScreen != NULL )
  232.         ReleaseDC( NULL, hdcScreen );
  233.     if( hdcColor != NULL )
  234.         DeleteDC( hdcColor );
  235.     if( hdcMask != NULL )
  236.         DeleteDC( hdcMask );
  237.     SAFE_DELETE_ARRAY( pcrArrayColor );
  238.     SAFE_DELETE_ARRAY( pcrArrayMask );
  239.     SAFE_RELEASE( pCursorSurface );
  240.     return hr;
  241. }
  242. //-----------------------------------------------------------------------------
  243. // Name: D3DFormatToString
  244. // Desc: Returns the string for the given D3DFORMAT.
  245. //-----------------------------------------------------------------------------
  246. LPCTSTR D3DUtil_D3DFormatToString( D3DFORMAT format, bool bWithPrefix )
  247. {
  248.     TCHAR* pstr = NULL;
  249.     switch( format )
  250.     {
  251.     case D3DFMT_UNKNOWN:         pstr = TEXT("D3DFMT_UNKNOWN"); break;
  252.     case D3DFMT_R8G8B8:          pstr = TEXT("D3DFMT_R8G8B8"); break;
  253.     case D3DFMT_A8R8G8B8:        pstr = TEXT("D3DFMT_A8R8G8B8"); break;
  254.     case D3DFMT_X8R8G8B8:        pstr = TEXT("D3DFMT_X8R8G8B8"); break;
  255.     case D3DFMT_R5G6B5:          pstr = TEXT("D3DFMT_R5G6B5"); break;
  256.     case D3DFMT_X1R5G5B5:        pstr = TEXT("D3DFMT_X1R5G5B5"); break;
  257.     case D3DFMT_A1R5G5B5:        pstr = TEXT("D3DFMT_A1R5G5B5"); break;
  258.     case D3DFMT_A4R4G4B4:        pstr = TEXT("D3DFMT_A4R4G4B4"); break;
  259.     case D3DFMT_R3G3B2:          pstr = TEXT("D3DFMT_R3G3B2"); break;
  260.     case D3DFMT_A8:              pstr = TEXT("D3DFMT_A8"); break;
  261.     case D3DFMT_A8R3G3B2:        pstr = TEXT("D3DFMT_A8R3G3B2"); break;
  262.     case D3DFMT_X4R4G4B4:        pstr = TEXT("D3DFMT_X4R4G4B4"); break;
  263.     case D3DFMT_A2B10G10R10:     pstr = TEXT("D3DFMT_A2B10G10R10"); break;
  264.     case D3DFMT_A8B8G8R8:        pstr = TEXT("D3DFMT_A8B8G8R8"); break;
  265.     case D3DFMT_X8B8G8R8:        pstr = TEXT("D3DFMT_X8B8G8R8"); break;
  266.     case D3DFMT_G16R16:          pstr = TEXT("D3DFMT_G16R16"); break;
  267.     case D3DFMT_A2R10G10B10:     pstr = TEXT("D3DFMT_A2R10G10B10"); break;
  268.     case D3DFMT_A16B16G16R16:    pstr = TEXT("D3DFMT_A16B16G16R16"); break;
  269.     case D3DFMT_A8P8:            pstr = TEXT("D3DFMT_A8P8"); break;
  270.     case D3DFMT_P8:              pstr = TEXT("D3DFMT_P8"); break;
  271.     case D3DFMT_L8:              pstr = TEXT("D3DFMT_L8"); break;
  272.     case D3DFMT_A8L8:            pstr = TEXT("D3DFMT_A8L8"); break;
  273.     case D3DFMT_A4L4:            pstr = TEXT("D3DFMT_A4L4"); break;
  274.     case D3DFMT_V8U8:            pstr = TEXT("D3DFMT_V8U8"); break;
  275.     case D3DFMT_L6V5U5:          pstr = TEXT("D3DFMT_L6V5U5"); break;
  276.     case D3DFMT_X8L8V8U8:        pstr = TEXT("D3DFMT_X8L8V8U8"); break;
  277.     case D3DFMT_Q8W8V8U8:        pstr = TEXT("D3DFMT_Q8W8V8U8"); break;
  278.     case D3DFMT_V16U16:          pstr = TEXT("D3DFMT_V16U16"); break;
  279.     case D3DFMT_A2W10V10U10:     pstr = TEXT("D3DFMT_A2W10V10U10"); break;
  280.     case D3DFMT_UYVY:            pstr = TEXT("D3DFMT_UYVY"); break;
  281.     case D3DFMT_YUY2:            pstr = TEXT("D3DFMT_YUY2"); break;
  282.     case D3DFMT_DXT1:            pstr = TEXT("D3DFMT_DXT1"); break;
  283.     case D3DFMT_DXT2:            pstr = TEXT("D3DFMT_DXT2"); break;
  284.     case D3DFMT_DXT3:            pstr = TEXT("D3DFMT_DXT3"); break;
  285.     case D3DFMT_DXT4:            pstr = TEXT("D3DFMT_DXT4"); break;
  286.     case D3DFMT_DXT5:            pstr = TEXT("D3DFMT_DXT5"); break;
  287.     case D3DFMT_D16_LOCKABLE:    pstr = TEXT("D3DFMT_D16_LOCKABLE"); break;
  288.     case D3DFMT_D32:             pstr = TEXT("D3DFMT_D32"); break;
  289.     case D3DFMT_D15S1:           pstr = TEXT("D3DFMT_D15S1"); break;
  290.     case D3DFMT_D24S8:           pstr = TEXT("D3DFMT_D24S8"); break;
  291.     case D3DFMT_D24X8:           pstr = TEXT("D3DFMT_D24X8"); break;
  292.     case D3DFMT_D24X4S4:         pstr = TEXT("D3DFMT_D24X4S4"); break;
  293.     case D3DFMT_D16:             pstr = TEXT("D3DFMT_D16"); break;
  294.     case D3DFMT_L16:             pstr = TEXT("D3DFMT_L16"); break;
  295.     case D3DFMT_VERTEXDATA:      pstr = TEXT("D3DFMT_VERTEXDATA"); break;
  296.     case D3DFMT_INDEX16:         pstr = TEXT("D3DFMT_INDEX16"); break;
  297.     case D3DFMT_INDEX32:         pstr = TEXT("D3DFMT_INDEX32"); break;
  298.     case D3DFMT_Q16W16V16U16:    pstr = TEXT("D3DFMT_Q16W16V16U16"); break;
  299.     case D3DFMT_MULTI2_ARGB8:    pstr = TEXT("D3DFMT_MULTI2_ARGB8"); break;
  300.     case D3DFMT_R16F:            pstr = TEXT("D3DFMT_R16F"); break;
  301.     case D3DFMT_G16R16F:         pstr = TEXT("D3DFMT_G16R16F"); break;
  302.     case D3DFMT_A16B16G16R16F:   pstr = TEXT("D3DFMT_A16B16G16R16F"); break;
  303.     case D3DFMT_R32F:            pstr = TEXT("D3DFMT_R32F"); break;
  304.     case D3DFMT_G32R32F:         pstr = TEXT("D3DFMT_G32R32F"); break;
  305.     case D3DFMT_A32B32G32R32F:   pstr = TEXT("D3DFMT_A32B32G32R32F"); break;
  306.     case D3DFMT_CxV8U8:          pstr = TEXT("D3DFMT_CxV8U8"); break;
  307.     default:                     pstr = TEXT("Unknown format"); break;
  308.     }
  309.     if( bWithPrefix || _tcsstr( pstr, TEXT("D3DFMT_") )== NULL )
  310.         return pstr;
  311.     else
  312.         return pstr + lstrlen( TEXT("D3DFMT_") );
  313. }
  314. //-----------------------------------------------------------------------------
  315. // Name: D3DUtil_QuaternionUnitAxisToUnitAxis2
  316. // Desc: Axis to axis quaternion double angle (no normalization)
  317. //       Takes two points on unit sphere an angle THETA apart, returns
  318. //       quaternion that represents a rotation around cross product by 2*THETA.
  319. //-----------------------------------------------------------------------------
  320. inline D3DXQUATERNION* WINAPI D3DUtil_QuaternionUnitAxisToUnitAxis2( D3DXQUATERNION *pOut, 
  321.                                                                      const D3DXVECTOR3 *pvFrom, 
  322.                                                                      const D3DXVECTOR3 *pvTo )
  323. {
  324.     D3DXVECTOR3 vAxis;
  325.     D3DXVec3Cross(&vAxis, pvFrom, pvTo);    // proportional to sin(theta)
  326.     pOut->x = vAxis.x;
  327.     pOut->y = vAxis.y;
  328.     pOut->z = vAxis.z;
  329.     pOut->w = D3DXVec3Dot( pvFrom, pvTo );
  330.     return pOut;
  331. }
  332. //-----------------------------------------------------------------------------
  333. // Name: D3DUtil_QuaternionAxisToAxis
  334. // Desc: Axis to axis quaternion 
  335. //       Takes two points on unit sphere an angle THETA apart, returns
  336. //       quaternion that represents a rotation around cross product by theta.
  337. //-----------------------------------------------------------------------------
  338. inline D3DXQUATERNION* WINAPI D3DUtil_QuaternionAxisToAxis( D3DXQUATERNION *pOut, 
  339.                                                             const D3DXVECTOR3 *pvFrom, 
  340.                                                             const D3DXVECTOR3 *pvTo)
  341. {
  342.     D3DXVECTOR3 vA, vB;
  343.     D3DXVec3Normalize(&vA, pvFrom);
  344.     D3DXVec3Normalize(&vB, pvTo);
  345.     D3DXVECTOR3 vHalf(vA + vB);
  346.     D3DXVec3Normalize(&vHalf, &vHalf);
  347.     return D3DUtil_QuaternionUnitAxisToUnitAxis2(pOut, &vA, &vHalf);
  348. }
  349. //-----------------------------------------------------------------------------
  350. // Name:
  351. // Desc:
  352. //-----------------------------------------------------------------------------
  353. CD3DArcBall::CD3DArcBall()
  354. {
  355.     Reset();
  356. m_vDownPt = D3DXVECTOR3(0,0,0);
  357. m_vCurrentPt = D3DXVECTOR3(0,0,0);
  358.     RECT rc;
  359.     GetClientRect( GetForegroundWindow(), &rc );
  360.     SetWindow( rc.right, rc.bottom );
  361. }
  362. //-----------------------------------------------------------------------------
  363. // Name:
  364. // Desc:
  365. //-----------------------------------------------------------------------------
  366. void CD3DArcBall::Reset()
  367. {
  368.     D3DXQuaternionIdentity( &m_qDown );
  369.     D3DXQuaternionIdentity( &m_qNow );
  370.     D3DXMatrixIdentity( &m_mRotation );
  371.     D3DXMatrixIdentity( &m_mTranslation );
  372.     D3DXMatrixIdentity( &m_mTranslationDelta );
  373.     m_bDrag = FALSE;
  374.     m_fRadiusTranslation = 1.0f;
  375.     m_fRadius = 1.0f;
  376. }
  377. //-----------------------------------------------------------------------------
  378. // Name:
  379. // Desc:
  380. //-----------------------------------------------------------------------------
  381. D3DXVECTOR3 CD3DArcBall::ScreenToVector( float fScreenPtX, float fScreenPtY )
  382. {
  383.     // Scale to screen
  384.     FLOAT x   = -(fScreenPtX - m_nWidth/2)  / (m_fRadius*m_nWidth/2);
  385.     FLOAT y   =  (fScreenPtY - m_nHeight/2) / (m_fRadius*m_nHeight/2);
  386.     FLOAT z   = 0.0f;
  387.     FLOAT mag = x*x + y*y;
  388.     if( mag > 1.0f )
  389.     {
  390.         FLOAT scale = 1.0f/sqrtf(mag);
  391.         x *= scale;
  392.         y *= scale;
  393.     }
  394.     else
  395.         z = sqrtf( 1.0f - mag );
  396.     // Return vector
  397.     return D3DXVECTOR3( x, y, z );
  398. }
  399. //-----------------------------------------------------------------------------
  400. // Name:
  401. // Desc:
  402. //-----------------------------------------------------------------------------
  403. D3DXQUATERNION CD3DArcBall::QuatFromBallPoints(const D3DXVECTOR3 &vFrom, const D3DXVECTOR3 &vTo)
  404. {
  405. D3DXVECTOR3 vPart;
  406. float fDot = D3DXVec3Dot(&vFrom, &vTo);
  407.     D3DXVec3Cross(&vPart, &vFrom, &vTo);
  408. return D3DXQUATERNION(vPart.x, vPart.y, vPart.z, fDot);
  409. }
  410. //-----------------------------------------------------------------------------
  411. // Name:
  412. // Desc:
  413. //-----------------------------------------------------------------------------
  414. void CD3DArcBall::OnBegin( int nX, int nY )
  415. {
  416. m_bDrag = true;
  417. m_vDownPt = ScreenToVector( (float)nX, (float)nY );
  418. }
  419. //-----------------------------------------------------------------------------
  420. // Name:
  421. // Desc:
  422. //-----------------------------------------------------------------------------
  423. void CD3DArcBall::OnMove( int nX, int nY )
  424. {
  425. if (m_bDrag) 
  426.     { 
  427. m_vCurrentPt = ScreenToVector( (float)nX, (float)nY );
  428.         m_qNow = m_qDown * QuatFromBallPoints( m_vDownPt, m_vCurrentPt );
  429.     }
  430. }
  431. //-----------------------------------------------------------------------------
  432. // Name:
  433. // Desc:
  434. //-----------------------------------------------------------------------------
  435. void CD3DArcBall::OnEnd()
  436. {
  437. m_bDrag = false;
  438. m_qDown = m_qNow;
  439. }
  440. //-----------------------------------------------------------------------------
  441. // Name: HandleMessages
  442. // Desc:
  443. //-----------------------------------------------------------------------------
  444. LRESULT CD3DArcBall::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  445. {
  446.     UNREFERENCED_PARAMETER( hWnd );
  447.     // Current mouse position
  448.     int iMouseX = GET_X_LPARAM(lParam);
  449.     int iMouseY = GET_Y_LPARAM(lParam);
  450.     switch( uMsg )
  451.     {
  452.         case WM_LBUTTONDOWN:
  453.             OnBegin( iMouseX, iMouseY );
  454.             return TRUE;
  455.         case WM_LBUTTONUP:
  456.             OnEnd();
  457.             return TRUE;
  458.         case WM_RBUTTONDOWN:
  459.         case WM_MBUTTONDOWN:
  460.             // Store off the position of the cursor when the button is pressed
  461.             m_ptLastMouse.x = iMouseX;
  462.             m_ptLastMouse.y = iMouseY;
  463.             return TRUE;
  464.         case WM_MOUSEMOVE:
  465.             if( MK_LBUTTON&wParam )
  466.             {
  467.                 OnMove( iMouseX, iMouseY );
  468.             }
  469.             else if( (MK_RBUTTON&wParam) || (MK_MBUTTON&wParam) )
  470.             {
  471.                 // Normalize based on size of window and bounding sphere radius
  472.                 FLOAT fDeltaX = ( m_ptLastMouse.x-iMouseX ) * m_fRadiusTranslation / m_nWidth;
  473.                 FLOAT fDeltaY = ( m_ptLastMouse.y-iMouseY ) * m_fRadiusTranslation / m_nHeight;
  474.                 if( wParam & MK_RBUTTON )
  475.                 {
  476.                     D3DXMatrixTranslation( &m_mTranslationDelta, -2*fDeltaX, 2*fDeltaY, 0.0f );
  477.                     D3DXMatrixMultiply( &m_mTranslation, &m_mTranslation, &m_mTranslationDelta );
  478.                 }
  479.                 else  // wParam & MK_MBUTTON
  480.                 {
  481.                     D3DXMatrixTranslation( &m_mTranslationDelta, 0.0f, 0.0f, 5*fDeltaY );
  482.                     D3DXMatrixMultiply( &m_mTranslation, &m_mTranslation, &m_mTranslationDelta );
  483.                 }
  484.                 // Store mouse coordinate
  485.                 m_ptLastMouse.x = iMouseX;
  486.                 m_ptLastMouse.y = iMouseY;
  487.             }
  488.             return TRUE;
  489.     }
  490.     return FALSE;
  491. }
  492. //-----------------------------------------------------------------------------
  493. // Name: CBaseCamera
  494. // Desc: Constructor
  495. //-----------------------------------------------------------------------------
  496. CBaseCamera::CBaseCamera()
  497. {
  498.     ZeroMemory( m_aKeys, sizeof(BYTE)*CAM_MAX_KEYS );
  499.     // Set attributes for the view matrix
  500.     D3DXVECTOR3 vEyePt    = D3DXVECTOR3(0.0f,0.0f,0.0f);
  501.     D3DXVECTOR3 vLookatPt = D3DXVECTOR3(0.0f,0.0f,1.0f);
  502.     // Setup the view matrix
  503.     SetViewParams( &vEyePt, &vLookatPt );
  504.     // Setup the projection matrix
  505.     SetProjParams( D3DX_PI/4, 1.0f, 1.0f, 1000.0f );
  506.     GetCursorPos( &m_ptLastMousePosition );
  507.     m_bMouseLButtonDown = false;
  508.     m_bMouseMButtonDown = false;
  509.     m_bMouseRButtonDown = false;
  510.     m_nCurrentButtonMask = 0;
  511.     m_nMouseWheelDelta = 0;
  512.     m_fCameraYawAngle = 0.0f;
  513.     m_fCameraPitchAngle = 0.0f;
  514.     m_vVelocity     = D3DXVECTOR3(0,0,0);
  515.     m_bMovementDrag = false;
  516.     m_vVelocityDrag = D3DXVECTOR3(0,0,0);
  517.     m_fDragTimer    = 0.0f;
  518.     m_fTotalDragTimeToZero = 0.25;
  519.     m_vRotVelocity = D3DXVECTOR2(0,0);
  520.     m_fRotationScaler = 0.01f;           
  521.     m_fMoveScaler = 5.0f;           
  522.     m_bInvertPitch = false;
  523.     m_bEnableYAxisMovement = true;
  524.     m_bEnablePositionMovement = true;
  525.     m_vMouseDelta   = D3DXVECTOR2(0,0);
  526.     m_fFramesToSmoothMouseData = 2.0f;
  527.     m_bClipToBoundary = false;
  528.     m_vMinBoundary = D3DXVECTOR3(-1,-1,-1);
  529.     m_vMaxBoundary = D3DXVECTOR3(1,1,1);
  530.     m_bResetCursorAfterMove = false;
  531. }
  532. //-----------------------------------------------------------------------------
  533. // Name: SetViewParams
  534. // Desc: Client can call this to change the position and direction of camrea
  535. //-----------------------------------------------------------------------------
  536. VOID CBaseCamera::SetViewParams( D3DXVECTOR3* pvEyePt, D3DXVECTOR3* pvLookatPt )
  537. {
  538.     if( NULL == pvEyePt || NULL == pvLookatPt )
  539.         return;
  540.     m_vDefaultEye = m_vEye = *pvEyePt;
  541.     m_vDefaultLookAt = m_vLookAt = *pvLookatPt;
  542.     // Calc the view matrix
  543.     D3DXVECTOR3 vUp(0,1,0);
  544.     D3DXMatrixLookAtLH( &m_mView, pvEyePt, pvLookatPt, &vUp );
  545.     D3DXMATRIX mInvView;
  546.     D3DXMatrixInverse( &mInvView, NULL, &m_mView );
  547.     // The axis basis vectors and camera position are stored inside the 
  548.     // position matrix in the 4 rows of the camera's world matrix.
  549.     // To figuire out the yaw/pitch of the camera, we just need the Z basis vector
  550.     D3DXVECTOR3* pZBasis = (D3DXVECTOR3*) &mInvView._31;
  551.     m_fCameraYawAngle   = atan2f( pZBasis->x, pZBasis->z );
  552.     float fLen = sqrtf(pZBasis->z*pZBasis->z + pZBasis->x*pZBasis->x);
  553.     m_fCameraPitchAngle = -atan2f( pZBasis->y, fLen );
  554. }
  555. //-----------------------------------------------------------------------------
  556. // Name: SetProjParams
  557. // Desc: Calculates the projection matrix based on input params
  558. //-----------------------------------------------------------------------------
  559. VOID CBaseCamera::SetProjParams( FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane,
  560.                                    FLOAT fFarPlane )
  561. {
  562.     // Set attributes for the projection matrix
  563.     m_fFOV        = fFOV;
  564.     m_fAspect     = fAspect;
  565.     m_fNearPlane  = fNearPlane;
  566.     m_fFarPlane   = fFarPlane;
  567.     D3DXMatrixPerspectiveFovLH( &m_mProj, fFOV, fAspect, fNearPlane, fFarPlane );
  568. }
  569. //-----------------------------------------------------------------------------
  570. // Name: HandleMessages
  571. // Desc: Call this from your message proc so this class can handle window messages
  572. //-----------------------------------------------------------------------------
  573. LRESULT CBaseCamera::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  574. {
  575.     UNREFERENCED_PARAMETER( hWnd );
  576.     UNREFERENCED_PARAMETER( lParam );
  577.     switch( uMsg )
  578.     {
  579.         case WM_KEYDOWN:
  580.         {
  581.             // Map this key to a D3DUtil_CameraKeys enum and update the
  582.             // state of m_aKeys[] by adding the KEY_WAS_DOWN_MASK|KEY_IS_DOWN_MASK mask
  583.             // only if the key is not down
  584.             D3DUtil_CameraKeys mappedKey = MapKey( (UINT)wParam );
  585.             if( mappedKey != CAM_UNKNOWN )
  586.             {
  587.                 if( FALSE == IsKeyDown(m_aKeys[mappedKey]) )
  588.                     m_aKeys[ mappedKey ] = KEY_WAS_DOWN_MASK | KEY_IS_DOWN_MASK;
  589.             }
  590.             break;
  591.         }
  592.         case WM_KEYUP:
  593.         {
  594.             // Map this key to a D3DUtil_CameraKeys enum and update the
  595.             // state of m_aKeys[] by removing the KEY_IS_DOWN_MASK mask.
  596.             D3DUtil_CameraKeys mappedKey = MapKey( (UINT)wParam );
  597.             if( mappedKey != CAM_UNKNOWN )
  598.                 m_aKeys[ mappedKey ] &= ~KEY_IS_DOWN_MASK;
  599.             break;
  600.         }
  601.         case WM_RBUTTONDOWN: 
  602.         case WM_MBUTTONDOWN: 
  603.         case WM_LBUTTONDOWN: 
  604.         {
  605.             // Update member var state
  606.             if( uMsg == WM_LBUTTONDOWN ) { m_bMouseLButtonDown = true; m_nCurrentButtonMask |= MOUSE_LEFT_BUTTON; }
  607.             if( uMsg == WM_MBUTTONDOWN ) { m_bMouseMButtonDown = true; m_nCurrentButtonMask |= MOUSE_MIDDLE_BUTTON; }
  608.             if( uMsg == WM_RBUTTONDOWN ) { m_bMouseRButtonDown = true; m_nCurrentButtonMask |= MOUSE_RIGHT_BUTTON; }
  609.             // Capture the mouse, so if the mouse button is 
  610.             // released outside the window, we'll get the WM_LBUTTONUP message
  611.             SetCapture(hWnd);
  612.             GetCursorPos( &m_ptLastMousePosition ); 
  613.             return TRUE;
  614.         }
  615.         case WM_RBUTTONUP: 
  616.         case WM_MBUTTONUP: 
  617.         case WM_LBUTTONUP:   
  618.         {
  619.             // Update member var state
  620.             if( uMsg == WM_LBUTTONUP ) { m_bMouseLButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_LEFT_BUTTON; }
  621.             if( uMsg == WM_MBUTTONUP ) { m_bMouseMButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_MIDDLE_BUTTON; }
  622.             if( uMsg == WM_RBUTTONUP ) { m_bMouseRButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_RIGHT_BUTTON; }
  623.             // Release the capture if no mouse buttons down
  624.             if( !m_bMouseLButtonDown  && 
  625.                 !m_bMouseRButtonDown &&
  626.                 !m_bMouseMButtonDown )
  627.             {
  628.                 ReleaseCapture();
  629.             }
  630.             break;
  631.         }
  632.         case WM_MOUSEWHEEL:
  633.             // Update member var state
  634.             m_nMouseWheelDelta = (short)HIWORD(wParam) / 120;
  635.             break;
  636.     }
  637.     return FALSE;
  638. }
  639. //-----------------------------------------------------------------------------
  640. // Name: UpdateMouseDelta
  641. // Desc: Figure out the mouse delta based on mouse movement
  642. //-----------------------------------------------------------------------------
  643. void CBaseCamera::UpdateMouseDelta( float fElapsedTime )
  644. {
  645.     UNREFERENCED_PARAMETER( fElapsedTime );
  646.     POINT ptCurMouseDelta;
  647.     POINT ptCurMousePos;
  648.     
  649.     // Get current position of mouse
  650.     GetCursorPos( &ptCurMousePos );
  651.     // Calc how far it's moved since last frame
  652.     ptCurMouseDelta.x = ptCurMousePos.x - m_ptLastMousePosition.x;
  653.     ptCurMouseDelta.y = ptCurMousePos.y - m_ptLastMousePosition.y;
  654.     // Record current position for next time
  655.     m_ptLastMousePosition = ptCurMousePos;
  656.     if( m_bResetCursorAfterMove )
  657.     {
  658.         // Set position of camera to center of desktop, 
  659.         // so it always has room to move.  This is very useful
  660.         // if the cursor is hidden.  If this isn't done and cursor is hidden, 
  661.         // then invisible cursor will hit the edge of the screen 
  662.         // and the user can't tell what happened
  663.         POINT ptCenter;
  664.         RECT rcDesktop;
  665.         GetWindowRect( GetDesktopWindow(), &rcDesktop );
  666.         ptCenter.x = (rcDesktop.right - rcDesktop.left) / 2;
  667.         ptCenter.y = (rcDesktop.bottom - rcDesktop.top) / 2;   
  668.         SetCursorPos( ptCenter.x, ptCenter.y );
  669.         m_ptLastMousePosition = ptCenter;
  670.     }
  671.     // Smooth the relative mouse data over a few frames so it isn't 
  672.     // jerky when moving slowly at low frame rates.
  673.     float fPercentOfNew =  1.0f / m_fFramesToSmoothMouseData;
  674.     float fPercentOfOld =  1.0f - fPercentOfNew;
  675.     m_vMouseDelta.x = m_vMouseDelta.x*fPercentOfOld + ptCurMouseDelta.x*fPercentOfNew;
  676.     m_vMouseDelta.y = m_vMouseDelta.y*fPercentOfOld + ptCurMouseDelta.y*fPercentOfNew;
  677.     m_vRotVelocity = m_vMouseDelta * m_fRotationScaler;
  678. }
  679. //-----------------------------------------------------------------------------
  680. // Name: UpdateVelocity
  681. // Desc: Figure out the velocity based on keyboard input & drag if any
  682. //-----------------------------------------------------------------------------
  683. void CBaseCamera::UpdateVelocity( float fElapsedTime )
  684. {
  685.     D3DXMATRIX mRotDelta;
  686.     D3DXVECTOR3 vAccel = D3DXVECTOR3(0,0,0);
  687.     if( m_bEnablePositionMovement )
  688.     {
  689.         // Update acceleration vector based on keyboard state
  690.         if( IsKeyDown(m_aKeys[CAM_MOVE_FORWARD]) )
  691.             vAccel.z += 1.0f;
  692.         if( IsKeyDown(m_aKeys[CAM_MOVE_BACKWARD]) )
  693.             vAccel.z -= 1.0f;
  694.         if( m_bEnableYAxisMovement )
  695.         {
  696.             if( IsKeyDown(m_aKeys[CAM_MOVE_UP]) )
  697.                 vAccel.y += 1.0f;
  698.             if( IsKeyDown(m_aKeys[CAM_MOVE_DOWN]) )
  699.                 vAccel.y -= 1.0f;
  700.         }
  701.         if( IsKeyDown(m_aKeys[CAM_STRAFE_RIGHT]) )
  702.             vAccel.x += 1.0f;
  703.         if( IsKeyDown(m_aKeys[CAM_STRAFE_LEFT]) )
  704.             vAccel.x -= 1.0f;
  705.     }
  706.     // Normalize vector so if moving 2 dirs (left & forward), 
  707.     // the camera doesn't move faster than if moving in 1 dir
  708.     D3DXVec3Normalize( &vAccel, &vAccel );
  709.     // Scale the acceleration vector
  710.     vAccel *= m_fMoveScaler;
  711.     if( m_bMovementDrag )
  712.     {
  713.         // Is there any acceleration this frame?
  714.         if( D3DXVec3LengthSq( &vAccel ) > 0 )
  715.         {
  716.             // If so, then this means the user has pressed a movement key
  717.             // so change the velocity immediately to acceleration 
  718.             // upon keyboard input.  This isn't normal physics
  719.             // but it will give a quick response to keyboard input
  720.             m_vVelocity = vAccel;
  721.             m_fDragTimer = m_fTotalDragTimeToZero;
  722.             m_vVelocityDrag = vAccel / m_fDragTimer;
  723.         }
  724.         else 
  725.         {
  726.             // If no key being pressed, then slowly decrease velocity to 0
  727.             if( m_fDragTimer > 0 )
  728.             {
  729.                 // Drag until timer is <= 0
  730.                 m_vVelocity -= m_vVelocityDrag * fElapsedTime;
  731.                 m_fDragTimer -= fElapsedTime;
  732.             }
  733.             else
  734.             {
  735.                 // Zero velocity
  736.                 m_vVelocity = D3DXVECTOR3(0,0,0);
  737.             }
  738.         }
  739.     }
  740.     else
  741.     {
  742.         // No drag, so immediatly change the velocity
  743.         m_vVelocity = vAccel;
  744.     }
  745. }
  746. //-----------------------------------------------------------------------------
  747. // Name: ConstrainToBoundary
  748. // Desc: Clamps pV to lie inside m_vMinBoundary & m_vMaxBoundary
  749. //-----------------------------------------------------------------------------
  750. void CBaseCamera::ConstrainToBoundary( D3DXVECTOR3* pV )
  751. {
  752.     // Constrain vector to a bounding box 
  753.     pV->x = max(pV->x, m_vMinBoundary.x);
  754.     pV->y = max(pV->y, m_vMinBoundary.y);
  755.     pV->z = max(pV->z, m_vMinBoundary.z);
  756.     pV->x = min(pV->x, m_vMaxBoundary.x);
  757.     pV->y = min(pV->y, m_vMaxBoundary.y);
  758.     pV->z = min(pV->z, m_vMaxBoundary.z);
  759. }
  760. //-----------------------------------------------------------------------------
  761. // Name: MapKey
  762. // Desc: Maps a windows virtual key to an enum
  763. //-----------------------------------------------------------------------------
  764. D3DUtil_CameraKeys CBaseCamera::MapKey( UINT nKey )
  765. {
  766.     // This could be upgraded to a method that's user-definable but for 
  767.     // simplisity, we'll use a hardcoded mapping.
  768.     switch( nKey )
  769.     {
  770.         case VK_LEFT:  return CAM_STRAFE_LEFT;
  771.         case VK_RIGHT: return CAM_STRAFE_RIGHT;
  772.         case VK_UP:    return CAM_MOVE_FORWARD;
  773.         case VK_DOWN:  return CAM_MOVE_BACKWARD;
  774.         case VK_PRIOR: return CAM_MOVE_UP;        // pgup
  775.         case VK_NEXT:  return CAM_MOVE_DOWN;      // pgdn
  776.         case 'A':      return CAM_STRAFE_LEFT;
  777.         case 'D':      return CAM_STRAFE_RIGHT;
  778.         case 'W':      return CAM_MOVE_FORWARD;
  779.         case 'S':      return CAM_MOVE_BACKWARD;
  780.         case 'Q':      return CAM_MOVE_DOWN;
  781.         case 'E':      return CAM_MOVE_UP;
  782.         case VK_NUMPAD4: return CAM_STRAFE_LEFT;
  783.         case VK_NUMPAD6: return CAM_STRAFE_RIGHT;
  784.         case VK_NUMPAD8: return CAM_MOVE_FORWARD;
  785.         case VK_NUMPAD2: return CAM_MOVE_BACKWARD;
  786.         case VK_NUMPAD9: return CAM_MOVE_UP;        
  787.         case VK_NUMPAD3: return CAM_MOVE_DOWN;      
  788.         case VK_HOME:   return CAM_RESET;
  789.     }
  790.     return CAM_UNKNOWN;
  791. }
  792. //-----------------------------------------------------------------------------
  793. // Name: Reset
  794. // Desc: Reset the camera's position back to the default
  795. //-----------------------------------------------------------------------------
  796. VOID CBaseCamera::Reset()
  797. {
  798.     SetViewParams( &m_vDefaultEye, &m_vDefaultLookAt );
  799. }
  800. //-----------------------------------------------------------------------------
  801. // Name: CFirstPersonCamera
  802. // Desc: Constructor
  803. //-----------------------------------------------------------------------------
  804. CFirstPersonCamera::CFirstPersonCamera()
  805. {
  806. }
  807. //-----------------------------------------------------------------------------
  808. // Name: FrameMove
  809. // Desc: Update the view matrix based on user input & elapsed time
  810. //-----------------------------------------------------------------------------
  811. VOID CFirstPersonCamera::FrameMove( FLOAT fElapsedTime )
  812. {
  813.     if( IsKeyDown(m_aKeys[CAM_RESET]) )
  814.         Reset();
  815.     // Get the mouse movement (if any) if the mouse button are down
  816.     if( m_bMouseLButtonDown || m_bMouseMButtonDown || m_bMouseRButtonDown ) 
  817.         UpdateMouseDelta( fElapsedTime );
  818.     // Get amount of velocity based on the keyboard input and drag (if any)
  819.     UpdateVelocity( fElapsedTime );
  820.     // Simple euler method to calculate position delta
  821.     D3DXVECTOR3 vPosDelta = m_vVelocity * fElapsedTime;
  822.     // If rotating the camera 
  823.     if( m_bMouseLButtonDown ||  m_bMouseMButtonDown || m_bMouseRButtonDown )
  824.     {
  825.         // Update the pitch & yaw angle based on mouse movement
  826.         float fYawDelta   = m_vRotVelocity.x;
  827.         float fPitchDelta = m_vRotVelocity.y;
  828.         // Invert pitch if requested
  829.         if( m_bInvertPitch )
  830.             fPitchDelta = -fPitchDelta;
  831.         m_fCameraPitchAngle += fPitchDelta;
  832.         m_fCameraYawAngle   += fYawDelta;
  833.         // Limit pitch to straight up or straight down
  834.         m_fCameraPitchAngle = max( -D3DX_PI/2.0f,  m_fCameraPitchAngle );
  835.         m_fCameraPitchAngle = min( +D3DX_PI/2.0f,  m_fCameraPitchAngle );
  836.     }
  837.     // Make a rotation matrix based on the camera's yaw & pitch
  838.     D3DXMATRIX mCameraRot;
  839.     D3DXMatrixRotationYawPitchRoll( &mCameraRot, m_fCameraYawAngle, m_fCameraPitchAngle, 0 );
  840.     // Transform vectors based on camera's rotation matrix
  841.     D3DXVECTOR3 vWorldUp, vWorldAhead;
  842.     D3DXVECTOR3 vLocalUp    = D3DXVECTOR3(0,1,0);
  843.     D3DXVECTOR3 vLocalAhead = D3DXVECTOR3(0,0,1);
  844.     D3DXVec3TransformCoord( &vWorldUp, &vLocalUp, &mCameraRot );
  845.     D3DXVec3TransformCoord( &vWorldAhead, &vLocalAhead, &mCameraRot );
  846.     // Transform the position delta by the camera's rotation 
  847.     D3DXVECTOR3 vPosDeltaWorld;
  848.     D3DXVec3TransformCoord( &vPosDeltaWorld, &vPosDelta, &mCameraRot );
  849.     if( !m_bEnableYAxisMovement )
  850.         vPosDeltaWorld.y = 0.0f;
  851.     // Move the eye position 
  852.     m_vEye += vPosDeltaWorld;
  853.     if( m_bClipToBoundary )
  854.         ConstrainToBoundary( &m_vEye );
  855.     // Update the lookAt position based on the eye position 
  856.     m_vLookAt = m_vEye + vWorldAhead;
  857.     // Update the view matrix
  858.     D3DXMatrixLookAtLH( &m_mView, &m_vEye, &m_vLookAt, &vWorldUp );
  859.     D3DXMatrixInverse( &m_mCameraWorld, NULL, &m_mView );
  860. }
  861. //-----------------------------------------------------------------------------
  862. // Name: CModelViewerCamera
  863. // Desc: Constructor 
  864. //-----------------------------------------------------------------------------
  865. CModelViewerCamera::CModelViewerCamera()
  866. {
  867.     D3DXMatrixIdentity( &m_mWorld );
  868.     D3DXMatrixIdentity( &m_mModelRot );
  869.     D3DXMatrixIdentity( &m_mModelLastRot );    
  870.     m_vModelCenter = D3DXVECTOR3(0,0,0);
  871.     m_fRadius    = 5.0f;
  872.     m_fDefaultRadius = 5.0f;
  873.     m_fMinRadius = 1.0f;
  874.     m_fMaxRadius = FLT_MAX;
  875.     m_bLimitPitch = false;
  876.     m_bEnablePositionMovement = false;
  877.     m_nRotateModelButtonMask  = MOUSE_LEFT_BUTTON;
  878.     m_nZoomButtonMask         = MOUSE_WHEEL;
  879.     m_nRotateCameraButtonMask = MOUSE_RIGHT_BUTTON;
  880. }
  881. //-----------------------------------------------------------------------------
  882. // Name: FrameMove
  883. // Desc: Update the view matrix & the model's world matrix based 
  884. //       on user input & elapsed time
  885. //-----------------------------------------------------------------------------
  886. VOID CModelViewerCamera::FrameMove( FLOAT fElapsedTime )
  887. {
  888.     if( IsKeyDown(m_aKeys[CAM_RESET]) )
  889.         Reset();
  890.     // Get the mouse movement (if any) if the mouse button are down
  891.     if( m_nCurrentButtonMask != 0 ) 
  892.         UpdateMouseDelta( fElapsedTime );
  893.     // Get amount of velocity based on the keyboard input and drag (if any)
  894.     UpdateVelocity( fElapsedTime );
  895.     // Simple euler method to calculate position delta
  896.     D3DXVECTOR3 vPosDelta = m_vVelocity * fElapsedTime;
  897.     // Change the radius from the camera to the model based on wheel scrolling
  898.     if( m_nMouseWheelDelta && m_nZoomButtonMask == MOUSE_WHEEL )
  899.         m_fRadius -= m_nMouseWheelDelta * m_fRadius * 0.1f;
  900.     m_fRadius = min( m_fMaxRadius, m_fRadius );
  901.     m_fRadius = max( m_fMinRadius, m_fRadius );
  902.     m_nMouseWheelDelta = 0;
  903.     // Get the inverse of the arcball's rotation matrix
  904.     D3DXMATRIX mCameraRot;
  905.     D3DXMatrixInverse( &mCameraRot, NULL, m_ViewArcBall.GetRotationMatrix() );
  906.     // Transform vectors based on camera's rotation matrix
  907.     D3DXVECTOR3 vWorldUp, vWorldAhead;
  908.     D3DXVECTOR3 vLocalUp    = D3DXVECTOR3(0,1,0);
  909.     D3DXVECTOR3 vLocalAhead = D3DXVECTOR3(0,0,1);
  910.     D3DXVec3TransformCoord( &vWorldUp, &vLocalUp, &mCameraRot );
  911.     D3DXVec3TransformCoord( &vWorldAhead, &vLocalAhead, &mCameraRot );
  912.     // Transform the position delta by the camera's rotation 
  913.     D3DXVECTOR3 vPosDeltaWorld;
  914.     D3DXVec3TransformCoord( &vPosDeltaWorld, &vPosDelta, &mCameraRot );
  915.     // Move the lookAt position 
  916.     m_vLookAt += vPosDeltaWorld;
  917.     if( m_bClipToBoundary )
  918.         ConstrainToBoundary( &m_vLookAt );
  919.     // Update the eye point based on a radius away from the lookAt position
  920.     m_vEye = m_vLookAt - vWorldAhead * m_fRadius;
  921.     // Update the view matrix
  922.     D3DXMatrixLookAtLH( &m_mView, &m_vEye, &m_vLookAt, &vWorldUp );
  923.     D3DXMATRIX mInvView;
  924.     D3DXMatrixInverse( &mInvView, NULL, &m_mView );
  925.     mInvView._41 = mInvView._42 = mInvView._43 = 0;
  926.     D3DXMATRIX mModelLastRotInv;
  927.     D3DXMatrixInverse(&mModelLastRotInv, NULL, &m_mModelLastRot);
  928.     // Accumulate the delta of the arcball's rotation in view space.
  929.     // Note that per-frame delta rotations could be problematic over long periods of time.
  930.     D3DXMATRIX mModelRot;
  931.     mModelRot = *m_WorldArcBall.GetRotationMatrix();
  932.     m_mModelRot *= m_mView * mModelLastRotInv * mModelRot * mInvView;
  933.     m_mModelLastRot = mModelRot;
  934.     // Since we're accumulating delta rotations, we need to orthonormalize 
  935.     // the matrix to prevent eventual matrix skew
  936.     D3DXVECTOR3* pXBasis = (D3DXVECTOR3*) &m_mWorld._11;
  937.     D3DXVECTOR3* pYBasis = (D3DXVECTOR3*) &m_mWorld._21;
  938.     D3DXVECTOR3* pZBasis = (D3DXVECTOR3*) &m_mWorld._31;
  939.     D3DXVec3Normalize( pXBasis, pXBasis );
  940.     D3DXVec3Cross( pYBasis, pZBasis, pXBasis );
  941.     D3DXVec3Normalize( pYBasis, pYBasis );
  942.     D3DXVec3Cross( pZBasis, pXBasis, pYBasis );
  943.     // Translate the rotation matrix to the same position as the lookAt position
  944.     m_mModelRot._41 = m_vLookAt.x;
  945.     m_mModelRot._42 = m_vLookAt.y;
  946.     m_mModelRot._43 = m_vLookAt.z;
  947.     // Translate world matrix so its at the center of the model
  948.     D3DXMATRIX mTrans;
  949.     D3DXMatrixTranslation( &mTrans, -m_vModelCenter.x, -m_vModelCenter.y, -m_vModelCenter.z );
  950.     m_mWorld = mTrans * m_mModelRot;
  951. }
  952. //-----------------------------------------------------------------------------
  953. // Name: Reset
  954. // Desc: Reset the camera's position back to the default
  955. //-----------------------------------------------------------------------------
  956. VOID CModelViewerCamera::Reset()
  957. {
  958.     CBaseCamera::Reset();
  959.     D3DXMatrixIdentity( &m_mWorld );
  960.     m_fRadius = m_fDefaultRadius;
  961.     m_WorldArcBall.Reset();
  962.     m_ViewArcBall.Reset();
  963. }
  964. //-----------------------------------------------------------------------------
  965. // Name: HandleMessages
  966. // Desc: Call this from your message proc so this class can handle window messages
  967. //-----------------------------------------------------------------------------
  968. LRESULT CModelViewerCamera::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  969. {
  970.     CBaseCamera::HandleMessages( hWnd, uMsg, wParam, lParam );
  971.     if( (uMsg == WM_LBUTTONDOWN && m_nRotateModelButtonMask == MOUSE_LEFT_BUTTON) ||
  972.         (uMsg == WM_MBUTTONDOWN && m_nRotateModelButtonMask == MOUSE_MIDDLE_BUTTON) ||
  973.         (uMsg == WM_RBUTTONDOWN && m_nRotateModelButtonMask == MOUSE_RIGHT_BUTTON) )
  974.     {
  975.         int iMouseX = GET_X_LPARAM(lParam);
  976.         int iMouseY = GET_Y_LPARAM(lParam);
  977.         m_WorldArcBall.OnBegin( iMouseX, iMouseY );            
  978.     }
  979.     if( (uMsg == WM_LBUTTONDOWN && m_nRotateCameraButtonMask == MOUSE_LEFT_BUTTON) ||
  980.         (uMsg == WM_MBUTTONDOWN && m_nRotateCameraButtonMask == MOUSE_MIDDLE_BUTTON) ||
  981.         (uMsg == WM_RBUTTONDOWN && m_nRotateCameraButtonMask == MOUSE_RIGHT_BUTTON) )
  982.     {
  983.         int iMouseX = GET_X_LPARAM(lParam);
  984.         int iMouseY = GET_Y_LPARAM(lParam);
  985.         m_ViewArcBall.OnBegin( iMouseX, iMouseY );            
  986.     }
  987.     if( uMsg == WM_MOUSEMOVE )
  988.     {
  989.         int iMouseX = GET_X_LPARAM(lParam);
  990.         int iMouseY = GET_Y_LPARAM(lParam);
  991.         m_WorldArcBall.OnMove( iMouseX, iMouseY );
  992.         m_ViewArcBall.OnMove( iMouseX, iMouseY );
  993.     }
  994.     if( (uMsg == WM_LBUTTONUP && m_nRotateModelButtonMask == MOUSE_LEFT_BUTTON) ||
  995.         (uMsg == WM_MBUTTONUP && m_nRotateModelButtonMask == MOUSE_MIDDLE_BUTTON) ||
  996.         (uMsg == WM_RBUTTONUP && m_nRotateModelButtonMask == MOUSE_RIGHT_BUTTON) )
  997.     {
  998.         m_WorldArcBall.OnEnd();
  999.     }
  1000.     if( (uMsg == WM_LBUTTONUP && m_nRotateCameraButtonMask == MOUSE_LEFT_BUTTON) ||
  1001.         (uMsg == WM_MBUTTONUP && m_nRotateCameraButtonMask == MOUSE_MIDDLE_BUTTON) ||
  1002.         (uMsg == WM_RBUTTONUP && m_nRotateCameraButtonMask == MOUSE_RIGHT_BUTTON) )
  1003.     {
  1004.         m_ViewArcBall.OnEnd();
  1005.     }
  1006.     return FALSE;
  1007. }