1 /** KempoApi: The Turloc Toolkit *****************************/
2 /** * * **/
3 /** ** ** Filename: arcball.cpp **/
4 /** ** Version: Common **/
5 /** ** **/
6 /** **/
7 /** Arcball class for mouse manipulation. **/
8 /** **/
9 /** **/
10 /** **/
11 /** **/
12 /** (C) 1999-2003 Tatewake.com **/
13 /** History: **/
14 /** 08/17/2003 - (TJG) - Creation **/
15 /** 09/23/2003 - (TJG) - Bug fix and optimization **/
16 /** 09/25/2003 - (TJG) - Version for NeHe Basecode users **/
17 /** **/
18 /*************************************************************/
19 /*
20 MIT License:
21
22 Permission is hereby granted, free of charge, to any person obtaining a copy
23 of this software and associated documentation files (the "Software"), to deal
24 in the Software without restriction, including without limitation the rights
25 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26 copies of the Software, and to permit persons to whom the Software is
27 furnished to do so, subject to the following conditions:
28
29 The above copyright notice and this permission notice shall be included in
30 all copies or substantial portions of the Software.
31
32 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
38 THE SOFTWARE.
39 */
40
41 #include "stdafx.h"
42
43
44 #include "math.h" // Needed for sqrtf
45
46 #include "arcball.h" // ArcBall header
47
48 //Arcball sphere constants:
49 //Diameter is 2.0f
50 //Radius is 1.0f
51 //Radius squared is 1.0f
52
_mapToSphere(const Point2fT * NewPt,Vector3fT * NewVec) const53 void ArcBall::_mapToSphere(const Point2fT* NewPt, Vector3fT* NewVec) const
54 {
55 Point2fT TempPt;
56 GLfloat length;
57
58 //Copy paramter into temp point
59 TempPt = *NewPt;
60
61 //Adjust point coords and scale down to range of [-1 ... 1]
62 TempPt.s.X = (TempPt.s.X * this->AdjustWidth) - 1.0f;
63 TempPt.s.Y = 1.0f - (TempPt.s.Y * this->AdjustHeight);
64
65 //Compute the square of the length of the vector to the point from the center
66 length = (TempPt.s.X * TempPt.s.X) + (TempPt.s.Y * TempPt.s.Y);
67
68 //If the point is mapped outside of the sphere... (length > radius squared)
69 if (length > 1.0f)
70 {
71 GLfloat norm;
72
73 //Compute a normalizing factor (radius / sqrt(length))
74 norm = 1.0f / FuncSqrt(length);
75
76 //Return the "normalized" vector, a point on the sphere
77 NewVec->s.X = TempPt.s.X * norm;
78 NewVec->s.Y = TempPt.s.Y * norm;
79 NewVec->s.Z = 0.0f;
80 }
81 else //Else it's on the inside
82 {
83 //Return a vector to a point mapped inside the sphere sqrt(radius squared - length)
84 NewVec->s.X = TempPt.s.X;
85 NewVec->s.Y = TempPt.s.Y;
86 NewVec->s.Z = FuncSqrt(1.0f - length);
87 }
88 }
89
90 //Create/Destroy
ArcBall(GLfloat NewWidth,GLfloat NewHeight)91 ArcBall::ArcBall(GLfloat NewWidth, GLfloat NewHeight)
92 {
93 //Clear initial values
94 this->StVec.s.X =
95 this->StVec.s.Y =
96 this->StVec.s.Z =
97
98 this->EnVec.s.X =
99 this->EnVec.s.Y =
100 this->EnVec.s.Z = 0.0f;
101
102 //Set initial bounds
103 this->setBounds(NewWidth, NewHeight);
104 }
105
106 //Mouse down
click(GLfloat x,GLfloat y,Matrix4fT * stTrans)107 void ArcBall::click(GLfloat x, GLfloat y, Matrix4fT *stTrans)
108 {
109 Point2fT NewPt;
110 NewPt.T[0] = x;
111 NewPt.T[1] = y;
112 //Map the point to the sphere
113 this->_mapToSphere(&NewPt, &this->StVec);
114 Matrix4fSetRotationScaleFromMatrix4f(&this->StTransform, stTrans);
115 }
116
117 //Mouse drag, calculate rotation
drag(GLfloat x,GLfloat y,Quat4fT * NewRot)118 void ArcBall::drag(GLfloat x, GLfloat y, Quat4fT* NewRot)
119 {
120 Point2fT NewPt;
121 NewPt.T[0] = x;
122 NewPt.T[1] = y;
123
124 //Map the point to the sphere
125 this->_mapToSphere(&NewPt, &this->EnVec);
126
127 //Return the quaternion equivalent to the rotation
128 if (NewRot)
129 {
130 Vector3fT Perp;
131
132 //Compute the vector perpendicular to the begin and end vectors
133 Vector3fCross(&Perp, &this->StVec, &this->EnVec);
134
135 //Compute the length of the perpendicular vector
136 if (Vector3fLength(&Perp) > Epsilon) //if its non-zero
137 {
138 //We're ok, so return the perpendicular vector as the transform after all
139 NewRot->s.X = Perp.s.X;
140 NewRot->s.Y = Perp.s.Y;
141 NewRot->s.Z = Perp.s.Z;
142 //In the quaternion values, w is cosine (theta / 2), where theta is rotation angle
143 NewRot->s.W= Vector3fDot(&this->StVec, &this->EnVec);
144 }
145 else //if its zero
146 {
147 //The begin and end vectors coincide, so return an identity transform
148 NewRot->s.X =
149 NewRot->s.Y =
150 NewRot->s.Z =
151 NewRot->s.W = 0.0f;
152 }
153 }
154 }
155
dragAccumulate(GLfloat x,GLfloat y,Matrix4fT * transform)156 void ArcBall::dragAccumulate(GLfloat x, GLfloat y, Matrix4fT *transform)
157 {
158 Quat4fT tmpQuat;
159 Matrix3fT tmpRot;
160
161 drag(x, y, &tmpQuat);
162
163 // Set output to the initial transform
164 Matrix4fSetRotationScaleFromMatrix4f(transform, &this->StTransform);
165 // get current rotation matrix
166 Matrix3fSetRotationFromQuat4f(&tmpRot, &tmpQuat);
167 // Apply to initial transform
168 Matrix4fMulRotationFromMatrix3f(transform, &tmpRot);
169 }
170