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