2 * Adapted to D by Antonio Monteiro
5 * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
7 * Permission to use, copy, modify, and distribute this software for
8 * any purpose and without fee is hereby granted, provided that the above
9 * copyright notice appear in all copies and that both the copyright notice
10 * and this permission notice appear in supporting documentation, and that
11 * the name of Silicon Graphics, Inc. not be used in advertising
12 * or publicity pertaining to distribution of the software without specific,
13 * written prior permission.
15 * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
16 * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
18 * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
20 * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
21 * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
22 * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
23 * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
24 * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
25 * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
26 * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
28 * US Government Users Restricted Rights
29 * Use, duplication, or disclosure by the Government is subject to
30 * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
31 * (c)(1)(ii) of the Rights in Technical Data and Computer Software
32 * clause at DFARS 252.227-7013 and/or in similar or successor
33 * clauses in the FAR or the DOD or NASA FAR Supplement.
34 * Unpublished-- rights reserved under the copyright laws of the
35 * United States. Contractor/manufacturer is Silicon Graphics,
36 * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
38 * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
42 * A virtual trackball implementation
43 * Written by Gavin Bell for Silicon Graphics, November 1988.
47 * This size should really be based on the distance from the center of
48 * rotation to the point on the object underneath the mouse. That
49 * point would then track the mouse as closely as possible. This is a
50 * simple example, though, so that is left as an Exercise for the
56 private import std
.math
;
59 const float TRACKBALLSIZE
= 0.8;
60 const int RENORMCOUNT
= 97;
63 * Pass the x and y coordinates of the last and current positions of
64 * the mouse, scaled so they are from (-1.0 ... 1.0).
66 * The resulting rotation is returned as a quaternion rotation in the
70 trackball(float q
[4], float p1x
, float p1y
, float p2x
, float p2y
)
73 * Ok, simulate a track-ball. Project the points onto the virtual
74 * trackball, then figure out the axis of rotation, which is the cross
75 * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
76 * Note: This is a deformed trackball-- is a trackball in the center,
77 * but is deformed into a hyperbolic sheet of rotation away from the
78 * center. This particular function was chosen after trying out
81 * It is assumed that the arguments to this routine are in the range
84 float[3] a
; /* Axis of rotation */
85 float phi
; /* how much to rotate about axis */
91 if (p1x
== p2x
&& p1y
== p2y
) {
99 * First, figure out z-coordinates for projection of P1 and P2 to
102 vset(p1
,p1x
,p1y
,tb_project_to_sphere(TRACKBALLSIZE
,p1x
,p1y
));
103 vset(p2
,p2x
,p2y
,tb_project_to_sphere(TRACKBALLSIZE
,p2x
,p2y
));
106 * Now, we want the cross product of P1 and P2
108 vcross(p2
.ptr
,p1
.ptr
,a
.ptr
);
111 * Figure out how much to rotate around that axis.
114 t
= vlength(d
) / (2.0*TRACKBALLSIZE
);
117 * Avoid problems with out-of-control values...
119 if (t
> 1.0) t
= 1.0;
120 if (t
< -1.0) t
= -1.0;
121 phi
= 2.0 * std
.math
.asin(t
);
123 axis_to_quat(a
,phi
,q
);
128 * Given two quaternions, add them together to get a third quaternion.
129 * Adding quaternions to get a compound rotation is analagous to adding
130 * translations to get a compound translation. When incrementally
131 * adding rotations, the first argument here should be the new
132 * rotation, the second and third the total rotation (which will be
133 * over-written with the resulting new total rotation).
136 add_quats(float[4] q1
, float[4] q2
, float[4] dest
)
139 * Given two rotations, e1 and e2, expressed as quaternion rotations,
140 * figure out the equivalent single rotation and stuff it into dest.
142 * This routine also normalizes the result every RENORMCOUNT times it is
143 * called, to keep error from creeping in.
145 * NOTE: This routine is written so that q1 or q2 may be the same
146 * as dest (or each other).
154 vcopy(q1
.ptr
,t1
.ptr
);
155 vscale(t1
.ptr
,q2
[3]);
157 vcopy(q2
.ptr
,t2
.ptr
);
158 vscale(t2
.ptr
,q1
[3]);
160 vcross(q2
.ptr
,q1
.ptr
,t3
.ptr
);
161 vadd(t1
.ptr
,t2
.ptr
,tf
.ptr
);
162 vadd(t3
.ptr
,tf
.ptr
,tf
.ptr
);
163 tf
[3] = q1
[3] * q2
[3] - vdot(q1
.ptr
,q2
.ptr
);
170 if (++count
> RENORMCOUNT
) {
172 normalize_quat(dest
);
178 * A useful function, builds a rotation matrix in Matrix based on
182 build_rotmatrix(float[4][4] m
, float[4] q
)
184 m
[0][0] = 1.0 - 2.0 * (q
[1] * q
[1] + q
[2] * q
[2]);
185 m
[0][1] = 2.0 * (q
[0] * q
[1] - q
[2] * q
[3]);
186 m
[0][2] = 2.0 * (q
[2] * q
[0] + q
[1] * q
[3]);
189 m
[1][0] = 2.0 * (q
[0] * q
[1] + q
[2] * q
[3]);
190 m
[1][1]= 1.0 - 2.0 * (q
[2] * q
[2] + q
[0] * q
[0]);
191 m
[1][2] = 2.0 * (q
[1] * q
[2] - q
[0] * q
[3]);
194 m
[2][0] = 2.0 * (q
[2] * q
[0] - q
[1] * q
[3]);
195 m
[2][1] = 2.0 * (q
[1] * q
[2] + q
[0] * q
[3]);
196 m
[2][2] = 1.0 - 2.0 * (q
[1] * q
[1] + q
[0] * q
[0]);
207 * This function computes a quaternion based on an axis (defined by
208 * the given vector) and an angle about which to rotate. The angle is
209 * expressed in radians. The result is put into the third argument.
212 axis_to_quat(float[3] a
, float phi
, float[4] q
)
216 vscale(q
.ptr
,sin(phi
/2.0));
221 * Quaternions always obey: a^2 + b^2 + c^2 + d^2 = 1.0
222 * If they don't add up to 1.0, dividing by their magnitued will
225 * Note: See the following for more information on quaternions:
227 * - Shoemake, K., Animating rotation with quaternion curves, Computer
228 * Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
229 * - Pletinckx, D., Quaternion calculus as a basic tool in computer
230 * graphics, The Visual Computer 5, 2-13, 1989.
233 normalize_quat(float[4] q
)
238 mag
= (q
[0]*q
[0] + q
[1]*q
[1] + q
[2]*q
[2] + q
[3]*q
[3]);
239 for (i
= 0; i
< 4; i
++) q
[i
] /= mag
;
243 * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
244 * if we are away from the center of the sphere.
247 tb_project_to_sphere(float r
, float x
, float y
)
252 if (d
< r
* 0.70710678118654752440) { /* Inside sphere */
254 } else { /* On hyperbola */
255 t
= r
/ 1.41421356237309504880;
270 vset(float[3] v
, float x
, float y
, float z
)
278 vsub(float[3] src1
, float[3] src2
, float[3] dst
)
280 dst
[0] = src1
[0] - src2
[0];
281 dst
[1] = src1
[1] - src2
[1];
282 dst
[2] = src1
[2] - src2
[2];
286 vcopy(float* v1
, float* v2
)
289 for (i
= 0 ; i
< 3 ; i
++)
294 vcross(float* v1
, float* v2
, float* cross
)
298 temp
[0] = (v1
[1] * v2
[2]) - (v1
[2] * v2
[1]);
299 temp
[1] = (v1
[2] * v2
[0]) - (v1
[0] * v2
[2]);
300 temp
[2] = (v1
[0] * v2
[1]) - (v1
[1] * v2
[0]);
301 vcopy(temp
.ptr
, cross
);
307 return sqrt(v
[0] * v
[0] + v
[1] * v
[1] + v
[2] * v
[2]);
311 vscale(float* v
, float div)
321 vscale(v
.ptr
,1.0/vlength(v
));
325 vdot(float* v1
, float* v2
)
327 return v1
[0]*v2
[0] + v1
[1]*v2
[1] + v1
[2]*v2
[2];
331 vadd(float* src1
, float* src2
, float* dst
)
333 dst
[0] = src1
[0] + src2
[0];
334 dst
[1] = src1
[1] + src2
[1];
335 dst
[2] = src1
[2] + src2
[2];