-
Notifications
You must be signed in to change notification settings - Fork 3
/
ArcBall.h
101 lines (84 loc) · 2.57 KB
/
ArcBall.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
//--------------------------------------------------------------------------------------
// File: ArcBall.h
//
// Ken Shoemake, "Arcball Rotation Control", Graphics Gems IV, pg 176 - 192
//
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//--------------------------------------------------------------------------------------
#pragma once
class ArcBall
{
public:
ArcBall() :
m_width(800.f),
m_height(400.f),
m_radius(1.f),
m_drag(false) { Reset(); }
void Reset()
{
m_qdown = m_qnow = DirectX::SimpleMath::Quaternion::Identity;
}
void OnBegin( int x, int y )
{
m_drag = true;
m_qdown = m_qnow;
m_downPoint = ScreenToVector(float(x), float(y));
}
void OnMove(int x, int y)
{
using namespace DirectX;
if (m_drag)
{
XMVECTOR curr = ScreenToVector(float(x), float(y));
m_qnow = XMQuaternionMultiply(m_qdown, QuatFromBallPoints(m_downPoint, curr));
m_qnow.Normalize();
}
}
void OnEnd()
{
m_drag = false;
}
void SetWindow(int width, int height)
{
m_width = float(width);
m_height = float(height);
}
void SetRadius(float radius)
{
m_radius = radius;
}
DirectX::SimpleMath::Quaternion GetQuat() const { return m_qnow; }
bool IsDragging() const { return m_drag; }
private:
float m_width;
float m_height;
float m_radius;
DirectX::SimpleMath::Quaternion m_qdown;
DirectX::SimpleMath::Quaternion m_qnow;
DirectX::SimpleMath::Vector3 m_downPoint;
bool m_drag;
DirectX::XMVECTOR ScreenToVector(float screenx, float screeny)
{
float x = -( screenx - m_width / 2.f ) / ( m_radius * m_width / 2.f );
float y = ( screeny - m_height / 2.f ) / ( m_radius * m_height / 2.f );
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 );
}
static DirectX::XMVECTOR QuatFromBallPoints( DirectX::FXMVECTOR vFrom, DirectX::FXMVECTOR vTo )
{
using namespace DirectX;
XMVECTOR dot = XMVector3Dot( vFrom, vTo );
XMVECTOR vPart = XMVector3Cross( vFrom, vTo );
return XMVectorSelect( dot, vPart, g_XMSelect1110 );
}
};