1 //--------------------------------------------------------------------------------------
\r
2 // File: DXUTcamera.cpp
\r
4 // Copyright (c) Microsoft Corporation. All rights reserved
\r
5 //--------------------------------------------------------------------------------------
\r
7 #include "DXUTcamera.h"
\r
9 #undef min // use __min instead
\r
10 #undef max // use __max instead
\r
12 //--------------------------------------------------------------------------------------
\r
13 CD3DArcBall::CD3DArcBall()
\r
16 m_vDownPt = D3DXVECTOR3( 0, 0, 0 );
\r
17 m_vCurrentPt = D3DXVECTOR3( 0, 0, 0 );
\r
18 m_Offset.x = m_Offset.y = 0;
\r
21 GetClientRect( GetForegroundWindow(), &rc );
\r
22 SetWindow( rc.right, rc.bottom );
\r
29 //--------------------------------------------------------------------------------------
\r
30 void CD3DArcBall::Reset()
\r
32 D3DXQuaternionIdentity( &m_qDown );
\r
33 D3DXQuaternionIdentity( &m_qNow );
\r
34 D3DXMatrixIdentity( &m_mRotation );
\r
35 D3DXMatrixIdentity( &m_mTranslation );
\r
36 D3DXMatrixIdentity( &m_mTranslationDelta );
\r
38 m_fRadiusTranslation = 1.0f;
\r
45 //--------------------------------------------------------------------------------------
\r
46 D3DXVECTOR3 CD3DArcBall::ScreenToVector( float fScreenPtX, float fScreenPtY )
\r
49 FLOAT x = -( fScreenPtX - m_Offset.x - m_nWidth / 2 ) / ( m_fRadius * m_nWidth / 2 );
\r
50 FLOAT y = ( fScreenPtY - m_Offset.y - m_nHeight / 2 ) / ( m_fRadius * m_nHeight / 2 );
\r
53 FLOAT mag = x * x + y * y;
\r
57 FLOAT scale = 1.0f / sqrtf( mag );
\r
62 z = sqrtf( 1.0f - mag );
\r
65 return D3DXVECTOR3( x, y, z );
\r
71 //--------------------------------------------------------------------------------------
\r
72 D3DXQUATERNION CD3DArcBall::QuatFromBallPoints( const D3DXVECTOR3& vFrom, const D3DXVECTOR3& vTo )
\r
75 float fDot = D3DXVec3Dot( &vFrom, &vTo );
\r
76 D3DXVec3Cross( &vPart, &vFrom, &vTo );
\r
78 return D3DXQUATERNION( vPart.x, vPart.y, vPart.z, fDot );
\r
84 //--------------------------------------------------------------------------------------
\r
85 void CD3DArcBall::OnBegin( int nX, int nY )
\r
87 // Only enter the drag state if the click falls
\r
88 // inside the click rectangle.
\r
89 if( nX >= m_Offset.x &&
\r
90 nX < m_Offset.x + m_nWidth &&
\r
92 nY < m_Offset.y + m_nHeight )
\r
96 m_vDownPt = ScreenToVector( ( float )nX, ( float )nY );
\r
103 //--------------------------------------------------------------------------------------
\r
104 void CD3DArcBall::OnMove( int nX, int nY )
\r
108 m_vCurrentPt = ScreenToVector( ( float )nX, ( float )nY );
\r
109 m_qNow = m_qDown * QuatFromBallPoints( m_vDownPt, m_vCurrentPt );
\r
116 //--------------------------------------------------------------------------------------
\r
117 void CD3DArcBall::OnEnd()
\r
125 //--------------------------------------------------------------------------------------
\r
127 //--------------------------------------------------------------------------------------
\r
128 LRESULT CD3DArcBall::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
\r
130 // Current mouse position
\r
131 int iMouseX = ( short )LOWORD( lParam );
\r
132 int iMouseY = ( short )HIWORD( lParam );
\r
136 case WM_LBUTTONDOWN:
\r
137 case WM_LBUTTONDBLCLK:
\r
138 SetCapture( hWnd );
\r
139 OnBegin( iMouseX, iMouseY );
\r
146 case WM_CAPTURECHANGED:
\r
147 if( ( HWND )lParam != hWnd )
\r
154 case WM_RBUTTONDOWN:
\r
155 case WM_RBUTTONDBLCLK:
\r
156 case WM_MBUTTONDOWN:
\r
157 case WM_MBUTTONDBLCLK:
\r
158 SetCapture( hWnd );
\r
159 // Store off the position of the cursor when the button is pressed
\r
160 m_ptLastMouse.x = iMouseX;
\r
161 m_ptLastMouse.y = iMouseY;
\r
170 if( MK_LBUTTON & wParam )
\r
172 OnMove( iMouseX, iMouseY );
\r
174 else if( ( MK_RBUTTON & wParam ) || ( MK_MBUTTON & wParam ) )
\r
176 // Normalize based on size of window and bounding sphere radius
\r
177 FLOAT fDeltaX = ( m_ptLastMouse.x - iMouseX ) * m_fRadiusTranslation / m_nWidth;
\r
178 FLOAT fDeltaY = ( m_ptLastMouse.y - iMouseY ) * m_fRadiusTranslation / m_nHeight;
\r
180 if( wParam & MK_RBUTTON )
\r
182 D3DXMatrixTranslation( &m_mTranslationDelta, -2 * fDeltaX, 2 * fDeltaY, 0.0f );
\r
183 D3DXMatrixMultiply( &m_mTranslation, &m_mTranslation, &m_mTranslationDelta );
\r
185 else // wParam & MK_MBUTTON
\r
187 D3DXMatrixTranslation( &m_mTranslationDelta, 0.0f, 0.0f, 5 * fDeltaY );
\r
188 D3DXMatrixMultiply( &m_mTranslation, &m_mTranslation, &m_mTranslationDelta );
\r
191 // Store mouse coordinate
\r
192 m_ptLastMouse.x = iMouseX;
\r
193 m_ptLastMouse.y = iMouseY;
\r
204 //--------------------------------------------------------------------------------------
\r
206 //--------------------------------------------------------------------------------------
\r
207 CBaseCamera::CBaseCamera()
\r
210 ZeroMemory( m_aKeys, sizeof( BYTE ) * CAM_MAX_KEYS );
\r
211 ZeroMemory( m_GamePad, sizeof( DXUT_GAMEPAD ) * DXUT_MAX_CONTROLLERS );
\r
213 // Set attributes for the view matrix
\r
214 D3DXVECTOR3 vEyePt = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
\r
215 D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
\r
217 // Setup the view matrix
\r
218 SetViewParams( &vEyePt, &vLookatPt );
\r
220 // Setup the projection matrix
\r
221 SetProjParams( D3DX_PI / 4, 1.0f, 1.0f, 1000.0f );
\r
223 GetCursorPos( &m_ptLastMousePosition );
\r
224 m_bMouseLButtonDown = false;
\r
225 m_bMouseMButtonDown = false;
\r
226 m_bMouseRButtonDown = false;
\r
227 m_nCurrentButtonMask = 0;
\r
228 m_nMouseWheelDelta = 0;
\r
230 m_fCameraYawAngle = 0.0f;
\r
231 m_fCameraPitchAngle = 0.0f;
\r
233 SetRect( &m_rcDrag, LONG_MIN, LONG_MIN, LONG_MAX, LONG_MAX );
\r
234 m_vVelocity = D3DXVECTOR3( 0, 0, 0 );
\r
235 m_bMovementDrag = false;
\r
236 m_vVelocityDrag = D3DXVECTOR3( 0, 0, 0 );
\r
237 m_fDragTimer = 0.0f;
\r
238 m_fTotalDragTimeToZero = 0.25;
\r
239 m_vRotVelocity = D3DXVECTOR2( 0, 0 );
\r
241 m_fRotationScaler = 0.01f;
\r
242 m_fMoveScaler = 5.0f;
\r
244 m_bInvertPitch = false;
\r
245 m_bEnableYAxisMovement = true;
\r
246 m_bEnablePositionMovement = true;
\r
248 m_vMouseDelta = D3DXVECTOR2( 0, 0 );
\r
249 m_fFramesToSmoothMouseData = 2.0f;
\r
251 m_bClipToBoundary = false;
\r
252 m_vMinBoundary = D3DXVECTOR3( -1, -1, -1 );
\r
253 m_vMaxBoundary = D3DXVECTOR3( 1, 1, 1 );
\r
255 m_bResetCursorAfterMove = false;
\r
259 //--------------------------------------------------------------------------------------
\r
260 // Client can call this to change the position and direction of camera
\r
261 //--------------------------------------------------------------------------------------
\r
262 VOID CBaseCamera::SetViewParams( D3DXVECTOR3* pvEyePt, D3DXVECTOR3* pvLookatPt )
\r
264 if( NULL == pvEyePt || NULL == pvLookatPt )
\r
267 m_vDefaultEye = m_vEye = *pvEyePt;
\r
268 m_vDefaultLookAt = m_vLookAt = *pvLookatPt;
\r
270 // Calc the view matrix
\r
271 D3DXVECTOR3 vUp( 0,1,0 );
\r
272 D3DXMatrixLookAtLH( &m_mView, pvEyePt, pvLookatPt, &vUp );
\r
274 D3DXMATRIX mInvView;
\r
275 D3DXMatrixInverse( &mInvView, NULL, &m_mView );
\r
277 // The axis basis vectors and camera position are stored inside the
\r
278 // position matrix in the 4 rows of the camera's world matrix.
\r
279 // To figure out the yaw/pitch of the camera, we just need the Z basis vector
\r
280 D3DXVECTOR3* pZBasis = ( D3DXVECTOR3* )&mInvView._31;
\r
282 m_fCameraYawAngle = atan2f( pZBasis->x, pZBasis->z );
\r
283 float fLen = sqrtf( pZBasis->z * pZBasis->z + pZBasis->x * pZBasis->x );
\r
284 m_fCameraPitchAngle = -atan2f( pZBasis->y, fLen );
\r
290 //--------------------------------------------------------------------------------------
\r
291 // Calculates the projection matrix based on input params
\r
292 //--------------------------------------------------------------------------------------
\r
293 VOID CBaseCamera::SetProjParams( FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane,
\r
296 // Set attributes for the projection matrix
\r
298 m_fAspect = fAspect;
\r
299 m_fNearPlane = fNearPlane;
\r
300 m_fFarPlane = fFarPlane;
\r
302 D3DXMatrixPerspectiveFovLH( &m_mProj, fFOV, fAspect, fNearPlane, fFarPlane );
\r
308 //--------------------------------------------------------------------------------------
\r
309 // Call this from your message proc so this class can handle window messages
\r
310 //--------------------------------------------------------------------------------------
\r
311 LRESULT CBaseCamera::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
\r
313 UNREFERENCED_PARAMETER( hWnd );
\r
314 UNREFERENCED_PARAMETER( lParam );
\r
320 // Map this key to a D3DUtil_CameraKeys enum and update the
\r
321 // state of m_aKeys[] by adding the KEY_WAS_DOWN_MASK|KEY_IS_DOWN_MASK mask
\r
322 // only if the key is not down
\r
323 D3DUtil_CameraKeys mappedKey = MapKey( ( UINT )wParam );
\r
324 if( mappedKey != CAM_UNKNOWN )
\r
326 if( FALSE == IsKeyDown( m_aKeys[mappedKey] ) )
\r
328 m_aKeys[ mappedKey ] = KEY_WAS_DOWN_MASK | KEY_IS_DOWN_MASK;
\r
337 // Map this key to a D3DUtil_CameraKeys enum and update the
\r
338 // state of m_aKeys[] by removing the KEY_IS_DOWN_MASK mask.
\r
339 D3DUtil_CameraKeys mappedKey = MapKey( ( UINT )wParam );
\r
340 if( mappedKey != CAM_UNKNOWN && ( DWORD )mappedKey < 8 )
\r
342 m_aKeys[ mappedKey ] &= ~KEY_IS_DOWN_MASK;
\r
348 case WM_RBUTTONDOWN:
\r
349 case WM_MBUTTONDOWN:
\r
350 case WM_LBUTTONDOWN:
\r
351 case WM_RBUTTONDBLCLK:
\r
352 case WM_MBUTTONDBLCLK:
\r
353 case WM_LBUTTONDBLCLK:
\r
355 // Compute the drag rectangle in screen coord.
\r
358 ( short )LOWORD( lParam ), ( short )HIWORD( lParam )
\r
361 // Update member var state
\r
362 if( ( uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK ) && PtInRect( &m_rcDrag, ptCursor ) )
\r
364 m_bMouseLButtonDown = true; m_nCurrentButtonMask |= MOUSE_LEFT_BUTTON;
\r
366 if( ( uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONDBLCLK ) && PtInRect( &m_rcDrag, ptCursor ) )
\r
368 m_bMouseMButtonDown = true; m_nCurrentButtonMask |= MOUSE_MIDDLE_BUTTON;
\r
370 if( ( uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONDBLCLK ) && PtInRect( &m_rcDrag, ptCursor ) )
\r
372 m_bMouseRButtonDown = true; m_nCurrentButtonMask |= MOUSE_RIGHT_BUTTON;
\r
375 // Capture the mouse, so if the mouse button is
\r
376 // released outside the window, we'll get the WM_LBUTTONUP message
\r
377 SetCapture( hWnd );
\r
378 GetCursorPos( &m_ptLastMousePosition );
\r
386 // Update member var state
\r
387 if( uMsg == WM_LBUTTONUP )
\r
389 m_bMouseLButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_LEFT_BUTTON;
\r
391 if( uMsg == WM_MBUTTONUP )
\r
393 m_bMouseMButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_MIDDLE_BUTTON;
\r
395 if( uMsg == WM_RBUTTONUP )
\r
397 m_bMouseRButtonDown = false; m_nCurrentButtonMask &= ~MOUSE_RIGHT_BUTTON;
\r
400 // Release the capture if no mouse buttons down
\r
401 if( !m_bMouseLButtonDown &&
\r
402 !m_bMouseRButtonDown &&
\r
403 !m_bMouseMButtonDown )
\r
410 case WM_CAPTURECHANGED:
\r
412 if( ( HWND )lParam != hWnd )
\r
414 if( ( m_nCurrentButtonMask & MOUSE_LEFT_BUTTON ) ||
\r
415 ( m_nCurrentButtonMask & MOUSE_MIDDLE_BUTTON ) ||
\r
416 ( m_nCurrentButtonMask & MOUSE_RIGHT_BUTTON ) )
\r
418 m_bMouseLButtonDown = false;
\r
419 m_bMouseMButtonDown = false;
\r
420 m_bMouseRButtonDown = false;
\r
421 m_nCurrentButtonMask &= ~MOUSE_LEFT_BUTTON;
\r
422 m_nCurrentButtonMask &= ~MOUSE_MIDDLE_BUTTON;
\r
423 m_nCurrentButtonMask &= ~MOUSE_RIGHT_BUTTON;
\r
430 case WM_MOUSEWHEEL:
\r
431 // Update member var state
\r
432 m_nMouseWheelDelta += ( short )HIWORD( wParam );
\r
439 //--------------------------------------------------------------------------------------
\r
440 // Figure out the velocity based on keyboard input & drag if any
\r
441 //--------------------------------------------------------------------------------------
\r
442 void CBaseCamera::GetInput( bool bGetKeyboardInput, bool bGetMouseInput, bool bGetGamepadInput,
\r
443 bool bResetCursorAfterMove )
\r
445 m_vKeyboardDirection = D3DXVECTOR3( 0, 0, 0 );
\r
446 if( bGetKeyboardInput )
\r
448 // Update acceleration vector based on keyboard state
\r
449 if( IsKeyDown( m_aKeys[CAM_MOVE_FORWARD] ) )
\r
450 m_vKeyboardDirection.z += 1.0f;
\r
451 if( IsKeyDown( m_aKeys[CAM_MOVE_BACKWARD] ) )
\r
452 m_vKeyboardDirection.z -= 1.0f;
\r
453 if( m_bEnableYAxisMovement )
\r
455 if( IsKeyDown( m_aKeys[CAM_MOVE_UP] ) )
\r
456 m_vKeyboardDirection.y += 1.0f;
\r
457 if( IsKeyDown( m_aKeys[CAM_MOVE_DOWN] ) )
\r
458 m_vKeyboardDirection.y -= 1.0f;
\r
460 if( IsKeyDown( m_aKeys[CAM_STRAFE_RIGHT] ) )
\r
461 m_vKeyboardDirection.x += 1.0f;
\r
462 if( IsKeyDown( m_aKeys[CAM_STRAFE_LEFT] ) )
\r
463 m_vKeyboardDirection.x -= 1.0f;
\r
466 if( bGetMouseInput )
\r
468 UpdateMouseDelta();
\r
471 if( bGetGamepadInput )
\r
473 m_vGamePadLeftThumb = D3DXVECTOR3( 0, 0, 0 );
\r
474 m_vGamePadRightThumb = D3DXVECTOR3( 0, 0, 0 );
\r
476 // Get controller state
\r
477 for( DWORD iUserIndex = 0; iUserIndex < DXUT_MAX_CONTROLLERS; iUserIndex++ )
\r
479 DXUTGetGamepadState( iUserIndex, &m_GamePad[iUserIndex], true, true );
\r
481 // Mark time if the controller is in a non-zero state
\r
482 if( m_GamePad[iUserIndex].wButtons ||
\r
483 m_GamePad[iUserIndex].sThumbLX || m_GamePad[iUserIndex].sThumbLX ||
\r
484 m_GamePad[iUserIndex].sThumbRX || m_GamePad[iUserIndex].sThumbRY ||
\r
485 m_GamePad[iUserIndex].bLeftTrigger || m_GamePad[iUserIndex].bRightTrigger )
\r
487 m_GamePadLastActive[iUserIndex] = DXUTGetTime();
\r
491 // Find out which controller was non-zero last
\r
492 int iMostRecentlyActive = -1;
\r
493 double fMostRecentlyActiveTime = 0.0f;
\r
494 for( DWORD iUserIndex = 0; iUserIndex < DXUT_MAX_CONTROLLERS; iUserIndex++ )
\r
496 if( m_GamePadLastActive[iUserIndex] > fMostRecentlyActiveTime )
\r
498 fMostRecentlyActiveTime = m_GamePadLastActive[iUserIndex];
\r
499 iMostRecentlyActive = iUserIndex;
\r
503 // Use the most recent non-zero controller if its connected
\r
504 if( iMostRecentlyActive >= 0 && m_GamePad[iMostRecentlyActive].bConnected )
\r
506 m_vGamePadLeftThumb.x = m_GamePad[iMostRecentlyActive].fThumbLX;
\r
507 m_vGamePadLeftThumb.y = 0.0f;
\r
508 m_vGamePadLeftThumb.z = m_GamePad[iMostRecentlyActive].fThumbLY;
\r
510 m_vGamePadRightThumb.x = m_GamePad[iMostRecentlyActive].fThumbRX;
\r
511 m_vGamePadRightThumb.y = 0.0f;
\r
512 m_vGamePadRightThumb.z = m_GamePad[iMostRecentlyActive].fThumbRY;
\r
518 //--------------------------------------------------------------------------------------
\r
519 // Figure out the mouse delta based on mouse movement
\r
520 //--------------------------------------------------------------------------------------
\r
521 void CBaseCamera::UpdateMouseDelta()
\r
523 POINT ptCurMouseDelta;
\r
524 POINT ptCurMousePos;
\r
526 // Get current position of mouse
\r
527 GetCursorPos( &ptCurMousePos );
\r
529 // Calc how far it's moved since last frame
\r
530 ptCurMouseDelta.x = ptCurMousePos.x - m_ptLastMousePosition.x;
\r
531 ptCurMouseDelta.y = ptCurMousePos.y - m_ptLastMousePosition.y;
\r
533 // Record current position for next time
\r
534 m_ptLastMousePosition = ptCurMousePos;
\r
536 if( m_bResetCursorAfterMove && DXUTIsActive() )
\r
538 // Set position of camera to center of desktop,
\r
539 // so it always has room to move. This is very useful
\r
540 // if the cursor is hidden. If this isn't done and cursor is hidden,
\r
541 // then invisible cursor will hit the edge of the screen
\r
542 // and the user can't tell what happened
\r
545 // Get the center of the current monitor
\r
547 mi.cbSize = sizeof( MONITORINFO );
\r
548 DXUTGetMonitorInfo( DXUTMonitorFromWindow( DXUTGetHWND(), MONITOR_DEFAULTTONEAREST ), &mi );
\r
549 ptCenter.x = ( mi.rcMonitor.left + mi.rcMonitor.right ) / 2;
\r
550 ptCenter.y = ( mi.rcMonitor.top + mi.rcMonitor.bottom ) / 2;
\r
551 SetCursorPos( ptCenter.x, ptCenter.y );
\r
552 m_ptLastMousePosition = ptCenter;
\r
555 // Smooth the relative mouse data over a few frames so it isn't
\r
556 // jerky when moving slowly at low frame rates.
\r
557 float fPercentOfNew = 1.0f / m_fFramesToSmoothMouseData;
\r
558 float fPercentOfOld = 1.0f - fPercentOfNew;
\r
559 m_vMouseDelta.x = m_vMouseDelta.x * fPercentOfOld + ptCurMouseDelta.x * fPercentOfNew;
\r
560 m_vMouseDelta.y = m_vMouseDelta.y * fPercentOfOld + ptCurMouseDelta.y * fPercentOfNew;
\r
562 m_vRotVelocity = m_vMouseDelta * m_fRotationScaler;
\r
568 //--------------------------------------------------------------------------------------
\r
569 // Figure out the velocity based on keyboard input & drag if any
\r
570 //--------------------------------------------------------------------------------------
\r
571 void CBaseCamera::UpdateVelocity( float fElapsedTime )
\r
573 D3DXMATRIX mRotDelta;
\r
574 D3DXVECTOR2 vGamePadRightThumb = D3DXVECTOR2( m_vGamePadRightThumb.x, -m_vGamePadRightThumb.z );
\r
575 m_vRotVelocity = m_vMouseDelta * m_fRotationScaler + vGamePadRightThumb * 0.02f;
\r
577 D3DXVECTOR3 vAccel = m_vKeyboardDirection + m_vGamePadLeftThumb;
\r
579 // Normalize vector so if moving 2 dirs (left & forward),
\r
580 // the camera doesn't move faster than if moving in 1 dir
\r
581 D3DXVec3Normalize( &vAccel, &vAccel );
\r
583 // Scale the acceleration vector
\r
584 vAccel *= m_fMoveScaler;
\r
586 if( m_bMovementDrag )
\r
588 // Is there any acceleration this frame?
\r
589 if( D3DXVec3LengthSq( &vAccel ) > 0 )
\r
591 // If so, then this means the user has pressed a movement key\
\r
592 // so change the velocity immediately to acceleration
\r
593 // upon keyboard input. This isn't normal physics
\r
594 // but it will give a quick response to keyboard input
\r
595 m_vVelocity = vAccel;
\r
596 m_fDragTimer = m_fTotalDragTimeToZero;
\r
597 m_vVelocityDrag = vAccel / m_fDragTimer;
\r
601 // If no key being pressed, then slowly decrease velocity to 0
\r
602 if( m_fDragTimer > 0 )
\r
604 // Drag until timer is <= 0
\r
605 m_vVelocity -= m_vVelocityDrag * fElapsedTime;
\r
606 m_fDragTimer -= fElapsedTime;
\r
611 m_vVelocity = D3DXVECTOR3( 0, 0, 0 );
\r
617 // No drag, so immediately change the velocity
\r
618 m_vVelocity = vAccel;
\r
625 //--------------------------------------------------------------------------------------
\r
626 // Clamps pV to lie inside m_vMinBoundary & m_vMaxBoundary
\r
627 //--------------------------------------------------------------------------------------
\r
628 void CBaseCamera::ConstrainToBoundary( D3DXVECTOR3* pV )
\r
630 // Constrain vector to a bounding box
\r
631 pV->x = __max( pV->x, m_vMinBoundary.x );
\r
632 pV->y = __max( pV->y, m_vMinBoundary.y );
\r
633 pV->z = __max( pV->z, m_vMinBoundary.z );
\r
635 pV->x = __min( pV->x, m_vMaxBoundary.x );
\r
636 pV->y = __min( pV->y, m_vMaxBoundary.y );
\r
637 pV->z = __min( pV->z, m_vMaxBoundary.z );
\r
643 //--------------------------------------------------------------------------------------
\r
644 // Maps a windows virtual key to an enum
\r
645 //--------------------------------------------------------------------------------------
\r
646 D3DUtil_CameraKeys CBaseCamera::MapKey( UINT nKey )
\r
648 // This could be upgraded to a method that's user-definable but for
\r
649 // simplicity, we'll use a hardcoded mapping.
\r
653 return CAM_CONTROLDOWN;
\r
655 return CAM_STRAFE_LEFT;
\r
657 return CAM_STRAFE_RIGHT;
\r
659 return CAM_MOVE_FORWARD;
\r
661 return CAM_MOVE_BACKWARD;
\r
663 return CAM_MOVE_UP; // pgup
\r
665 return CAM_MOVE_DOWN; // pgdn
\r
668 return CAM_STRAFE_LEFT;
\r
670 return CAM_STRAFE_RIGHT;
\r
672 return CAM_MOVE_FORWARD;
\r
674 return CAM_MOVE_BACKWARD;
\r
676 return CAM_MOVE_DOWN;
\r
678 return CAM_MOVE_UP;
\r
681 return CAM_STRAFE_LEFT;
\r
683 return CAM_STRAFE_RIGHT;
\r
685 return CAM_MOVE_FORWARD;
\r
687 return CAM_MOVE_BACKWARD;
\r
689 return CAM_MOVE_UP;
\r
691 return CAM_MOVE_DOWN;
\r
697 return CAM_UNKNOWN;
\r
703 //--------------------------------------------------------------------------------------
\r
704 // Reset the camera's position back to the default
\r
705 //--------------------------------------------------------------------------------------
\r
706 VOID CBaseCamera::Reset()
\r
708 SetViewParams( &m_vDefaultEye, &m_vDefaultLookAt );
\r
714 //--------------------------------------------------------------------------------------
\r
716 //--------------------------------------------------------------------------------------
\r
717 CFirstPersonCamera::CFirstPersonCamera() : m_nActiveButtonMask( 0x07 )
\r
719 m_bRotateWithoutButtonDown = false;
\r
725 //--------------------------------------------------------------------------------------
\r
726 // Update the view matrix based on user input & elapsed time
\r
727 //--------------------------------------------------------------------------------------
\r
728 VOID CFirstPersonCamera::FrameMove( FLOAT fElapsedTime )
\r
730 if( DXUTGetGlobalTimer()->IsStopped() ) {
\r
731 if (DXUTGetFPS() == 0.0f) fElapsedTime = 0;
\r
732 else fElapsedTime = 1.0f / DXUTGetFPS();
\r
735 if( IsKeyDown( m_aKeys[CAM_RESET] ) )
\r
738 // Get keyboard/mouse/gamepad input
\r
739 GetInput( m_bEnablePositionMovement, ( m_nActiveButtonMask & m_nCurrentButtonMask ) || m_bRotateWithoutButtonDown,
\r
740 true, m_bResetCursorAfterMove );
\r
742 //// Get the mouse movement (if any) if the mouse button are down
\r
743 //if( (m_nActiveButtonMask & m_nCurrentButtonMask) || m_bRotateWithoutButtonDown )
\r
744 // UpdateMouseDelta( fElapsedTime );
\r
746 // Get amount of velocity based on the keyboard input and drag (if any)
\r
747 UpdateVelocity( fElapsedTime );
\r
749 // Simple euler method to calculate position delta
\r
750 D3DXVECTOR3 vPosDelta = m_vVelocity * fElapsedTime;
\r
752 // If rotating the camera
\r
753 if( ( m_nActiveButtonMask & m_nCurrentButtonMask ) ||
\r
754 m_bRotateWithoutButtonDown ||
\r
755 m_vGamePadRightThumb.x != 0 ||
\r
756 m_vGamePadRightThumb.z != 0 )
\r
758 // Update the pitch & yaw angle based on mouse movement
\r
759 float fYawDelta = m_vRotVelocity.x;
\r
760 float fPitchDelta = m_vRotVelocity.y;
\r
762 // Invert pitch if requested
\r
763 if( m_bInvertPitch )
\r
764 fPitchDelta = -fPitchDelta;
\r
766 m_fCameraPitchAngle += fPitchDelta;
\r
767 m_fCameraYawAngle += fYawDelta;
\r
769 // Limit pitch to straight up or straight down
\r
770 m_fCameraPitchAngle = __max( -D3DX_PI / 2.0f, m_fCameraPitchAngle );
\r
771 m_fCameraPitchAngle = __min( +D3DX_PI / 2.0f, m_fCameraPitchAngle );
\r
774 // Make a rotation matrix based on the camera's yaw & pitch
\r
775 D3DXMATRIX mCameraRot;
\r
776 D3DXMatrixRotationYawPitchRoll( &mCameraRot, m_fCameraYawAngle, m_fCameraPitchAngle, 0 );
\r
778 // Transform vectors based on camera's rotation matrix
\r
779 D3DXVECTOR3 vWorldUp, vWorldAhead;
\r
780 D3DXVECTOR3 vLocalUp = D3DXVECTOR3( 0, 1, 0 );
\r
781 D3DXVECTOR3 vLocalAhead = D3DXVECTOR3( 0, 0, 1 );
\r
782 D3DXVec3TransformCoord( &vWorldUp, &vLocalUp, &mCameraRot );
\r
783 D3DXVec3TransformCoord( &vWorldAhead, &vLocalAhead, &mCameraRot );
\r
785 // Transform the position delta by the camera's rotation
\r
786 D3DXVECTOR3 vPosDeltaWorld;
\r
787 if( !m_bEnableYAxisMovement )
\r
789 // If restricting Y movement, do not include pitch
\r
790 // when transforming position delta vector.
\r
791 D3DXMatrixRotationYawPitchRoll( &mCameraRot, m_fCameraYawAngle, 0.0f, 0.0f );
\r
793 D3DXVec3TransformCoord( &vPosDeltaWorld, &vPosDelta, &mCameraRot );
\r
795 // Move the eye position
\r
796 m_vEye += vPosDeltaWorld;
\r
797 if( m_bClipToBoundary )
\r
798 ConstrainToBoundary( &m_vEye );
\r
800 // Update the lookAt position based on the eye position
\r
801 m_vLookAt = m_vEye + vWorldAhead;
\r
803 // Update the view matrix
\r
804 D3DXMatrixLookAtLH( &m_mView, &m_vEye, &m_vLookAt, &vWorldUp );
\r
806 D3DXMatrixInverse( &m_mCameraWorld, NULL, &m_mView );
\r
810 //--------------------------------------------------------------------------------------
\r
811 // Enable or disable each of the mouse buttons for rotation drag.
\r
812 //--------------------------------------------------------------------------------------
\r
813 void CFirstPersonCamera::SetRotateButtons( bool bLeft, bool bMiddle, bool bRight, bool bRotateWithoutButtonDown )
\r
815 m_nActiveButtonMask = ( bLeft ? MOUSE_LEFT_BUTTON : 0 ) |
\r
816 ( bMiddle ? MOUSE_MIDDLE_BUTTON : 0 ) |
\r
817 ( bRight ? MOUSE_RIGHT_BUTTON : 0 );
\r
818 m_bRotateWithoutButtonDown = bRotateWithoutButtonDown;
\r
822 //--------------------------------------------------------------------------------------
\r
824 //--------------------------------------------------------------------------------------
\r
825 CModelViewerCamera::CModelViewerCamera()
\r
827 D3DXMatrixIdentity( &m_mWorld );
\r
828 D3DXMatrixIdentity( &m_mModelRot );
\r
829 D3DXMatrixIdentity( &m_mModelLastRot );
\r
830 D3DXMatrixIdentity( &m_mCameraRotLast );
\r
831 m_vModelCenter = D3DXVECTOR3( 0, 0, 0 );
\r
833 m_fDefaultRadius = 5.0f;
\r
834 m_fMinRadius = 1.0f;
\r
835 m_fMaxRadius = FLT_MAX;
\r
836 m_bLimitPitch = false;
\r
837 m_bEnablePositionMovement = false;
\r
838 m_bAttachCameraToModel = false;
\r
840 m_nRotateModelButtonMask = MOUSE_LEFT_BUTTON;
\r
841 m_nZoomButtonMask = MOUSE_WHEEL;
\r
842 m_nRotateCameraButtonMask = MOUSE_RIGHT_BUTTON;
\r
843 m_bDragSinceLastUpdate = true;
\r
849 //--------------------------------------------------------------------------------------
\r
850 // Update the view matrix & the model's world matrix based
\r
851 // on user input & elapsed time
\r
852 //--------------------------------------------------------------------------------------
\r
853 VOID CModelViewerCamera::FrameMove( FLOAT fElapsedTime )
\r
855 if( IsKeyDown( m_aKeys[CAM_RESET] ) )
\r
858 // If no dragged has happend since last time FrameMove is called,
\r
859 // and no camera key is held down, then no need to handle again.
\r
860 if( !m_bDragSinceLastUpdate && 0 == m_cKeysDown )
\r
862 m_bDragSinceLastUpdate = false;
\r
864 //// If no mouse button is held down,
\r
865 //// Get the mouse movement (if any) if the mouse button are down
\r
866 //if( m_nCurrentButtonMask != 0 )
\r
867 // UpdateMouseDelta( fElapsedTime );
\r
869 GetInput( m_bEnablePositionMovement, m_nCurrentButtonMask != 0, true, false );
\r
871 // Get amount of velocity based on the keyboard input and drag (if any)
\r
872 UpdateVelocity( fElapsedTime );
\r
874 // Simple euler method to calculate position delta
\r
875 D3DXVECTOR3 vPosDelta = m_vVelocity * fElapsedTime;
\r
877 // Change the radius from the camera to the model based on wheel scrolling
\r
878 if( m_nMouseWheelDelta && m_nZoomButtonMask == MOUSE_WHEEL )
\r
879 m_fRadius -= m_nMouseWheelDelta * m_fRadius * 0.1f / 120.0f;
\r
880 m_fRadius = __min( m_fMaxRadius, m_fRadius );
\r
881 m_fRadius = __max( m_fMinRadius, m_fRadius );
\r
882 m_nMouseWheelDelta = 0;
\r
884 // Get the inverse of the arcball's rotation matrix
\r
885 D3DXMATRIX mCameraRot;
\r
886 D3DXMatrixInverse( &mCameraRot, NULL, m_ViewArcBall.GetRotationMatrix() );
\r
888 // Transform vectors based on camera's rotation matrix
\r
889 D3DXVECTOR3 vWorldUp, vWorldAhead;
\r
890 D3DXVECTOR3 vLocalUp = D3DXVECTOR3( 0, 1, 0 );
\r
891 D3DXVECTOR3 vLocalAhead = D3DXVECTOR3( 0, 0, 1 );
\r
892 D3DXVec3TransformCoord( &vWorldUp, &vLocalUp, &mCameraRot );
\r
893 D3DXVec3TransformCoord( &vWorldAhead, &vLocalAhead, &mCameraRot );
\r
895 // Transform the position delta by the camera's rotation
\r
896 D3DXVECTOR3 vPosDeltaWorld;
\r
897 D3DXVec3TransformCoord( &vPosDeltaWorld, &vPosDelta, &mCameraRot );
\r
899 // Move the lookAt position
\r
900 m_vLookAt += vPosDeltaWorld;
\r
901 if( m_bClipToBoundary )
\r
902 ConstrainToBoundary( &m_vLookAt );
\r
904 // Update the eye point based on a radius away from the lookAt position
\r
905 m_vEye = m_vLookAt - vWorldAhead * m_fRadius;
\r
907 // Update the view matrix
\r
908 D3DXMatrixLookAtLH( &m_mView, &m_vEye, &m_vLookAt, &vWorldUp );
\r
910 D3DXMATRIX mInvView;
\r
911 D3DXMatrixInverse( &mInvView, NULL, &m_mView );
\r
912 mInvView._41 = mInvView._42 = mInvView._43 = 0;
\r
914 D3DXMATRIX mModelLastRotInv;
\r
915 D3DXMatrixInverse( &mModelLastRotInv, NULL, &m_mModelLastRot );
\r
917 // Accumulate the delta of the arcball's rotation in view space.
\r
918 // Note that per-frame delta rotations could be problematic over long periods of time.
\r
919 D3DXMATRIX mModelRot;
\r
920 mModelRot = *m_WorldArcBall.GetRotationMatrix();
\r
921 m_mModelRot *= m_mView * mModelLastRotInv * mModelRot * mInvView;
\r
923 if( m_ViewArcBall.IsBeingDragged() && m_bAttachCameraToModel && !IsKeyDown( m_aKeys[CAM_CONTROLDOWN] ) )
\r
925 // Attach camera to model by inverse of the model rotation
\r
926 D3DXMATRIX mCameraLastRotInv;
\r
927 D3DXMatrixInverse( &mCameraLastRotInv, NULL, &m_mCameraRotLast );
\r
928 D3DXMATRIX mCameraRotDelta = mCameraLastRotInv * mCameraRot; // local to world matrix
\r
929 m_mModelRot *= mCameraRotDelta;
\r
931 m_mCameraRotLast = mCameraRot;
\r
933 m_mModelLastRot = mModelRot;
\r
935 // Since we're accumulating delta rotations, we need to orthonormalize
\r
936 // the matrix to prevent eventual matrix skew
\r
937 D3DXVECTOR3* pXBasis = ( D3DXVECTOR3* )&m_mModelRot._11;
\r
938 D3DXVECTOR3* pYBasis = ( D3DXVECTOR3* )&m_mModelRot._21;
\r
939 D3DXVECTOR3* pZBasis = ( D3DXVECTOR3* )&m_mModelRot._31;
\r
940 D3DXVec3Normalize( pXBasis, pXBasis );
\r
941 D3DXVec3Cross( pYBasis, pZBasis, pXBasis );
\r
942 D3DXVec3Normalize( pYBasis, pYBasis );
\r
943 D3DXVec3Cross( pZBasis, pXBasis, pYBasis );
\r
945 // Translate the rotation matrix to the same position as the lookAt position
\r
946 m_mModelRot._41 = m_vLookAt.x;
\r
947 m_mModelRot._42 = m_vLookAt.y;
\r
948 m_mModelRot._43 = m_vLookAt.z;
\r
950 // Translate world matrix so its at the center of the model
\r
952 D3DXMatrixTranslation( &mTrans, -m_vModelCenter.x, -m_vModelCenter.y, -m_vModelCenter.z );
\r
953 m_mWorld = mTrans * m_mModelRot;
\r
957 void CModelViewerCamera::SetDragRect( RECT& rc )
\r
959 CBaseCamera::SetDragRect( rc );
\r
961 m_WorldArcBall.SetOffset( rc.left, rc.top );
\r
962 m_ViewArcBall.SetOffset( rc.left, rc.top );
\r
963 SetWindow( rc.right - rc.left, rc.bottom - rc.top );
\r
967 //--------------------------------------------------------------------------------------
\r
968 // Reset the camera's position back to the default
\r
969 //--------------------------------------------------------------------------------------
\r
970 VOID CModelViewerCamera::Reset()
\r
972 CBaseCamera::Reset();
\r
974 D3DXMatrixIdentity( &m_mWorld );
\r
975 D3DXMatrixIdentity( &m_mModelRot );
\r
976 D3DXMatrixIdentity( &m_mModelLastRot );
\r
977 D3DXMatrixIdentity( &m_mCameraRotLast );
\r
979 m_fRadius = m_fDefaultRadius;
\r
980 m_WorldArcBall.Reset();
\r
981 m_ViewArcBall.Reset();
\r
985 //--------------------------------------------------------------------------------------
\r
986 // Override for setting the view parameters
\r
987 //--------------------------------------------------------------------------------------
\r
988 void CModelViewerCamera::SetViewParams( D3DXVECTOR3* pvEyePt, D3DXVECTOR3* pvLookatPt )
\r
990 CBaseCamera::SetViewParams( pvEyePt, pvLookatPt );
\r
992 // Propogate changes to the member arcball
\r
993 D3DXQUATERNION quat;
\r
994 D3DXMATRIXA16 mRotation;
\r
995 D3DXVECTOR3 vUp( 0,1,0 );
\r
996 D3DXMatrixLookAtLH( &mRotation, pvEyePt, pvLookatPt, &vUp );
\r
997 D3DXQuaternionRotationMatrix( &quat, &mRotation );
\r
998 m_ViewArcBall.SetQuatNow( quat );
\r
1000 // Set the radius according to the distance
\r
1001 D3DXVECTOR3 vEyeToPoint;
\r
1002 D3DXVec3Subtract( &vEyeToPoint, pvLookatPt, pvEyePt );
\r
1003 SetRadius( D3DXVec3Length( &vEyeToPoint ) );
\r
1005 // View information changed. FrameMove should be called.
\r
1006 m_bDragSinceLastUpdate = true;
\r
1011 //--------------------------------------------------------------------------------------
\r
1012 // Call this from your message proc so this class can handle window messages
\r
1013 //--------------------------------------------------------------------------------------
\r
1014 LRESULT CModelViewerCamera::HandleMessages( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
\r
1016 CBaseCamera::HandleMessages( hWnd, uMsg, wParam, lParam );
\r
1018 if( ( ( uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK ) && m_nRotateModelButtonMask & MOUSE_LEFT_BUTTON ) ||
\r
1019 ( ( uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONDBLCLK ) && m_nRotateModelButtonMask & MOUSE_MIDDLE_BUTTON ) ||
\r
1020 ( ( uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONDBLCLK ) && m_nRotateModelButtonMask & MOUSE_RIGHT_BUTTON ) )
\r
1022 int iMouseX = ( short )LOWORD( lParam );
\r
1023 int iMouseY = ( short )HIWORD( lParam );
\r
1024 m_WorldArcBall.OnBegin( iMouseX, iMouseY );
\r
1027 if( ( ( uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK ) && m_nRotateCameraButtonMask & MOUSE_LEFT_BUTTON ) ||
\r
1028 ( ( uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONDBLCLK ) &&
\r
1029 m_nRotateCameraButtonMask & MOUSE_MIDDLE_BUTTON ) ||
\r
1030 ( ( uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONDBLCLK ) && m_nRotateCameraButtonMask & MOUSE_RIGHT_BUTTON ) )
\r
1032 int iMouseX = ( short )LOWORD( lParam );
\r
1033 int iMouseY = ( short )HIWORD( lParam );
\r
1034 m_ViewArcBall.OnBegin( iMouseX, iMouseY );
\r
1037 if( uMsg == WM_MOUSEMOVE )
\r
1039 int iMouseX = ( short )LOWORD( lParam );
\r
1040 int iMouseY = ( short )HIWORD( lParam );
\r
1041 m_WorldArcBall.OnMove( iMouseX, iMouseY );
\r
1042 m_ViewArcBall.OnMove( iMouseX, iMouseY );
\r
1045 if( ( uMsg == WM_LBUTTONUP && m_nRotateModelButtonMask & MOUSE_LEFT_BUTTON ) ||
\r
1046 ( uMsg == WM_MBUTTONUP && m_nRotateModelButtonMask & MOUSE_MIDDLE_BUTTON ) ||
\r
1047 ( uMsg == WM_RBUTTONUP && m_nRotateModelButtonMask & MOUSE_RIGHT_BUTTON ) )
\r
1049 m_WorldArcBall.OnEnd();
\r
1052 if( ( uMsg == WM_LBUTTONUP && m_nRotateCameraButtonMask & MOUSE_LEFT_BUTTON ) ||
\r
1053 ( uMsg == WM_MBUTTONUP && m_nRotateCameraButtonMask & MOUSE_MIDDLE_BUTTON ) ||
\r
1054 ( uMsg == WM_RBUTTONUP && m_nRotateCameraButtonMask & MOUSE_RIGHT_BUTTON ) )
\r
1056 m_ViewArcBall.OnEnd();
\r
1059 if( uMsg == WM_CAPTURECHANGED )
\r
1061 if( ( HWND )lParam != hWnd )
\r
1063 if( ( m_nRotateModelButtonMask & MOUSE_LEFT_BUTTON ) ||
\r
1064 ( m_nRotateModelButtonMask & MOUSE_MIDDLE_BUTTON ) ||
\r
1065 ( m_nRotateModelButtonMask & MOUSE_RIGHT_BUTTON ) )
\r
1067 m_WorldArcBall.OnEnd();
\r
1070 if( ( m_nRotateCameraButtonMask & MOUSE_LEFT_BUTTON ) ||
\r
1071 ( m_nRotateCameraButtonMask & MOUSE_MIDDLE_BUTTON ) ||
\r
1072 ( m_nRotateCameraButtonMask & MOUSE_RIGHT_BUTTON ) )
\r
1074 m_ViewArcBall.OnEnd();
\r
1079 if( uMsg == WM_LBUTTONDOWN ||
\r
1080 uMsg == WM_LBUTTONDBLCLK ||
\r
1081 uMsg == WM_MBUTTONDOWN ||
\r
1082 uMsg == WM_MBUTTONDBLCLK ||
\r
1083 uMsg == WM_RBUTTONDOWN ||
\r
1084 uMsg == WM_RBUTTONDBLCLK ||
\r
1085 uMsg == WM_LBUTTONUP ||
\r
1086 uMsg == WM_MBUTTONUP ||
\r
1087 uMsg == WM_RBUTTONUP ||
\r
1088 uMsg == WM_MOUSEWHEEL ||
\r
1089 uMsg == WM_MOUSEMOVE )
\r
1091 m_bDragSinceLastUpdate = true;
\r
1099 //--------------------------------------------------------------------------------------
\r
1101 IDirect3DDevice9* CDXUTDirectionWidget::s_pd3d9Device = NULL;
\r
1102 ID3DXEffect* CDXUTDirectionWidget::s_pD3D9Effect = NULL;
\r
1103 ID3DXMesh* CDXUTDirectionWidget::s_pD3D9Mesh = NULL;
\r
1104 D3DXHANDLE CDXUTDirectionWidget::s_hRenderWith1LightNoTexture = NULL;
\r
1105 D3DXHANDLE CDXUTDirectionWidget::s_hMaterialDiffuseColor = NULL;
\r
1106 D3DXHANDLE CDXUTDirectionWidget::s_hLightDir = NULL;
\r
1107 D3DXHANDLE CDXUTDirectionWidget::s_hWorldViewProjection = NULL;
\r
1108 D3DXHANDLE CDXUTDirectionWidget::s_hWorld = NULL;
\r
1111 //--------------------------------------------------------------------------------------
\r
1112 CDXUTDirectionWidget::CDXUTDirectionWidget()
\r
1115 m_vDefaultDir = D3DXVECTOR3( 0, 1, 0 );
\r
1116 m_vCurrentDir = m_vDefaultDir;
\r
1117 m_nRotateMask = MOUSE_RIGHT_BUTTON;
\r
1119 D3DXMatrixIdentity( &m_mView );
\r
1120 D3DXMatrixIdentity( &m_mRot );
\r
1121 D3DXMatrixIdentity( &m_mRotSnapshot );
\r
1125 //--------------------------------------------------------------------------------------
\r
1126 HRESULT CDXUTDirectionWidget::StaticOnD3D9CreateDevice( IDirect3DDevice9* pd3dDevice )
\r
1130 s_pd3d9Device = pd3dDevice;
\r
1132 const char* g_strBuffer =
\r
1133 "float4 g_MaterialDiffuseColor; // Material's diffuse color\r\n"
\r
1134 "float3 g_LightDir; // Light's direction in world space\r\n"
\r
1135 "float4x4 g_mWorld; // World matrix for object\r\n"
\r
1136 "float4x4 g_mWorldViewProjection; // World * View * Projection matrix\r\n"
\r
1138 "struct VS_OUTPUT\r\n"
\r
1140 " float4 Position : POSITION; // vertex position\r\n"
\r
1141 " float4 Diffuse : COLOR0; // vertex diffuse color\r\n"
\r
1144 "VS_OUTPUT RenderWith1LightNoTextureVS( float4 vPos : POSITION,\r\n"
\r
1145 " float3 vNormal : NORMAL )\r\n"
\r
1147 " VS_OUTPUT Output;\r\n"
\r
1149 " // Transform the position from object space to homogeneous projection space\r\n"
\r
1150 " Output.Position = mul(vPos, g_mWorldViewProjection);\r\n"
\r
1152 " // Transform the normal from object space to world space\r\n"
\r
1153 " float3 vNormalWorldSpace;\r\n"
\r
1154 " vNormalWorldSpace = normalize(mul(vNormal, (float3x3)g_mWorld)); // normal (world space)\r\n"
\r
1156 " // Compute simple directional lighting equation\r\n"
\r
1157 " Output.Diffuse.rgb = g_MaterialDiffuseColor * max(0,dot(vNormalWorldSpace, g_LightDir));\r\n"
\r
1158 " Output.Diffuse.a = 1.0f;\r\n"
\r
1160 " return Output;\r\n"
\r
1163 "float4 RenderWith1LightNoTexturePS( float4 Diffuse : COLOR0 ) : COLOR0\r\n"
\r
1165 " return Diffuse;\r\n"
\r
1168 "technique RenderWith1LightNoTexture\r\n"
\r
1172 " VertexShader = compile vs_2_0 RenderWith1LightNoTextureVS();\r\n"
\r
1173 " PixelShader = compile ps_2_0 RenderWith1LightNoTexturePS();\r\n"
\r
1178 UINT dwBufferSize = ( UINT )strlen( g_strBuffer ) + 1;
\r
1180 V_RETURN( D3DXCreateEffect( s_pd3d9Device, g_strBuffer, dwBufferSize, NULL, NULL, D3DXFX_NOT_CLONEABLE,
\r
1181 NULL, &s_pD3D9Effect, NULL ) );
\r
1183 // Save technique handles for use when rendering
\r
1184 s_hRenderWith1LightNoTexture = s_pD3D9Effect->GetTechniqueByName( "RenderWith1LightNoTexture" );
\r
1185 s_hMaterialDiffuseColor = s_pD3D9Effect->GetParameterByName( NULL, "g_MaterialDiffuseColor" );
\r
1186 s_hLightDir = s_pD3D9Effect->GetParameterByName( NULL, "g_LightDir" );
\r
1187 s_hWorld = s_pD3D9Effect->GetParameterByName( NULL, "g_mWorld" );
\r
1188 s_hWorldViewProjection = s_pD3D9Effect->GetParameterByName( NULL, "g_mWorldViewProjection" );
\r
1190 // Load the mesh with D3DX and get back a ID3DXMesh*. For this
\r
1191 // sample we'll ignore the X file's embedded materials since we know
\r
1192 // exactly the model we're loading. See the mesh samples such as
\r
1193 // "OptimizedMesh" for a more generic mesh loading example.
\r
1194 V_RETURN( DXUTCreateArrowMeshFromInternalArray( s_pd3d9Device, &s_pD3D9Mesh ) );
\r
1196 // Optimize the mesh for this graphics card's vertex cache
\r
1197 // so when rendering the mesh's triangle list the vertices will
\r
1198 // cache hit more often so it won't have to re-execute the vertex shader
\r
1199 // on those vertices so it will improve perf.
\r
1200 DWORD* rgdwAdjacency = new DWORD[s_pD3D9Mesh->GetNumFaces() * 3];
\r
1201 if( rgdwAdjacency == NULL )
\r
1202 return E_OUTOFMEMORY;
\r
1203 V( s_pD3D9Mesh->GenerateAdjacency( 1e-6f, rgdwAdjacency ) );
\r
1204 V( s_pD3D9Mesh->OptimizeInplace( D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL ) );
\r
1205 delete []rgdwAdjacency;
\r
1211 //--------------------------------------------------------------------------------------
\r
1212 HRESULT CDXUTDirectionWidget::OnD3D9ResetDevice( const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
\r
1214 m_ArcBall.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
\r
1219 //--------------------------------------------------------------------------------------
\r
1220 void CDXUTDirectionWidget::StaticOnD3D9LostDevice()
\r
1222 if( s_pD3D9Effect )
\r
1223 s_pD3D9Effect->OnLostDevice();
\r
1227 //--------------------------------------------------------------------------------------
\r
1228 void CDXUTDirectionWidget::StaticOnD3D9DestroyDevice()
\r
1230 SAFE_RELEASE( s_pD3D9Effect );
\r
1231 SAFE_RELEASE( s_pD3D9Mesh );
\r
1235 //--------------------------------------------------------------------------------------
\r
1236 LRESULT CDXUTDirectionWidget::HandleMessages( HWND hWnd, UINT uMsg,
\r
1237 WPARAM wParam, LPARAM lParam )
\r
1241 case WM_LBUTTONDOWN:
\r
1242 case WM_MBUTTONDOWN:
\r
1243 case WM_RBUTTONDOWN:
\r
1245 if( ( ( m_nRotateMask & MOUSE_LEFT_BUTTON ) != 0 && uMsg == WM_LBUTTONDOWN ) ||
\r
1246 ( ( m_nRotateMask & MOUSE_MIDDLE_BUTTON ) != 0 && uMsg == WM_MBUTTONDOWN ) ||
\r
1247 ( ( m_nRotateMask & MOUSE_RIGHT_BUTTON ) != 0 && uMsg == WM_RBUTTONDOWN ) )
\r
1249 int iMouseX = ( int )( short )LOWORD( lParam );
\r
1250 int iMouseY = ( int )( short )HIWORD( lParam );
\r
1251 m_ArcBall.OnBegin( iMouseX, iMouseY );
\r
1252 SetCapture( hWnd );
\r
1257 case WM_MOUSEMOVE:
\r
1259 if( m_ArcBall.IsBeingDragged() )
\r
1261 int iMouseX = ( int )( short )LOWORD( lParam );
\r
1262 int iMouseY = ( int )( short )HIWORD( lParam );
\r
1263 m_ArcBall.OnMove( iMouseX, iMouseY );
\r
1269 case WM_LBUTTONUP:
\r
1270 case WM_MBUTTONUP:
\r
1271 case WM_RBUTTONUP:
\r
1273 if( ( ( m_nRotateMask & MOUSE_LEFT_BUTTON ) != 0 && uMsg == WM_LBUTTONUP ) ||
\r
1274 ( ( m_nRotateMask & MOUSE_MIDDLE_BUTTON ) != 0 && uMsg == WM_MBUTTONUP ) ||
\r
1275 ( ( m_nRotateMask & MOUSE_RIGHT_BUTTON ) != 0 && uMsg == WM_RBUTTONUP ) )
\r
1277 m_ArcBall.OnEnd();
\r
1285 case WM_CAPTURECHANGED:
\r
1287 if( ( HWND )lParam != hWnd )
\r
1289 if( ( m_nRotateMask & MOUSE_LEFT_BUTTON ) ||
\r
1290 ( m_nRotateMask & MOUSE_MIDDLE_BUTTON ) ||
\r
1291 ( m_nRotateMask & MOUSE_RIGHT_BUTTON ) )
\r
1293 m_ArcBall.OnEnd();
\r
1305 //--------------------------------------------------------------------------------------
\r
1306 HRESULT CDXUTDirectionWidget::OnRender9( D3DXCOLOR color, const D3DXMATRIX* pmView,
\r
1307 const D3DXMATRIX* pmProj, const D3DXVECTOR3* pEyePt )
\r
1309 m_mView = *pmView;
\r
1311 // Render the light spheres so the user can visually see the light dir
\r
1312 UINT iPass, cPasses;
\r
1313 D3DXMATRIX mRotate;
\r
1314 D3DXMATRIX mScale;
\r
1315 D3DXMATRIX mTrans;
\r
1316 D3DXMATRIXA16 mWorldViewProj;
\r
1319 V( s_pD3D9Effect->SetTechnique( s_hRenderWith1LightNoTexture ) );
\r
1320 V( s_pD3D9Effect->SetVector( s_hMaterialDiffuseColor, ( D3DXVECTOR4* )&color ) );
\r
1322 D3DXVECTOR3 vEyePt;
\r
1323 D3DXVec3Normalize( &vEyePt, pEyePt );
\r
1324 V( s_pD3D9Effect->SetValue( s_hLightDir, &vEyePt, sizeof( D3DXVECTOR3 ) ) );
\r
1326 // Rotate arrow model to point towards origin
\r
1327 D3DXMATRIX mRotateA, mRotateB;
\r
1328 D3DXVECTOR3 vAt = D3DXVECTOR3( 0, 0, 0 );
\r
1329 D3DXVECTOR3 vUp = D3DXVECTOR3( 0, 1, 0 );
\r
1330 D3DXMatrixRotationX( &mRotateB, D3DX_PI );
\r
1331 D3DXMatrixLookAtLH( &mRotateA, &m_vCurrentDir, &vAt, &vUp );
\r
1332 D3DXMatrixInverse( &mRotateA, NULL, &mRotateA );
\r
1333 mRotate = mRotateB * mRotateA;
\r
1335 D3DXVECTOR3 vL = m_vCurrentDir * m_fRadius * 1.0f;
\r
1336 D3DXMatrixTranslation( &mTrans, vL.x, vL.y, vL.z );
\r
1337 D3DXMatrixScaling( &mScale, m_fRadius * 0.2f, m_fRadius * 0.2f, m_fRadius * 0.2f );
\r
1339 D3DXMATRIX mWorld = mRotate * mScale * mTrans;
\r
1340 mWorldViewProj = mWorld * ( m_mView )*( *pmProj );
\r
1342 V( s_pD3D9Effect->SetMatrix( s_hWorldViewProjection, &mWorldViewProj ) );
\r
1343 V( s_pD3D9Effect->SetMatrix( s_hWorld, &mWorld ) );
\r
1345 for( int iSubset = 0; iSubset < 2; iSubset++ )
\r
1347 V( s_pD3D9Effect->Begin( &cPasses, 0 ) );
\r
1348 for( iPass = 0; iPass < cPasses; iPass++ )
\r
1350 V( s_pD3D9Effect->BeginPass( iPass ) );
\r
1351 V( s_pD3D9Mesh->DrawSubset( iSubset ) );
\r
1352 V( s_pD3D9Effect->EndPass() );
\r
1354 V( s_pD3D9Effect->End() );
\r
1360 //--------------------------------------------------------------------------------------
\r
1361 HRESULT CDXUTDirectionWidget::UpdateLightDir()
\r
1363 D3DXMATRIX mInvView;
\r
1364 D3DXMatrixInverse( &mInvView, NULL, &m_mView );
\r
1365 mInvView._41 = mInvView._42 = mInvView._43 = 0;
\r
1367 D3DXMATRIX mLastRotInv;
\r
1368 D3DXMatrixInverse( &mLastRotInv, NULL, &m_mRotSnapshot );
\r
1370 D3DXMATRIX mRot = *m_ArcBall.GetRotationMatrix();
\r
1371 m_mRotSnapshot = mRot;
\r
1373 // Accumulate the delta of the arcball's rotation in view space.
\r
1374 // Note that per-frame delta rotations could be problematic over long periods of time.
\r
1375 m_mRot *= m_mView * mLastRotInv * mRot * mInvView;
\r
1377 // Since we're accumulating delta rotations, we need to orthonormalize
\r
1378 // the matrix to prevent eventual matrix skew
\r
1379 D3DXVECTOR3* pXBasis = ( D3DXVECTOR3* )&m_mRot._11;
\r
1380 D3DXVECTOR3* pYBasis = ( D3DXVECTOR3* )&m_mRot._21;
\r
1381 D3DXVECTOR3* pZBasis = ( D3DXVECTOR3* )&m_mRot._31;
\r
1382 D3DXVec3Normalize( pXBasis, pXBasis );
\r
1383 D3DXVec3Cross( pYBasis, pZBasis, pXBasis );
\r
1384 D3DXVec3Normalize( pYBasis, pYBasis );
\r
1385 D3DXVec3Cross( pZBasis, pXBasis, pYBasis );
\r
1387 // Transform the default direction vector by the light's rotation matrix
\r
1388 D3DXVec3TransformNormal( &m_vCurrentDir, &m_vDefaultDir, &m_mRot );
\r
1393 //--------------------------------------------------------------------------------------
\r
1394 HRESULT CDXUTDirectionWidget::StaticOnD3D11CreateDevice( ID3D11Device* pd3dDevice, ID3D11DeviceContext* pd3dImmediateContext )
\r
1398 //s_pd3d10Device = pd3dDevice;
\r
1400 //const char* g_strBuffer =
\r
1401 // "float4 g_MaterialDiffuseColor; // Material's diffuse color\r\n"
\r
1402 // "float4 g_LightDir; // Light's direction in world space\r\n"
\r
1403 // "float4x4 g_mWorld; // World matrix for object\r\n"
\r
1404 // "float4x4 g_mWorldViewProjection; // World * View * Projection matrix\r\n"
\r
1406 // "struct VS_OUTPUT\r\n"
\r
1408 // " float4 Position : SV_POSITION; // vertex position\r\n"
\r
1409 // " float4 Diffuse : COLOR0; // vertex diffuse color\r\n"
\r
1412 // "VS_OUTPUT RenderWith1LightNoTextureVS( float3 vPos : POSITION,\r\n"
\r
1413 // " float3 vNormal : NORMAL )\r\n"
\r
1415 // " VS_OUTPUT Output;\r\n"
\r
1417 // " // Transform the position from object space to homogeneous projection space\r\n"
\r
1418 // " Output.Position = mul( float4(vPos,1), g_mWorldViewProjection);\r\n"
\r
1420 // " // Transform the normal from object space to world space\r\n"
\r
1421 // " float3 vNormalWorldSpace;\r\n"
\r
1422 // " vNormalWorldSpace = normalize(mul(vNormal, (float3x3)g_mWorld)); // normal (world space)\r\n"
\r
1424 // " // Compute simple directional lighting equation\r\n"
\r
1425 // " Output.Diffuse.rgb = g_MaterialDiffuseColor * max(0,dot(vNormalWorldSpace, g_LightDir));\r\n"
\r
1426 // " Output.Diffuse.a = 1.0f;\r\n"
\r
1428 // " return Output;\r\n"
\r
1431 // "float4 RenderWith1LightNoTexturePS( VS_OUTPUT Input ) : SV_TARGET\r\n"
\r
1433 // " return Input.Diffuse;\r\n"
\r
1436 // "technique10 RenderWith1LightNoTexture\r\n"
\r
1440 // " SetVertexShader( CompileShader( vs_4_0, RenderWith1LightNoTextureVS() ) );\r\n"
\r
1441 // " SetGeometryShader( NULL );\r\n"
\r
1442 // " SetPixelShader( CompileShader( ps_4_0, RenderWith1LightNoTexturePS() ) );\r\n"
\r
1447 //UINT dwBufferSize = ( UINT )strlen( g_strBuffer ) + 1;
\r
1449 //HRESULT hr = D3DX10CreateEffectFromMemory( g_strBuffer, dwBufferSize, "None", NULL, NULL, "fx_4_0",
\r
1450 // D3D10_SHADER_ENABLE_STRICTNESS, 0, pd3dDevice, NULL,
\r
1451 // NULL, &s_pD3D10Effect, NULL, NULL );
\r
1452 //if( FAILED( hr ) )
\r
1455 //s_pRenderTech = s_pD3D10Effect->GetTechniqueByName( "RenderWith1LightNoTexture" );
\r
1456 //g_pMaterialDiffuseColor = s_pD3D10Effect->GetVariableByName( "g_MaterialDiffuseColor" )->AsVector();
\r
1457 //g_pLightDir = s_pD3D10Effect->GetVariableByName( "g_LightDir" )->AsVector();
\r
1458 //g_pmWorld = s_pD3D10Effect->GetVariableByName( "g_mWorld" )->AsMatrix();
\r
1459 //g_pmWorldViewProjection = s_pD3D10Effect->GetVariableByName( "g_mWorldViewProjection" )->AsMatrix();
\r
1461 //const D3D10_INPUT_ELEMENT_DESC layout[] =
\r
1463 // { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
\r
1464 // { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
\r
1466 //D3D10_PASS_DESC PassDesc;
\r
1467 //V_RETURN( s_pRenderTech->GetPassByIndex( 0 )->GetDesc( &PassDesc ) );
\r
1468 //V_RETURN( pd3dDevice->CreateInputLayout( layout, 2, PassDesc.pIAInputSignature,
\r
1469 // PassDesc.IAInputSignatureSize, &s_pVertexLayout ) );
\r
1471 //TODO: Add loading code here
\r
1476 //--------------------------------------------------------------------------------------
\r
1477 HRESULT CDXUTDirectionWidget::OnRender11( D3DXCOLOR color, const D3DXMATRIX* pmView, const D3DXMATRIX* pmProj,
\r
1478 const D3DXVECTOR3* pEyePt )
\r
1481 // m_mView = *pmView;
\r
1483 // // Render the light spheres so the user can visually see the light dir
\r
1484 // D3DXMATRIX mRotate;
\r
1485 // D3DXMATRIX mScale;
\r
1486 // D3DXMATRIX mTrans;
\r
1487 // D3DXMATRIXA16 mWorldViewProj;
\r
1489 // g_pMaterialDiffuseColor->SetFloatVector( ( float* )&color );
\r
1490 // D3DXVECTOR3 vEyePt;
\r
1491 // D3DXVec3Normalize( &vEyePt, pEyePt );
\r
1492 // g_pLightDir->SetFloatVector( ( float* )&vEyePt );
\r
1494 // // Rotate arrow model to point towards origin
\r
1495 // D3DXMATRIX mRotateA, mRotateB;
\r
1496 // D3DXVECTOR3 vAt = D3DXVECTOR3( 0, 0, 0 );
\r
1497 // D3DXVECTOR3 vUp = D3DXVECTOR3( 0, 1, 0 );
\r
1498 // D3DXMatrixRotationX( &mRotateB, D3DX_PI );
\r
1499 // D3DXMatrixLookAtLH( &mRotateA, &m_vCurrentDir, &vAt, &vUp );
\r
1500 // D3DXMatrixInverse( &mRotateA, NULL, &mRotateA );
\r
1501 // mRotate = mRotateB * mRotateA;
\r
1503 // D3DXVECTOR3 vL = m_vCurrentDir * m_fRadius * 1.0f;
\r
1504 // D3DXMatrixTranslation( &mTrans, vL.x, vL.y, vL.z );
\r
1505 // D3DXMatrixScaling( &mScale, m_fRadius * 0.2f, m_fRadius * 0.2f, m_fRadius * 0.2f );
\r
1507 // D3DXMATRIX mWorld = mRotate * mScale * mTrans;
\r
1508 // mWorldViewProj = mWorld * ( m_mView )*( *pmProj );
\r
1510 // g_pmWorldViewProjection->SetMatrix( ( float* )&mWorldViewProj );
\r
1511 // g_pmWorld->SetMatrix( ( float* )&mWorld );
\r
1513 // s_pd3d10Device->IASetInputLayout( s_pVertexLayout );
\r
1515 //TODO: Add rendering code here
\r
1520 //--------------------------------------------------------------------------------------
\r
1521 void CDXUTDirectionWidget::StaticOnD3D11DestroyDevice()
\r
1523 // SAFE_RELEASE( s_pVertexLayout );
\r
1524 // SAFE_RELEASE( s_pD3D11Effect );
\r