1
/* $Id: arcball.c,v 1.6 2009/12/03 19:16:04 arif Exp $Revision: */
2
/* vim:set shiftwidth=4 ts=8: */
4
/*************************************************************************************/
6
/** Copyright (c) 1999-2009 Tatewake.com **/
8
/** Permission is hereby granted, free of charge, to any person obtaining a copy **/
9
/** of this software and associated documentation files (the "Software"), to deal **/
10
/** in the Software without restriction, including without limitation the rights **/
11
/** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell **/
12
/** copies of the Software, and to permit persons to whom the Software is **/
13
/** furnished to do so, subject to the following conditions: **/
15
/** The above copyright notice and this permission notice shall be included in **/
16
/** all copies or substantial portions of the Software. **/
18
/** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR **/
19
/** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, **/
20
/** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE **/
21
/** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER **/
22
/** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, **/
23
/** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN **/
26
/*************************************************************************************/
28
#include "glcompdefs.h"
30
#include "smyrnadefs.h"
33
static void setBounds(ArcBall_t * a, GLfloat NewWidth, GLfloat NewHeight)
35
assert((NewWidth > 1.0f) && (NewHeight > 1.0f));
36
//Set adjustment factor for width/height
37
a->AdjustWidth = 1.0f / ((NewWidth - 1.0f) * 0.5f);
38
a->AdjustHeight = 1.0f / ((NewHeight - 1.0f) * 0.5f);
41
static void mapToSphere(ArcBall_t * a, const Point2fT * NewPt,
47
//Copy paramter into temp point
50
//Adjust point coords and scale down to range of [-1 ... 1]
51
TempPt.s.X = (TempPt.s.X * a->AdjustWidth) - 1.0f;
52
TempPt.s.Y = 1.0f - (TempPt.s.Y * a->AdjustHeight);
54
//Compute the square of the length of the vector to the point from the center
55
length = (TempPt.s.X * TempPt.s.X) + (TempPt.s.Y * TempPt.s.Y);
57
//If the point is mapped outside of the sphere... (length > radius squared)
61
//Compute a normalizing factor (radius / sqrt(length))
62
norm = 1.0f / FuncSqrt(length);
64
//Return the "normalized" vector, a point on the sphere
65
NewVec->s.X = TempPt.s.X * norm;
66
NewVec->s.Y = TempPt.s.Y * norm;
68
} else //Else it's on the inside
70
//Return a vector to a point mapped inside the sphere sqrt(radius squared - length)
71
NewVec->s.X = TempPt.s.X;
72
NewVec->s.Y = TempPt.s.Y;
73
NewVec->s.Z = FuncSqrt(1.0f - length);
77
static Matrix4fT Transform = { {1.0f, 0.0f, 0.0f, 0.0f, // NEW: Final Transform
78
0.0f, 1.0f, 0.0f, 0.0f,
79
0.0f, 0.0f, 1.0f, 0.0f,
80
0.0f, 0.0f, 0.0f, 1.0f}
83
static Matrix3fT LastRot = { {1.0f, 0.0f, 0.0f, // NEW: Last Rotation
88
static Matrix3fT ThisRot = { {1.0f, 0.0f, 0.0f, // NEW: This Rotation
94
void init_arcBall(ArcBall_t * a, GLfloat NewWidth, GLfloat NewHeight)
96
a->Transform = Transform;
99
//Clear initial values
102
a->StVec.s.Z = a->EnVec.s.X = a->EnVec.s.Y = a->EnVec.s.Z = 0.0f;
105
setBounds(a, NewWidth, NewHeight);
113
static void click(ArcBall_t * a, const Point2fT * NewPt)
115
//Map the point to the sphere
116
mapToSphere(a, NewPt, &a->StVec);
119
//Mouse drag, calculate rotation
120
static void drag(ArcBall_t * a, const Point2fT * NewPt, Quat4fT * NewRot)
122
//Map the point to the sphere
123
mapToSphere(a, NewPt, &a->EnVec);
125
//Return the quaternion equivalent to the rotation
129
//Compute the vector perpendicular to the begin and end vectors
130
Vector3fCross(&Perp, &a->StVec, &a->EnVec);
132
//Compute the length of the perpendicular vector
133
if (Vector3fLength(&Perp) > Epsilon) //if its non-zero
135
//We're ok, so return the perpendicular vector as the transform after all
136
NewRot->s.X = Perp.s.X;
137
NewRot->s.Y = Perp.s.Y;
138
NewRot->s.Z = Perp.s.Z;
139
//In the quaternion values, w is cosine (theta / 2), where theta is rotation angle
140
NewRot->s.W = Vector3fDot(&a->StVec, &a->EnVec);
143
//The begin and end vectors coincide, so return an identity transform
144
NewRot->s.X = NewRot->s.Y = NewRot->s.Z = NewRot->s.W = 0.0f;
150
static void arcmouseRClick(ViewInfo * v)
152
Matrix3fSetIdentity(&view->arcball->LastRot); // Reset Rotation
153
Matrix3fSetIdentity(&view->arcball->ThisRot); // Reset Rotation
154
Matrix4fSetRotationFromMatrix3f(&view->arcball->Transform, &view->arcball->ThisRot); // Reset Rotation
159
void arcmouseClick(ViewInfo * v)
161
view->arcball->isDragging = 1; // Prepare For Dragging
162
view->arcball->LastRot = view->arcball->ThisRot; // Set Last Static Rotation To Last Dynamic One
163
click(view->arcball, &view->arcball->MousePt);
164
// printf ("arcmouse click \n");
168
void arcmouseDrag(ViewInfo * v)
171
drag(view->arcball, &view->arcball->MousePt, &ThisQuat);
172
Matrix3fSetRotationFromQuat4f(&view->arcball->ThisRot, &ThisQuat); // Convert Quaternion Into Matrix3fT
173
Matrix3fMulMatrix3f(&view->arcball->ThisRot, &view->arcball->LastRot); // Accumulate Last Rotation Into This One
174
Matrix4fSetRotationFromMatrix3f(&view->arcball->Transform, &view->arcball->ThisRot); // Set Our Final Transform's Rotation From This One
179
void Update(ViewInfo * view)
182
if (view->arcball->isRClicked) // If Right Mouse Clicked, Reset All Rotations
184
Matrix3fSetIdentity(&view->arcball->LastRot); // Reset Rotation
185
Matrix3fSetIdentity(&view->arcball->ThisRot); // Reset Rotation
186
Matrix4fSetRotationFromMatrix3f(&view->arcball->Transform, &view->arcball->ThisRot); // Reset Rotation
189
if (!view->arcball->isDragging) // Not Dragging
191
if (view->arcball->isClicked) // First Click
193
view->arcball->isDragging = 1; // Prepare For Dragging
194
view->arcball->LastRot = view->arcball->ThisRot; // Set Last Static Rotation To Last Dynamic One
195
click(view->arcball, &view->arcball->MousePt);
198
if (view->arcball->isClicked) // Still Clicked, So Still Dragging
202
drag(view->arcball, &view->arcball->MousePt, &ThisQuat);
203
Matrix3fSetRotationFromQuat4f(&view->arcball->ThisRot, &ThisQuat); // Convert Quaternion Into Matrix3fT
204
Matrix3fMulMatrix3f(&view->arcball->ThisRot, &view->arcball->LastRot); // Accumulate Last Rotation Into This One
205
Matrix4fSetRotationFromMatrix3f(&view->arcball->Transform, &view->arcball->ThisRot); // Set Our Final Transform's Rotation From This One
206
} else // No Longer Dragging
207
view->arcball->isDragging = 0;