forked from vchukanov/grassdx11
/
DXUTcamera.h
422 lines (354 loc) · 19.1 KB
/
DXUTcamera.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
//--------------------------------------------------------------------------------------
// File: Camera.h
//
// Helper functions for Direct3D programming.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// http://go.microsoft.com/fwlink/?LinkId=320437
//--------------------------------------------------------------------------------------
#pragma once
//--------------------------------------------------------------------------------------
class CD3DArcBall
{
public:
CD3DArcBall() noexcept;
// Functions to change behavior
void Reset();
void SetTranslationRadius( _In_ float fRadiusTranslation )
{
m_fRadiusTranslation = fRadiusTranslation;
}
void SetWindow( _In_ INT nWidth, _In_ INT nHeight, _In_ float fRadius = 0.9f )
{
m_nWidth = nWidth;
m_nHeight = nHeight;
m_fRadius = fRadius;
m_vCenter.x = float(m_nWidth) / 2.0f;
m_vCenter.y = float(m_nHeight) / 2.0f;
}
void SetOffset( _In_ INT nX, _In_ INT nY ) { m_Offset.x = nX; m_Offset.y = nY; }
// Call these from client and use GetRotationMatrix() to read new rotation matrix
void OnBegin( _In_ int nX, _In_ int nY ); // start the rotation (pass current mouse position)
void OnMove( _In_ int nX, _In_ int nY ); // continue the rotation (pass current mouse position)
void OnEnd(); // end the rotation
// Or call this to automatically handle left, middle, right buttons
LRESULT HandleMessages( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam );
// Functions to get/set state
DirectX::XMMATRIX GetRotationMatrix() const
{
using namespace DirectX;
XMVECTOR q = XMLoadFloat4( &m_qNow );
return DirectX::XMMatrixRotationQuaternion( q );
}
DirectX::XMMATRIX GetTranslationMatrix() const { return DirectX::XMLoadFloat4x4( &m_mTranslation ); }
DirectX::XMMATRIX GetTranslationDeltaMatrix() const { return DirectX::XMLoadFloat4x4( &m_mTranslationDelta ); }
bool IsBeingDragged() const { return m_bDrag; }
DirectX::XMVECTOR GetQuatNow() const { return DirectX::XMLoadFloat4( &m_qNow ); }
void SetQuatNow( _In_ DirectX::FXMVECTOR& q ) { DirectX::XMStoreFloat4( &m_qNow, q ); }
static DirectX::XMVECTOR QuatFromBallPoints( _In_ DirectX::FXMVECTOR vFrom, _In_ DirectX::FXMVECTOR vTo )
{
using namespace DirectX;
XMVECTOR dot = XMVector3Dot( vFrom, vTo );
XMVECTOR vPart = XMVector3Cross( vFrom, vTo );
return XMVectorSelect( dot, vPart, g_XMSelect1110 );
}
protected:
DirectX::XMFLOAT4X4 m_mRotation; // Matrix for arc ball's orientation
DirectX::XMFLOAT4X4 m_mTranslation; // Matrix for arc ball's position
DirectX::XMFLOAT4X4 m_mTranslationDelta;// Matrix for arc ball's position
POINT m_Offset; // window offset, or upper-left corner of window
INT m_nWidth; // arc ball's window width
INT m_nHeight; // arc ball's window height
DirectX::XMFLOAT2 m_vCenter; // center of arc ball
float m_fRadius; // arc ball's radius in screen coords
float m_fRadiusTranslation; // arc ball's radius for translating the target
DirectX::XMFLOAT4 m_qDown; // Quaternion before button down
DirectX::XMFLOAT4 m_qNow; // Composite quaternion for current drag
bool m_bDrag; // Whether user is dragging arc ball
POINT m_ptLastMouse; // position of last mouse point
DirectX::XMFLOAT3 m_vDownPt; // starting point of rotation arc
DirectX::XMFLOAT3 m_vCurrentPt; // current point of rotation arc
DirectX::XMVECTOR ScreenToVector( _In_ float fScreenPtX, _In_ float fScreenPtY )
{
// Scale to screen
float x = -( fScreenPtX - m_Offset.x - m_nWidth / 2 ) / ( m_fRadius * m_nWidth / 2 );
float y = ( fScreenPtY - m_Offset.y - m_nHeight / 2 ) / ( m_fRadius * m_nHeight / 2 );
float z = 0.0f;
float mag = x * x + y * y;
if( mag > 1.0f )
{
float scale = 1.0f / sqrtf( mag );
x *= scale;
y *= scale;
}
else
z = sqrtf( 1.0f - mag );
return DirectX::XMVectorSet( x, y, z, 0 );
}
};
//--------------------------------------------------------------------------------------
// used by CCamera to map WM_KEYDOWN keys
//--------------------------------------------------------------------------------------
enum D3DUtil_CameraKeys
{
CAM_STRAFE_LEFT = 0,
CAM_STRAFE_RIGHT,
CAM_MOVE_FORWARD,
CAM_MOVE_BACKWARD,
CAM_MOVE_UP,
CAM_MOVE_DOWN,
CAM_RESET,
CAM_CONTROLDOWN,
CAM_MAX_KEYS,
CAM_UNKNOWN = 0xFF
};
#define KEY_WAS_DOWN_MASK 0x80
#define KEY_IS_DOWN_MASK 0x01
#define MOUSE_LEFT_BUTTON 0x01
#define MOUSE_MIDDLE_BUTTON 0x02
#define MOUSE_RIGHT_BUTTON 0x04
#define MOUSE_WHEEL 0x08
//--------------------------------------------------------------------------------------
// Simple base camera class that moves and rotates. The base class
// records mouse and keyboard input for use by a derived class, and
// keeps common state.
//--------------------------------------------------------------------------------------
class CBaseCamera
{
public:
CBaseCamera() noexcept;
// Call these from client and use Get*Matrix() to read new matrices
virtual LRESULT HandleMessages( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam );
virtual void FrameMove( _In_ float fElapsedTime ) = 0;
// Functions to change camera matrices
virtual void Reset();
virtual void SetViewParams( _In_ DirectX::FXMVECTOR vEyePt, _In_ DirectX::FXMVECTOR vLookatPt );
virtual void SetProjParams( _In_ float fFOV, _In_ float fAspect, _In_ float fNearPlane, _In_ float fFarPlane );
// Functions to change behavior
virtual void SetDragRect( _In_ const RECT& rc ) { m_rcDrag = rc; }
void SetInvertPitch( _In_ bool bInvertPitch ) { m_bInvertPitch = bInvertPitch; }
void SetDrag( _In_ bool bMovementDrag, _In_ float fTotalDragTimeToZero = 0.25f )
{
m_bMovementDrag = bMovementDrag;
m_fTotalDragTimeToZero = fTotalDragTimeToZero;
}
void SetEnableYAxisMovement( _In_ bool bEnableYAxisMovement ) { m_bEnableYAxisMovement = bEnableYAxisMovement; }
void SetEnablePositionMovement( _In_ bool bEnablePositionMovement ) { m_bEnablePositionMovement = bEnablePositionMovement; }
void SetClipToBoundary( _In_ bool bClipToBoundary, _In_opt_ DirectX::XMFLOAT3* pvMinBoundary, _In_opt_ DirectX::XMFLOAT3* pvMaxBoundary )
{
m_bClipToBoundary = bClipToBoundary;
if( pvMinBoundary ) m_vMinBoundary = *pvMinBoundary;
if( pvMaxBoundary ) m_vMaxBoundary = *pvMaxBoundary;
}
void SetScalers( _In_ float fRotationScaler = 0.01f, _In_ float fMoveScaler = 5.0f )
{
m_fRotationScaler = fRotationScaler;
m_fMoveScaler = fMoveScaler;
}
void SetNumberOfFramesToSmoothMouseData( _In_ int nFrames ) { if( nFrames > 0 ) m_fFramesToSmoothMouseData = ( float )nFrames; }
void SetResetCursorAfterMove( _In_ bool bResetCursorAfterMove ) { m_bResetCursorAfterMove = bResetCursorAfterMove; }
// Functions to get state
DirectX::XMMATRIX GetViewMatrix() const { return DirectX::XMLoadFloat4x4( &m_mView ); }
DirectX::XMMATRIX GetProjMatrix() const { return DirectX::XMLoadFloat4x4( &m_mProj ); }
DirectX::XMVECTOR GetEyePt() const { return DirectX::XMLoadFloat3( &m_vEye ); }
DirectX::XMVECTOR GetLookAtPt() const { return DirectX::XMLoadFloat3( &m_vLookAt ); }
float GetNearClip() const { return m_fNearPlane; }
float GetFarClip() const { return m_fFarPlane; }
bool IsBeingDragged() const { return ( m_bMouseLButtonDown || m_bMouseMButtonDown || m_bMouseRButtonDown ); }
bool IsMouseLButtonDown() const { return m_bMouseLButtonDown; }
bool IsMouseMButtonDown() const { return m_bMouseMButtonDown; }
bool sMouseRButtonDown() const { return m_bMouseRButtonDown; }
protected:
// Functions to map a WM_KEYDOWN key to a D3DUtil_CameraKeys enum
virtual D3DUtil_CameraKeys MapKey( _In_ UINT nKey );
bool IsKeyDown( _In_ BYTE key ) const { return( ( key & KEY_IS_DOWN_MASK ) == KEY_IS_DOWN_MASK ); }
bool WasKeyDown( _In_ BYTE key ) const { return( ( key & KEY_WAS_DOWN_MASK ) == KEY_WAS_DOWN_MASK ); }
DirectX::XMVECTOR ConstrainToBoundary( _In_ DirectX::FXMVECTOR v )
{
using namespace DirectX;
XMVECTOR vMin = XMLoadFloat3( &m_vMinBoundary );
XMVECTOR vMax = XMLoadFloat3( &m_vMaxBoundary );
// Constrain vector to a bounding box
return XMVectorClamp( v, vMin, vMax );
}
void UpdateMouseDelta();
void UpdateVelocity( _In_ float fElapsedTime );
void GetInput( _In_ bool bGetKeyboardInput, _In_ bool bGetMouseInput, _In_ bool bGetGamepadInput );
DirectX::XMFLOAT4X4 m_mView; // View matrix
DirectX::XMFLOAT4X4 m_mProj; // Projection matrix
DXUT_GAMEPAD m_GamePad[DXUT_MAX_CONTROLLERS]; // XInput controller state
DirectX::XMFLOAT3 m_vGamePadLeftThumb;
DirectX::XMFLOAT3 m_vGamePadRightThumb;
double m_GamePadLastActive[DXUT_MAX_CONTROLLERS];
int m_cKeysDown; // Number of camera keys that are down.
BYTE m_aKeys[CAM_MAX_KEYS]; // State of input - KEY_WAS_DOWN_MASK|KEY_IS_DOWN_MASK
DirectX::XMFLOAT3 m_vKeyboardDirection; // Direction vector of keyboard input
POINT m_ptLastMousePosition; // Last absolute position of mouse cursor
int m_nCurrentButtonMask; // mask of which buttons are down
int m_nMouseWheelDelta; // Amount of middle wheel scroll (+/-)
DirectX::XMFLOAT2 m_vMouseDelta; // Mouse relative delta smoothed over a few frames
float m_fFramesToSmoothMouseData; // Number of frames to smooth mouse data over
DirectX::XMFLOAT3 m_vDefaultEye; // Default camera eye position
DirectX::XMFLOAT3 m_vDefaultLookAt; // Default LookAt position
DirectX::XMFLOAT3 m_vEye; // Camera eye position
DirectX::XMFLOAT3 m_vLookAt; // LookAt position
float m_fCameraYawAngle; // Yaw angle of camera
float m_fCameraPitchAngle; // Pitch angle of camera
RECT m_rcDrag; // Rectangle within which a drag can be initiated.
DirectX::XMFLOAT3 m_vVelocity; // Velocity of camera
DirectX::XMFLOAT3 m_vVelocityDrag; // Velocity drag force
float m_fDragTimer; // Countdown timer to apply drag
float m_fTotalDragTimeToZero; // Time it takes for velocity to go from full to 0
DirectX::XMFLOAT2 m_vRotVelocity; // Velocity of camera
float m_fFOV; // Field of view
float m_fAspect; // Aspect ratio
float m_fNearPlane; // Near plane
float m_fFarPlane; // Far plane
float m_fRotationScaler; // Scaler for rotation
float m_fMoveScaler; // Scaler for movement
bool m_bMouseLButtonDown; // True if left button is down
bool m_bMouseMButtonDown; // True if middle button is down
bool m_bMouseRButtonDown; // True if right button is down
bool m_bMovementDrag; // If true, then camera movement will slow to a stop otherwise movement is instant
bool m_bInvertPitch; // Invert the pitch axis
bool m_bEnablePositionMovement; // If true, then the user can translate the camera/model
bool m_bEnableYAxisMovement; // If true, then camera can move in the y-axis
bool m_bClipToBoundary; // If true, then the camera will be clipped to the boundary
bool m_bResetCursorAfterMove; // If true, the class will reset the cursor position so that the cursor always has space to move
DirectX::XMFLOAT3 m_vMinBoundary; // Min point in clip boundary
DirectX::XMFLOAT3 m_vMaxBoundary; // Max point in clip boundary
};
//--------------------------------------------------------------------------------------
// Simple first person camera class that moves and rotates.
// It allows yaw and pitch but not roll. It uses WM_KEYDOWN and
// GetCursorPos() to respond to keyboard and mouse input and updates the
// view matrix based on input.
//--------------------------------------------------------------------------------------
class CFirstPersonCamera : public CBaseCamera
{
public:
CFirstPersonCamera() noexcept;
// Call these from client and use Get*Matrix() to read new matrices
virtual void FrameMove( _In_ float fElapsedTime ) override;
// Functions to change behavior
void SetRotateButtons( _In_ bool bLeft, _In_ bool bMiddle, _In_ bool bRight, _In_ bool bRotateWithoutButtonDown = false );
// Functions to get state
DirectX::XMMATRIX GetWorldMatrix() const { return DirectX::XMLoadFloat4x4( &m_mCameraWorld ); }
DirectX::XMVECTOR GetWorldRight() const { return DirectX::XMLoadFloat3( reinterpret_cast<const DirectX::XMFLOAT3*>( &m_mCameraWorld._11 ) ); }
DirectX::XMVECTOR GetWorldUp() const { return DirectX::XMLoadFloat3( reinterpret_cast<const DirectX::XMFLOAT3*>( &m_mCameraWorld._21 ) ); }
DirectX::XMVECTOR GetWorldAhead() const { return DirectX::XMLoadFloat3( reinterpret_cast<const DirectX::XMFLOAT3*>( &m_mCameraWorld._31 ) ); }
DirectX::XMVECTOR GetEyePt() const { return DirectX::XMLoadFloat3( reinterpret_cast<const DirectX::XMFLOAT3*>( &m_mCameraWorld._41 ) ); }
protected:
DirectX::XMFLOAT4X4 m_mCameraWorld; // World matrix of the camera (inverse of the view matrix)
int m_nActiveButtonMask; // Mask to determine which button to enable for rotation
bool m_bRotateWithoutButtonDown;
};
//--------------------------------------------------------------------------------------
// Simple model viewing camera class that rotates around the object.
//--------------------------------------------------------------------------------------
class CModelViewerCamera : public CBaseCamera
{
public:
CModelViewerCamera() noexcept;
// Call these from client and use Get*Matrix() to read new matrices
virtual LRESULT HandleMessages( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) override;
virtual void FrameMove( _In_ float fElapsedTime ) override;
// Functions to change behavior
virtual void SetDragRect( _In_ const RECT& rc ) override;
virtual void Reset() override;
virtual void SetViewParams( _In_ DirectX::FXMVECTOR pvEyePt, _In_ DirectX::FXMVECTOR pvLookatPt ) override;
void SetButtonMasks( _In_ int nRotateModelButtonMask = MOUSE_LEFT_BUTTON, _In_ int nZoomButtonMask = MOUSE_WHEEL,
_In_ int nRotateCameraButtonMask = MOUSE_RIGHT_BUTTON )
{
m_nRotateModelButtonMask = nRotateModelButtonMask, m_nZoomButtonMask = nZoomButtonMask;
m_nRotateCameraButtonMask = nRotateCameraButtonMask;
}
void SetAttachCameraToModel( _In_ bool bEnable = false ) { m_bAttachCameraToModel = bEnable; }
void SetWindow( _In_ int nWidth, _In_ int nHeight, _In_ float fArcballRadius=0.9f )
{
m_WorldArcBall.SetWindow( nWidth, nHeight, fArcballRadius );
m_ViewArcBall.SetWindow( nWidth, nHeight, fArcballRadius );
}
void SetRadius( _In_ float fDefaultRadius=5.0f, _In_ float fMinRadius=1.0f, _In_ float fMaxRadius=FLT_MAX )
{
m_fDefaultRadius = m_fRadius = fDefaultRadius; m_fMinRadius = fMinRadius; m_fMaxRadius = fMaxRadius;
m_bDragSinceLastUpdate = true;
}
void SetModelCenter( _In_ const DirectX::XMFLOAT3& vModelCenter ) { m_vModelCenter = vModelCenter; }
void SetLimitPitch( _In_ bool bLimitPitch ) { m_bLimitPitch = bLimitPitch; }
void SetViewQuat( _In_ DirectX::FXMVECTOR q )
{
m_ViewArcBall.SetQuatNow( q );
m_bDragSinceLastUpdate = true;
}
void SetWorldQuat( _In_ DirectX::FXMVECTOR q )
{
m_WorldArcBall.SetQuatNow( q );
m_bDragSinceLastUpdate = true;
}
// Functions to get state
DirectX::XMMATRIX GetWorldMatrix() const { return DirectX::XMLoadFloat4x4( &m_mWorld ); }
void SetWorldMatrix( _In_ DirectX::CXMMATRIX mWorld )
{
XMStoreFloat4x4( &m_mWorld, mWorld );
m_bDragSinceLastUpdate = true;
}
protected:
CD3DArcBall m_WorldArcBall;
CD3DArcBall m_ViewArcBall;
DirectX::XMFLOAT3 m_vModelCenter;
DirectX::XMFLOAT4X4 m_mModelLastRot; // Last arcball rotation matrix for model
DirectX::XMFLOAT4X4 m_mModelRot; // Rotation matrix of model
DirectX::XMFLOAT4X4 m_mWorld; // World matrix of model
int m_nRotateModelButtonMask;
int m_nZoomButtonMask;
int m_nRotateCameraButtonMask;
bool m_bAttachCameraToModel;
bool m_bLimitPitch;
bool m_bDragSinceLastUpdate; // True if mouse drag has happened since last time FrameMove is called.
float m_fRadius; // Distance from the camera to model
float m_fDefaultRadius; // Distance from the camera to model
float m_fMinRadius; // Min radius
float m_fMaxRadius; // Max radius
DirectX::XMFLOAT4X4 m_mCameraRotLast;
};
//--------------------------------------------------------------------------------------
// Manages the mesh, direction, mouse events of a directional arrow that
// rotates around a radius controlled by an arcball
//--------------------------------------------------------------------------------------
class CDXUTDirectionWidget
{
public:
CDXUTDirectionWidget() noexcept;
LRESULT HandleMessages( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam );
HRESULT OnRender( _In_ DirectX::FXMVECTOR color, _In_ DirectX::CXMMATRIX pmView, _In_ DirectX::CXMMATRIX pmProj, _In_ DirectX::FXMVECTOR vEyePt );
DirectX::XMVECTOR GetLightDirection() const { return DirectX::XMLoadFloat3( &m_vCurrentDir ); }
void SetLightDirection( _In_ DirectX::FXMVECTOR vDir )
{
DirectX::XMStoreFloat3( &m_vCurrentDir, vDir );
m_vDefaultDir = m_vCurrentDir;
}
void SetLightDirection( _In_ DirectX::XMFLOAT3 vDir )
{
m_vDefaultDir = m_vCurrentDir = vDir;
}
void SetButtonMask( _In_ int nRotate = MOUSE_RIGHT_BUTTON ) { m_nRotateMask = nRotate; }
float GetRadius() const { return m_fRadius; }
void SetRadius( _In_ float fRadius ) { m_fRadius = fRadius; }
bool IsBeingDragged() { return m_ArcBall.IsBeingDragged(); }
static HRESULT WINAPI StaticOnD3D11CreateDevice( _In_ ID3D11Device* pd3dDevice, _In_ ID3D11DeviceContext* pd3dImmediateContext );
static void WINAPI StaticOnD3D11DestroyDevice();
protected:
HRESULT UpdateLightDir();
// TODO - need support for Direct3D 11 widget
DirectX::XMFLOAT4X4 m_mRot;
DirectX::XMFLOAT4X4 m_mRotSnapshot;
float m_fRadius;
int m_nRotateMask;
CD3DArcBall m_ArcBall;
DirectX::XMFLOAT3 m_vDefaultDir;
DirectX::XMFLOAT3 m_vCurrentDir;
DirectX::XMFLOAT4X4 m_mView;
};