1 | //
|
---|
2 | // ============================================================
|
---|
3 | // === OpenGL Library ===
|
---|
4 | //
|
---|
5 | // $Date: 2004/10/28 22:43:53 $
|
---|
6 | // $Revision: 1.1 $
|
---|
7 | //
|
---|
8 | // Hacked into C++ from SGI's trackball.h---see copyright
|
---|
9 | // at end.
|
---|
10 | //
|
---|
11 | // ============================================================
|
---|
12 | //
|
---|
13 |
|
---|
14 | #include <iostream.h>
|
---|
15 | #include <string.h>
|
---|
16 | #include <limits.h>
|
---|
17 | #include <assert.h>
|
---|
18 | #include <math.h>
|
---|
19 |
|
---|
20 | #include "Trackball.h"
|
---|
21 | #include "VectorMath.h"
|
---|
22 | #include "MatrixMath.h"
|
---|
23 |
|
---|
24 |
|
---|
25 | //===========================================================================
|
---|
26 | //===========================================================================
|
---|
27 | // Static Initialization
|
---|
28 | //===========================================================================
|
---|
29 | //===========================================================================
|
---|
30 |
|
---|
31 | // This size should really be based on the distance from the center of
|
---|
32 | // rotation to the point on the object underneath the mouse. That
|
---|
33 | // point would then track the mouse as closely as possible. This is a
|
---|
34 | // simple example, though, so that is left as an Exercise for the
|
---|
35 | // Programmer.
|
---|
36 | float Trackball::trackballSize = (float)0.9;
|
---|
37 |
|
---|
38 | // Number of iterations before we renormalize.
|
---|
39 | int Trackball::renormCount = 97;
|
---|
40 |
|
---|
41 |
|
---|
42 | //===========================================================================
|
---|
43 | //===========================================================================
|
---|
44 | // Constructors/Destructor
|
---|
45 | //===========================================================================
|
---|
46 | //===========================================================================
|
---|
47 |
|
---|
48 | Trackball::Trackball()
|
---|
49 | {
|
---|
50 | lastX = 0.0;
|
---|
51 | lastY = 0.0;
|
---|
52 | vZero(lastQuat);
|
---|
53 | vZero(curQuat);
|
---|
54 | lastQuat[3] = 1.0;
|
---|
55 | curQuat[3] = 1.0;
|
---|
56 | }
|
---|
57 |
|
---|
58 |
|
---|
59 | Trackball::~Trackball()
|
---|
60 | {
|
---|
61 | // Empty.
|
---|
62 | }
|
---|
63 |
|
---|
64 |
|
---|
65 |
|
---|
66 | //===========================================================================
|
---|
67 | // Public Member Functions
|
---|
68 | //===========================================================================
|
---|
69 |
|
---|
70 | void
|
---|
71 | Trackball::start(float x, float y)
|
---|
72 | {
|
---|
73 | lastX = x;
|
---|
74 | lastY = y;
|
---|
75 | vZero(lastQuat);
|
---|
76 | lastQuat[3] = 1.0;
|
---|
77 | }
|
---|
78 |
|
---|
79 |
|
---|
80 |
|
---|
81 | /////////////////////////////////////////////////////////////////////////////
|
---|
82 | //
|
---|
83 | // Ok, simulate a track-ball. Project the points onto the virtual
|
---|
84 | // trackball, then figure out the axis of rotation, which is the cross
|
---|
85 | // product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
|
---|
86 | // Note: This is a deformed trackball-- is a trackball in the center,
|
---|
87 | // but is deformed into a hyperbolic sheet of rotation away from the
|
---|
88 | // center. This particular function was chosen after trying out
|
---|
89 | // several variations.
|
---|
90 | //
|
---|
91 | // It is assumed that the arguments to this routine are in the range
|
---|
92 | // (-1.0 ... 1.0)
|
---|
93 | //
|
---|
94 | void
|
---|
95 | Trackball::update(float x, float y)
|
---|
96 | {
|
---|
97 | float p1[3], p2[3], d[3];
|
---|
98 | float t;
|
---|
99 |
|
---|
100 | // Might just be able to return here.
|
---|
101 | if (lastX == x && lastY == y) {
|
---|
102 | /* Zero rotation */
|
---|
103 | vZero(lastQuat);
|
---|
104 | lastQuat[3] = 1.0;
|
---|
105 | return;
|
---|
106 | }
|
---|
107 |
|
---|
108 | /*
|
---|
109 | * First, figure out z-coordinates for projection of P1 and P2 to
|
---|
110 | * deformed sphere
|
---|
111 | */
|
---|
112 | vSet(p1, lastX, lastY, projectToSphere(trackballSize, lastX, lastY));
|
---|
113 | vSet(p2, x, y, projectToSphere(trackballSize, x, y));
|
---|
114 |
|
---|
115 | /*
|
---|
116 | * Now, we want the cross product of P1 and P2
|
---|
117 | */
|
---|
118 | vCross(p2, p1, a);
|
---|
119 |
|
---|
120 | /*
|
---|
121 | * Figure out how much to rotate around that axis.
|
---|
122 | */
|
---|
123 | vSub(p1,p2,d);
|
---|
124 | t = (float)(vLength(d) / (2.0*trackballSize));
|
---|
125 |
|
---|
126 | /*
|
---|
127 | * Avoid problems with out-of-control values...
|
---|
128 | */
|
---|
129 | if (t > 1.0) t = 1.0;
|
---|
130 | if (t < -1.0) t = -1.0;
|
---|
131 | phi = (float)(2.0 * asin(t));
|
---|
132 |
|
---|
133 | axisToQuat(a, phi, lastQuat);
|
---|
134 |
|
---|
135 | lastX = x;
|
---|
136 | lastY = y;
|
---|
137 |
|
---|
138 | addQuats(lastQuat, curQuat, curQuat);
|
---|
139 | }
|
---|
140 |
|
---|
141 | //get the axis and angle for the rotation
|
---|
142 | void Trackball::getAxisAngle(float& angle, float axis[3]) {
|
---|
143 | angle = phi*180.0f/3.141517;
|
---|
144 | for (int i=0;i<3;i++)
|
---|
145 | axis[i] = a[i];
|
---|
146 | }
|
---|
147 |
|
---|
148 | /////////////////////////////////////////////////////////////////////////////
|
---|
149 | // joeys clear
|
---|
150 | //
|
---|
151 | void
|
---|
152 | Trackball::clear()
|
---|
153 | {
|
---|
154 | lastX = 0.0;
|
---|
155 | lastY = 0.0;
|
---|
156 | vZero(lastQuat);
|
---|
157 | vZero(curQuat);
|
---|
158 | lastQuat[3] = 1.0;
|
---|
159 | curQuat[3] = 1.0;
|
---|
160 | }
|
---|
161 |
|
---|
162 |
|
---|
163 |
|
---|
164 | /////////////////////////////////////////////////////////////////////////////
|
---|
165 | //
|
---|
166 | // Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
|
---|
167 | // if we are away from the center of the sphere.
|
---|
168 | //
|
---|
169 | float
|
---|
170 | Trackball::projectToSphere(float r, float x, float y)
|
---|
171 | {
|
---|
172 | float d, t, z;
|
---|
173 |
|
---|
174 | d = (float)(sqrt(x*x + y*y));
|
---|
175 | if (d < r * 0.70710678118654752440) { /* Inside sphere */
|
---|
176 | z = (float)(sqrt(r*r - d*d));
|
---|
177 | } else { /* On hyperbola */
|
---|
178 | t = (float)(r / 1.41421356237309504880);
|
---|
179 | z = t*t / d;
|
---|
180 | }
|
---|
181 | return z;
|
---|
182 | }
|
---|
183 |
|
---|
184 |
|
---|
185 |
|
---|
186 | /////////////////////////////////////////////////////////////////////////////
|
---|
187 | //
|
---|
188 | // Build a rotation matrix, given a quaternion rotation.
|
---|
189 | //
|
---|
190 | void
|
---|
191 | Trackball::buildRotMatrix(float m[4][4])
|
---|
192 | {
|
---|
193 | m[0][0] = (float)(1.0 - 2.0 * (curQuat[1] * curQuat[1] + curQuat[2] * curQuat[2]));
|
---|
194 | m[0][1] = (float)(2.0 * (curQuat[0] * curQuat[1] - curQuat[2] * curQuat[3]));
|
---|
195 | m[0][2] = (float)(2.0 * (curQuat[2] * curQuat[0] + curQuat[1] * curQuat[3]));
|
---|
196 | m[0][3] = (float)(0.0);
|
---|
197 |
|
---|
198 | m[1][0] = (float)(2.0 * (curQuat[0] * curQuat[1] + curQuat[2] * curQuat[3]));
|
---|
199 | m[1][1]= (float)(1.0 - 2.0 * (curQuat[2] * curQuat[2] + curQuat[0] * curQuat[0]));
|
---|
200 | m[1][2] = (float)(2.0 * (curQuat[1] * curQuat[2] - curQuat[0] * curQuat[3]));
|
---|
201 | m[1][3] = (float)(0.0);
|
---|
202 |
|
---|
203 | m[2][0] = (float)(2.0 * (curQuat[2] * curQuat[0] - curQuat[1] * curQuat[3]));
|
---|
204 | m[2][1] = (float)(2.0 * (curQuat[1] * curQuat[2] + curQuat[0] * curQuat[3]));
|
---|
205 | m[2][2] = (float)(1.0 - 2.0 * (curQuat[1] * curQuat[1] + curQuat[0] * curQuat[0]));
|
---|
206 | m[2][3] = (float)(0.0);
|
---|
207 |
|
---|
208 | m[3][0] = (float)(0.0);
|
---|
209 | m[3][1] = (float)(0.0);
|
---|
210 | m[3][2] = (float)(0.0);
|
---|
211 | m[3][3] = (float)(1.0);
|
---|
212 | }
|
---|
213 |
|
---|
214 | void
|
---|
215 | Trackball::reapply()
|
---|
216 | {
|
---|
217 | addQuats(lastQuat, curQuat, curQuat);
|
---|
218 | }
|
---|