Max 5 API Reference
00001 /* 00002 * (c) Copyright 1993, 1994, Silicon Graphics, Inc. 00003 * ALL RIGHTS RESERVED 00004 * Permission to use, copy, modify, and distribute this software for 00005 * any purpose and without fee is hereby granted, provided that the above 00006 * copyright notice appear in all copies and that both the copyright notice 00007 * and this permission notice appear in supporting documentation, and that 00008 * the name of Silicon Graphics, Inc. not be used in advertising 00009 * or publicity pertaining to distribution of the software without specific, 00010 * written prior permission. 00011 * 00012 * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" 00013 * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, 00014 * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR 00015 * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON 00016 * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT, 00017 * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY 00018 * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, 00019 * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF 00020 * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN 00021 * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON 00022 * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE 00023 * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. 00024 * 00025 * US Government Users Restricted Rights 00026 * Use, duplication, or disclosure by the Government is subject to 00027 * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph 00028 * (c)(1)(ii) of the Rights in Technical Data and Computer Software 00029 * clause at DFARS 252.227-7013 and/or in similar or successor 00030 * clauses in the FAR or the DOD or NASA FAR Supplement. 00031 * Unpublished-- rights reserved under the copyright laws of the 00032 * United States. Contractor/manufacturer is Silicon Graphics, 00033 * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311. 00034 * 00035 * OpenGL(TM) is a trademark of Silicon Graphics, Inc. 00036 */ 00037 /* 00038 * Trackball code: 00039 * 00040 * Implementation of a virtual trackball. 00041 * Implemented by Gavin Bell, lots of ideas from Thant Tessman and 00042 * the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129. 00043 * 00044 * Vector manip code: 00045 * 00046 * Original code from: 00047 * David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli 00048 * 00049 * Much mucking with by: 00050 * Gavin Bell 00051 */ 00052 00053 #include <math.h> 00054 #include "trackball.h" 00055 #include "jit.gl.h" 00056 #include "jit.math.h" 00057 00058 /* 00059 * This size should really be based on the distance from the center of 00060 * rotation to the point on the object underneath the mouse. That 00061 * point would then track the mouse as closely as possible. This is a 00062 * simple example, though, so that is left as an Exercise for the 00063 * Programmer. 00064 */ 00065 #define TRACKBALLSIZE (0.4) 00066 00067 /* 00068 * Local function prototypes (not defined in trackball.h) 00069 */ 00070 static float tb_project_to_sphere(float, float, float); 00071 static void normalize_quat(float [4]); 00072 static void normalize_quatd(double [4]); 00073 00074 void 00075 vzero(float *v) 00076 { 00077 v[0] = 0.0; 00078 v[1] = 0.0; 00079 v[2] = 0.0; 00080 } 00081 00082 void 00083 vset(float *v, float x, float y, float z) 00084 { 00085 v[0] = x; 00086 v[1] = y; 00087 v[2] = z; 00088 } 00089 00090 void 00091 vsub(const float *src1, const float *src2, float *dst) 00092 { 00093 dst[0] = src1[0] - src2[0]; 00094 dst[1] = src1[1] - src2[1]; 00095 dst[2] = src1[2] - src2[2]; 00096 } 00097 00098 void 00099 vcopy(const float *v1, float *v2) 00100 { 00101 register int i; 00102 for (i = 0 ; i < 3 ; i++) 00103 v2[i] = v1[i]; 00104 } 00105 00106 void 00107 vcross(const float *v1, const float *v2, float *cross) 00108 { 00109 float temp[3]; 00110 00111 temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]); 00112 temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]); 00113 temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]); 00114 vcopy(temp, cross); 00115 } 00116 00117 float 00118 vlength(const float *v) 00119 { 00120 return jit_math_sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); 00121 } 00122 00123 void 00124 vscale(float *v, float div) 00125 { 00126 v[0] *= div; 00127 v[1] *= div; 00128 v[2] *= div; 00129 } 00130 00131 void 00132 vnormal(float *v) 00133 { 00134 vscale(v,1.0/vlength(v)); 00135 } 00136 00137 float vdot(const float *v1, const float *v2) 00138 { 00139 return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; 00140 } 00141 00142 void vadd(const float *src1, const float *src2, float *dst) 00143 { 00144 dst[0] = src1[0] + src2[0]; 00145 dst[1] = src1[1] + src2[1]; 00146 dst[2] = src1[2] + src2[2]; 00147 } 00148 00149 00150 void 00151 vdzero(double *v) 00152 { 00153 v[0] = 0.0; 00154 v[1] = 0.0; 00155 v[2] = 0.0; 00156 } 00157 00158 void 00159 vdset(double *v, double x, double y, double z) 00160 { 00161 v[0] = x; 00162 v[1] = y; 00163 v[2] = z; 00164 } 00165 00166 void 00167 vdsub(const double *src1, const double *src2, double *dst) 00168 { 00169 dst[0] = src1[0] - src2[0]; 00170 dst[1] = src1[1] - src2[1]; 00171 dst[2] = src1[2] - src2[2]; 00172 } 00173 00174 void 00175 vdcopy(const double *v1, double *v2) 00176 { 00177 register int i; 00178 for (i = 0 ; i < 3 ; i++) 00179 v2[i] = v1[i]; 00180 } 00181 00182 void 00183 vdcross(const double *v1, const double *v2, double *cross) 00184 { 00185 double temp[3]; 00186 00187 temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]); 00188 temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]); 00189 temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]); 00190 vdcopy(temp, cross); 00191 } 00192 00193 double 00194 vdlength(const double *v) 00195 { 00196 return jit_math_sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); 00197 } 00198 00199 void 00200 vdscale(double *v, double div) 00201 { 00202 v[0] *= div; 00203 v[1] *= div; 00204 v[2] *= div; 00205 } 00206 00207 void 00208 vdnormal(double *v) 00209 { 00210 vdscale(v,1.0/vdlength(v)); 00211 } 00212 00213 double vddot(const double *v1, const double *v2) 00214 { 00215 return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; 00216 } 00217 00218 void vdadd(const double *src1, const double *src2, double *dst) 00219 { 00220 dst[0] = src1[0] + src2[0]; 00221 dst[1] = src1[1] + src2[1]; 00222 dst[2] = src1[2] + src2[2]; 00223 } 00224 00225 00226 /* 00227 * Ok, simulate a track-ball. Project the points onto the virtual 00228 * trackball, then figure out the axis of rotation, which is the cross 00229 * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0) 00230 * Note: This is a deformed trackball-- is a trackball in the center, 00231 * but is deformed into a hyperbolic sheet of rotation away from the 00232 * center. This particular function was chosen after trying out 00233 * several variations. 00234 * 00235 * It is assumed that the arguments to this routine are in the range 00236 * (-1.0 ... 1.0) 00237 */ 00238 void 00239 trackball(float q[4], float p1x, float p1y, float p2x, float p2y) 00240 { 00241 float a[3]; /* Axis of rotation */ 00242 float phi; /* how much to rotate about axis */ 00243 float p1[3], p2[3], d[3]; 00244 float t; 00245 00246 if (p1x == p2x && p1y == p2y) { 00247 /* Zero rotation */ 00248 vzero(q); 00249 q[3] = 1.0; 00250 return; 00251 } 00252 00253 /* 00254 * First, figure out z-coordinates for projection of P1 and P2 to 00255 * deformed sphere 00256 */ 00257 vset(p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y)); 00258 vset(p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y)); 00259 00260 /* 00261 * Now, we want the cross product of P1 and P2 00262 */ 00263 vcross(p2,p1,a); 00264 00265 /* 00266 * Figure out how much to rotate around that axis. 00267 */ 00268 vsub(p1,p2,d); 00269 t = vlength(d) / (2.0*TRACKBALLSIZE); 00270 00271 /* 00272 * Avoid problems with out-of-control values... 00273 */ 00274 if (t > 1.0) t = 1.0; 00275 if (t < -1.0) t = -1.0; 00276 phi = 2.0 * jit_math_asin(t); 00277 00278 axis_to_quat(a,phi,q); 00279 } 00280 00281 /* 00282 * Given an axis and angle, compute quaternion. 00283 */ 00284 void 00285 axis_to_quat(float a[3], float phi, float q[4]) 00286 { 00287 vnormal(a); 00288 vcopy(a,q); 00289 vscale(q,jit_math_sin(phi/2.0)); 00290 q[3] = jit_math_cos(phi/2.0); 00291 } 00292 00293 00294 // compute axis/angle rotation from quaternion. added by rej. 00295 void 00296 quat_to_axis(float q[4], float axis[3], float * phi) 00297 { 00298 float cos_a, sin_a; 00299 00300 cos_a = q[3]; 00301 *phi = jit_math_acos(cos_a) * 2.; 00302 sin_a = jit_math_sqrt(1.0 - cos_a * cos_a); 00303 00304 if (fabs(sin_a) < 0.0005) 00305 sin_a = 1; 00306 00307 axis[0] = q[0] / sin_a; 00308 axis[1] = q[1] / sin_a; 00309 axis[2] = q[2] / sin_a; 00310 } 00311 00312 void 00313 xyz_to_axis(float xyz[3], float axis[3], float * phi) 00314 { 00315 float vec[3]; 00316 float q1[4],q2[4],q3[4]; 00317 00318 // convert xyz to angle/axis 00319 jit_gl_set_floats(vec, 3, 1., 0., 0.); 00320 axis_to_quat(vec, xyz[0], q1); 00321 00322 jit_gl_set_floats(vec, 3, 0., 1., 0.); 00323 axis_to_quat(vec, xyz[1], q2); 00324 add_quats(q1,q2,q3); 00325 00326 jit_gl_set_floats(vec, 3, 0., 0., 1.); 00327 axis_to_quat(vec, xyz[2], q2); 00328 add_quats(q3,q2,q1); 00329 00330 normalize_quat(q1); // to solve people's complaints with rotatexyz differing by ~0.00001% 00331 00332 quat_to_axis(q1, axis, phi); 00333 } 00334 00335 void 00336 axis_to_xyz(float axis[3], float phi, float xyz[3]) 00337 { 00338 double fCos = cos(phi); 00339 double fSin = sin(phi); 00340 double fOneMinusCos = 1.0-fCos; 00341 double fX2 = axis[0]*axis[0]; 00342 double fY2 = axis[1]*axis[1]; 00343 double fZ2 = axis[2]*axis[2]; 00344 double fXYM = axis[0]*axis[1]*fOneMinusCos; 00345 double fXZM = axis[0]*axis[2]*fOneMinusCos; 00346 double fYZM = axis[1]*axis[2]*fOneMinusCos; 00347 double fXSin = axis[0]*fSin; 00348 double fYSin = axis[1]*fSin; 00349 double fZSin = axis[2]*fSin; 00350 double m[9]; 00351 00352 // convert axis angle to rotation matrix 00353 m[0] = fX2*fOneMinusCos+fCos; 00354 m[1] = fXYM-fZSin; 00355 m[2] = fXZM+fYSin; 00356 m[3] = fXYM+fZSin; 00357 m[4] = fY2*fOneMinusCos+fCos; 00358 m[5] = fYZM-fXSin; 00359 m[6] = fXZM-fYSin; 00360 m[7] = fYZM+fXSin; 00361 m[8] = fZ2*fOneMinusCos+fCos; 00362 00363 00364 // convert matrix to euler angles 00365 00366 // fromEulerAnglesZYX (ZYX the mathematical order of matrix concatenation) 00367 // rot = cy*cz cz*sx*sy-cx*sz cx*cz*sy+sx*sz 00368 // cy*sz cx*cz+sx*sy*sz -cz*sx+cx*sy*sz 00369 // -sy cy*sx cx*cy 00370 00371 if ( m[6] < 1.0 ) 00372 { 00373 if ( m[6] > -1.0 ) 00374 { 00375 xyz[2] = atan2(m[3],m[0]); 00376 xyz[1] = asin(-(double)m[6]); 00377 xyz[0] = atan2(m[7],m[8]); 00378 } 00379 else 00380 { 00381 // WARNING. Not unique. ZA - XA = -atan2(r01,r02) 00382 xyz[2] = -atan2(m[1],m[2]); 00383 xyz[1] = PI/2.0; 00384 xyz[0] = 0.0; 00385 } 00386 } 00387 else 00388 { 00389 // WARNING. Not unique. ZA + XA = atan2(-r01,-r02) 00390 xyz[2] = atan2(-m[1],-m[2]); 00391 xyz[1] = -PI/2.0; 00392 xyz[0] = 0.0; 00393 } 00394 } 00395 00396 /* 00397 * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet 00398 * if we are away from the center of the sphere. 00399 */ 00400 static float 00401 tb_project_to_sphere(float r, float x, float y) 00402 { 00403 float d, t, z; 00404 00405 d = jit_math_sqrt(x*x + y*y); 00406 if (d < r * 0.70710678118654752440) { /* Inside sphere */ 00407 z = jit_math_sqrt(r*r - d*d); 00408 } else { /* On hyperbola */ 00409 t = r / 1.41421356237309504880; 00410 z = t*t / d; 00411 } 00412 return z; 00413 } 00414 00415 /* 00416 * Given two rotations, e1 and e2, expressed as quaternion rotations, 00417 * figure out the equivalent single rotation and stuff it into dest. 00418 * 00419 * This routine also normalizes the result every RENORMCOUNT times it is 00420 * called, to keep error from creeping in. 00421 * 00422 * NOTE: This routine is written so that q1 or q2 may be the same 00423 * as dest (or each other). 00424 */ 00425 00426 #define RENORMCOUNT 0 //97 00427 00428 00429 void 00430 add_quats(float q1[4], float q2[4], float dest[4]) 00431 { 00432 static int count=0; 00433 double qd1[4],qd2[4]; 00434 double t1[4], t2[4], t3[4]; 00435 double tf[4]; 00436 00437 //vdcopy(qd1,t1); 00438 t1[0] = qd1[0] = q1[0]; 00439 t1[1] = qd1[1] = q1[1]; 00440 t1[2] = qd1[2] = q1[2]; 00441 t1[3] = qd1[3] = q1[3]; 00442 00443 //vdcopy(qd2,t2); 00444 t2[0] = qd2[0] = q2[0]; 00445 t2[1] = qd2[1] = q2[1]; 00446 t2[2] = qd2[2] = q2[2]; 00447 t2[3] = qd2[3] = q2[3]; 00448 00449 vdscale(t1,qd2[3]); 00450 vdscale(t2,qd1[3]); 00451 00452 vdcross(qd2,qd1,t3); 00453 vdadd(t1,t2,tf); 00454 vdadd(t3,tf,tf); 00455 tf[3] = qd1[3] * qd2[3] - vddot(qd1,qd2); 00456 00457 normalize_quatd(tf); 00458 00459 dest[0] = tf[0]; 00460 dest[1] = tf[1]; 00461 dest[2] = tf[2]; 00462 dest[3] = tf[3]; 00463 00464 } 00465 00466 /*void 00467 add_quats(float q1[4], float q2[4], float dest[4]) 00468 { 00469 static int count=0; 00470 float t1[4], t2[4], t3[4]; 00471 float tf[4]; 00472 00473 vcopy(q1,t1); 00474 vscale(t1,q2[3]); 00475 00476 vcopy(q2,t2); 00477 vscale(t2,q1[3]); 00478 00479 vcross(q2,q1,t3); 00480 vadd(t1,t2,tf); 00481 vadd(t3,tf,tf); 00482 tf[3] = q1[3] * q2[3] - vdot(q1,q2); 00483 00484 dest[0] = tf[0]; 00485 dest[1] = tf[1]; 00486 dest[2] = tf[2]; 00487 dest[3] = tf[3]; 00488 00489 if (++count > RENORMCOUNT) { 00490 count = 0; 00491 normalize_quat(dest); 00492 } 00493 } 00494 */ 00495 00496 /* 00497 * Quaternions always obey: a^2 + b^2 + c^2 + d^2 = 1.0 00498 * If they don't add up to 1.0, dividing by their magnitude will 00499 * renormalize them. 00500 * 00501 * Note: See the following for more information on quaternions: 00502 * 00503 * - Shoemake, K., Animating rotation with quaternion curves, Computer 00504 * Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985. 00505 * - Pletinckx, D., Quaternion calculus as a basic tool in computer 00506 * graphics, The Visual Computer 5, 2-13, 1989. 00507 */ 00508 static void 00509 normalize_quat(float q[4]) 00510 { 00511 int i; 00512 float mag; 00513 00514 mag = 1./(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]); 00515 for (i = 0; i < 4; i++) q[i] *= mag; 00516 } 00517 00518 static void 00519 normalize_quatd(double q[4]) 00520 { 00521 int i; 00522 double mag; 00523 00524 mag = 1./(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]); 00525 for (i = 0; i < 4; i++) q[i] *= mag; 00526 } 00527 00528 /* 00529 * Build a rotation matrix, given a quaternion rotation. 00530 * where the matrix is m1 m4 m8 m12 00531 * m2 m5 m9 m13 00532 * m3 m6 m10 m14 00533 * m4 m7 m11 m15 00534 * 00535 */ 00536 00537 void 00538 build_rotmatrix(float m[16], float q[4]) 00539 { 00540 m[0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]); 00541 m[4] = 2.0 * (q[0] * q[1] - q[2] * q[3]); 00542 m[8] = 2.0 * (q[2] * q[0] + q[1] * q[3]); 00543 m[12] = 0.0; 00544 00545 m[1] = 2.0 * (q[0] * q[1] + q[2] * q[3]); 00546 m[5] = 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]); 00547 m[9] = 2.0 * (q[1] * q[2] - q[0] * q[3]); 00548 m[13] = 0.0; 00549 00550 m[2] = 2.0 * (q[2] * q[0] - q[1] * q[3]); 00551 m[6] = 2.0 * (q[1] * q[2] + q[0] * q[3]); 00552 m[10] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]); 00553 m[14] = 0.0; 00554 00555 m[3] = 0.0; 00556 m[7] = 0.0; 00557 m[11] = 0.0; 00558 m[15] = 1.0; 00559 } 00560 00561 00562 /* 00563 * Transform a point (column vector) by a 4x4 matrix. I.e. out = m * in 00564 * Input: m - the 4x4 matrix 00565 * in - the 4x1 vector 00566 * Output: out - the resulting 4x1 vector. 00567 */ 00568 void transform_point(const float in[4], const float m[16], float out[4]) 00569 { 00570 #define M(row,col) m[col*4+row] 00571 out[0] = 00572 M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3]; 00573 out[1] = 00574 M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3]; 00575 out[2] = 00576 M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3]; 00577 out[3] = 00578 M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3]; 00579 #undef M 00580 } 00581 00582
Copyright © 2008, Cycling '74