quat.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* $Header: /Commando/Code/Tools/W3DShellExt/External/quat.cpp 1 1/02/02 1:18p Moumine_ballo $ */
  19. /***********************************************************************************************
  20. *** Confidential - Westwood Studios ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Voxel Technology *
  24. * *
  25. * File Name : QUAT.CPP *
  26. * *
  27. * Programmer : Greg Hjelstrom *
  28. * *
  29. * Start Date : 02/24/97 *
  30. * *
  31. * Last Update : February 28, 1997 [GH] *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * Quaternion::Quaternion -- constructor *
  36. * Quaternion::Set -- Set the quaternion *
  37. * Quaternion::operator= -- Assignment operator *
  38. * Quaternion::Make_Closest -- Use nearest representation to the given quaternion. *
  39. * Trackball -- Computes a "trackball" quaternion given 2D mouse coordinates *
  40. * Axis_To_Quat -- Creates a quaternion given an axis and angle of rotation *
  41. * Slerp -- Spherical Linear interpolation! *
  42. * Build_Quaternion -- Creates a quaternion from a Matrix *
  43. * Build_Matrix -- Creates a Matrix from a Quaternion *
  44. * Normalize -- normalizes a quaternion *
  45. * Quaternion::Quaternion -- constructor *
  46. * Slerp_Setup -- Get ready to call "Cached_Slerp" *
  47. * Cached_Slerp -- Quaternion slerping, optimized with cached values *
  48. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  49. #include <stdio.h>
  50. //#include <iostream.h>
  51. #include <stdlib.h>
  52. #include <math.h>
  53. #include <assert.h>
  54. //#include "math_util.h"
  55. #include "quat.h"
  56. #include "matrix3d.h"
  57. #include "matrix4.h"
  58. #define SLERP_EPSILON 0.001f
  59. static int _nxt[3] = { 1 , 2, 0 };
  60. // ------------------------------------------------------------
  61. // local functions
  62. // ------------------------------------------------------------
  63. static float Project_To_Sphere(float, float, float);
  64. /***********************************************************************************************
  65. * Quaternion::Quaternion -- constructor *
  66. * *
  67. * constructs a quaternion from the given axis and angle of rotation (in RADIANS of course) *
  68. * *
  69. * INPUT: *
  70. * axis - axis of the rotation *
  71. * angle - rotation angle *
  72. * *
  73. * OUTPUT: *
  74. * *
  75. * WARNINGS: *
  76. * *
  77. * HISTORY: *
  78. * 12/10/97 GTH : Created. *
  79. *=============================================================================================*/
  80. Quaternion::Quaternion(const Vector3 & axis,float angle)
  81. {
  82. float s = sinf(angle/2);
  83. float c = cosf(angle/2);
  84. X = s * axis.X;
  85. Y = s * axis.Y;
  86. Z = s * axis.Z;
  87. W = c;
  88. }
  89. /***********************************************************************************************
  90. * Quaternion::Normalize -- Normalize to a unit quaternion *
  91. * *
  92. * INPUT: *
  93. * *
  94. * OUTPUT: *
  95. * *
  96. * WARNINGS: *
  97. * *
  98. * HISTORY: *
  99. * 02/24/1997 GH : Created. *
  100. *=============================================================================================*/
  101. void Quaternion::Normalize()
  102. {
  103. float mag = 1.0f / (float)sqrt(X * X + Y * Y + Z * Z + W * W);
  104. X *= mag;
  105. Y *= mag;
  106. Z *= mag;
  107. W *= mag;
  108. }
  109. /***********************************************************************************************
  110. * Quaternion::operator= -- Assignment operator *
  111. * *
  112. * INPUT: *
  113. * *
  114. * OUTPUT: *
  115. * *
  116. * WARNINGS: *
  117. * *
  118. * HISTORY: *
  119. * 02/24/1997 GH : Created. *
  120. *=============================================================================================*/
  121. Quaternion & Quaternion::operator = (const Quaternion & source)
  122. {
  123. X = source[0];
  124. Y = source[1];
  125. Z = source[2];
  126. W = source[3];
  127. return *this;
  128. }
  129. /***********************************************************************************************
  130. * Q::Make_Closest -- Use nearest representation to the given quaternion. *
  131. * *
  132. * INPUT: *
  133. * *
  134. * OUTPUT: *
  135. * *
  136. * WARNINGS: *
  137. * *
  138. * HISTORY: *
  139. * 02/28/1997 GH : Created. *
  140. *=============================================================================================*/
  141. Quaternion & Quaternion::Make_Closest(const Quaternion & qto)
  142. {
  143. float cos_t = qto.X * X + qto.Y * Y + qto.Z * Z + qto.W * W;
  144. // if we are on opposite hemisphere from qto, negate ourselves
  145. if (cos_t < 0.0f)
  146. {
  147. X = -X;
  148. Y = -Y;
  149. Z = -Z;
  150. W = -W;
  151. }
  152. return *this;
  153. }
  154. /***********************************************************************************************
  155. * Trackball -- Computes a "trackball" quaternion given 2D mouse coordinates *
  156. * *
  157. * INPUT: *
  158. * x0,y0 - x1,y1 - "normalized" mouse coordinates for the mouse movement *
  159. * sphsize - size of the trackball sphere *
  160. * *
  161. * OUTPUT: *
  162. * a quaternion representing the rotation of a trackball *
  163. * *
  164. * WARNINGS: *
  165. * *
  166. * HISTORY: *
  167. * 02/28/1997 GH : Created. *
  168. *=============================================================================================*/
  169. Quaternion Trackball(float x0, float y0, float x1, float y1, float sphsize)
  170. {
  171. Vector3 a;
  172. Vector3 p1;
  173. Vector3 p2;
  174. Vector3 d;
  175. float phi,t;
  176. if ((x0 == x1) && (y0 == y1))
  177. {
  178. return Quaternion(0.0f, 0.0f, 0.0f, 1.0f); // Zero rotation
  179. }
  180. // Compute z coordinates for projection of p1 and p2 to
  181. // deformed sphere
  182. p1[0] = x0;
  183. p1[1] = y0;
  184. p1[2] = Project_To_Sphere(sphsize, x0, y0);
  185. p2[0] = x1;
  186. p2[1] = y1;
  187. p2[2] = Project_To_Sphere(sphsize, x1, y1);
  188. // Find their cross product
  189. Vector3::Cross_Product(p2,p1,&a);
  190. // Compute how much to rotate
  191. d = p1 - p2;
  192. t = d.Length() / (2.0f * sphsize);
  193. // Avoid problems with out of control values
  194. if (t > 1.0f) t = 1.0f;
  195. if (t < -1.0f) t = -1.0f;
  196. phi = 2.0f * asinf(t);
  197. return Axis_To_Quat(a, phi);
  198. }
  199. /***********************************************************************************************
  200. * Axis_To_Quat -- Creates a quaternion given an axis and angle of rotation *
  201. * *
  202. * INPUT: *
  203. * *
  204. * OUTPUT: *
  205. * *
  206. * WARNINGS: *
  207. * *
  208. * HISTORY: *
  209. * 02/28/1997 GH : Created. *
  210. *=============================================================================================*/
  211. Quaternion Axis_To_Quat(const Vector3 &a, float phi)
  212. {
  213. Quaternion q;
  214. Vector3 tmp = a;
  215. tmp.Normalize();
  216. q[0] = tmp[0];
  217. q[1] = tmp[1];
  218. q[2] = tmp[2];
  219. q.Scale(sinf(phi / 2.0f));
  220. q[3] = cosf(phi / 2.0f);
  221. return q;
  222. }
  223. /***********************************************************************************************
  224. * Slerp -- Spherical Linear interpolation! *
  225. * *
  226. * INPUT: *
  227. * p - start quaternion *
  228. * q - end quaternion *
  229. * alpha - interpolating parameter *
  230. * *
  231. * OUTPUT: *
  232. * *
  233. * WARNINGS: *
  234. * *
  235. * HISTORY: *
  236. * 02/28/1997 GH : Created. *
  237. *=============================================================================================*/
  238. Quaternion Slerp(const Quaternion & p,const Quaternion & q,float alpha)
  239. {
  240. float beta; // complementary interploation parameter
  241. float theta; // angle between p and q
  242. float sin_t,cos_t; // sine, cosine of theta
  243. float oo_sin_t;
  244. int qflip; // use flip of q?
  245. // cos theta = dot product of p and q
  246. cos_t = p.X * q.X + p.Y * q.Y + p.Z * q.Z + p.W * q.W;
  247. // if q is on opposite hemisphere from A, use -B instead
  248. if (cos_t < 0.0f)
  249. {
  250. cos_t = -cos_t;
  251. qflip = true;
  252. }
  253. else
  254. {
  255. qflip = false;
  256. }
  257. if (1.0f - cos_t < SLERP_EPSILON)
  258. {
  259. // if q is very close to p, just linearly interpolate
  260. // between the two.
  261. beta = 1.0f - (float)alpha;
  262. }
  263. else
  264. {
  265. // normal slerp!
  266. theta = acosf(cos_t);
  267. sin_t = sinf(theta);
  268. oo_sin_t = 1.0f / sin_t;
  269. beta = sinf(theta - alpha*theta) * oo_sin_t;
  270. alpha = sinf(alpha*theta) * oo_sin_t;
  271. }
  272. if (qflip)
  273. {
  274. alpha = -alpha;
  275. }
  276. Quaternion res;
  277. res.X = beta*p.X + alpha*q.X;
  278. res.Y = beta*p.Y + alpha*q.Y;
  279. res.Z = beta*p.Z + alpha*q.Z;
  280. res.W = beta*p.W + alpha*q.W;
  281. return res;
  282. }
  283. /***********************************************************************************************
  284. * Slerp_Setup -- Get ready to call "Cached_Slerp" *
  285. * *
  286. * INPUT: *
  287. * *
  288. * OUTPUT: *
  289. * *
  290. * WARNINGS: *
  291. * *
  292. * HISTORY: *
  293. * 2/27/98 GTH : Created. *
  294. *=============================================================================================*/
  295. void Slerp_Setup(
  296. const Quaternion & p,
  297. const Quaternion & q,
  298. SlerpInfoStruct* slerpinfo)
  299. {
  300. float cos_t;
  301. assert(!slerpinfo);
  302. // cos theta = dot product of p and q
  303. cos_t = p.X * q.X + p.Y * q.Y + p.Z * q.Z + p.W * q.W;
  304. // if q is on opposite hemisphere from A, use -B instead
  305. if (cos_t < 0.0f)
  306. {
  307. cos_t = -cos_t;
  308. slerpinfo->Flip = true;
  309. }
  310. else
  311. {
  312. slerpinfo->Flip = false;
  313. }
  314. if (1.0 - cos_t < SLERP_EPSILON)
  315. {
  316. slerpinfo->Linear = true;
  317. slerpinfo->Theta = 0.0f;
  318. slerpinfo->SinT = 0.0f;
  319. }
  320. else
  321. {
  322. slerpinfo->Linear = false;
  323. slerpinfo->Theta = acosf(cos_t);
  324. slerpinfo->SinT = sinf(slerpinfo->Theta);
  325. }
  326. }
  327. /***********************************************************************************************
  328. * Cached_Slerp -- Quaternion slerping, optimized with cached values *
  329. * *
  330. * INPUT: *
  331. * *
  332. * OUTPUT: *
  333. * *
  334. * WARNINGS: *
  335. * *
  336. * HISTORY: *
  337. * 2/27/98 GTH : Created. *
  338. *=============================================================================================*/
  339. Quaternion Cached_Slerp(
  340. const Quaternion & p,
  341. const Quaternion & q,
  342. float alpha,
  343. SlerpInfoStruct * slerpinfo)
  344. {
  345. float beta; // complementary interploation parameter
  346. float oo_sin_t;
  347. if (slerpinfo->Linear)
  348. {
  349. // if q is very close to p, just linearly interpolate
  350. // between the two.
  351. beta = 1.0f - alpha;
  352. }
  353. else
  354. {
  355. // normal slerp!
  356. oo_sin_t = 1.0f / slerpinfo->Theta;
  357. beta = sinf(slerpinfo->Theta - alpha*slerpinfo->Theta) * oo_sin_t;
  358. alpha = sinf(alpha*slerpinfo->Theta) * oo_sin_t;
  359. }
  360. if (slerpinfo->Flip)
  361. {
  362. alpha = -alpha;
  363. }
  364. Quaternion res;
  365. res.X = beta*p.X + alpha*q.X;
  366. res.Y = beta*p.Y + alpha*q.Y;
  367. res.Z = beta*p.Z + alpha*q.Z;
  368. res.W = beta*p.W + alpha*q.W;
  369. return res;
  370. }
  371. void Cached_Slerp(
  372. const Quaternion & p,
  373. const Quaternion & q,
  374. float alpha,SlerpInfoStruct * slerpinfo,
  375. Quaternion * set_q)
  376. {
  377. float beta; // complementary interploation parameter
  378. float oo_sin_t;
  379. if (slerpinfo->Linear)
  380. {
  381. // if q is very close to p, just linearly interpolate
  382. // between the two.
  383. beta = 1.0f - alpha;
  384. }
  385. else
  386. {
  387. // normal slerp!
  388. oo_sin_t = 1.0f / slerpinfo->Theta;
  389. beta = sinf(slerpinfo->Theta - alpha*slerpinfo->Theta) * oo_sin_t;
  390. alpha = sinf(alpha*slerpinfo->Theta) * oo_sin_t;
  391. }
  392. if (slerpinfo->Flip)
  393. {
  394. alpha = -alpha;
  395. }
  396. set_q->X = beta*p.X + alpha*q.X;
  397. set_q->Y = beta*p.Y + alpha*q.Y;
  398. set_q->Z = beta*p.Z + alpha*q.Z;
  399. set_q->W = beta*p.W + alpha*q.W;
  400. }
  401. /***********************************************************************************************
  402. * Build_Quaternion -- Creates a quaternion from a Matrix *
  403. * *
  404. * INPUT: *
  405. * *
  406. * OUTPUT: *
  407. * *
  408. * WARNINGS: *
  409. * Matrix MUST NOT have scaling! *
  410. * *
  411. * HISTORY: *
  412. * 02/28/1997 GH : Created. *
  413. *=============================================================================================*/
  414. Quaternion Build_Quaternion(const Matrix3D & mat)
  415. {
  416. float tr,s;
  417. int i,j,k;
  418. Quaternion q;
  419. // sum the diagonal of the rotation matrix
  420. tr = mat[0][0] + mat[1][1] + mat[2][2];
  421. if (tr > 0.0f)
  422. {
  423. s = (float)sqrt(tr + 1.0f);
  424. q[3] = s * 0.5f;
  425. s = 0.5f / s;
  426. q[0] = (mat[2][1] - mat[1][2]) * s;
  427. q[1] = (mat[0][2] - mat[2][0]) * s;
  428. q[2] = (mat[1][0] - mat[0][1]) * s;
  429. }
  430. else
  431. {
  432. i=0;
  433. if (mat[1][1] > mat[0][0]) i = 1;
  434. if (mat[2][2] > mat[i][i]) i = 2;
  435. j = _nxt[i];
  436. k = _nxt[j];
  437. s = (float)sqrt((mat[i][i] - (mat[j][j] + mat[k][k])) + 1.0f);
  438. q[i] = s * 0.5f;
  439. if (s != 0.0f)
  440. {
  441. s = 0.5f / s;
  442. }
  443. q[3] = ( mat[k][j] - mat[j][k] ) * s;
  444. q[j] = ( mat[j][i] + mat[i][j] ) * s;
  445. q[k] = ( mat[k][i] + mat[i][k] ) * s;
  446. }
  447. return q;
  448. }
  449. Quaternion Build_Quaternion(const Matrix3 & mat)
  450. {
  451. float tr,s;
  452. int i,j,k;
  453. Quaternion q;
  454. // sum the diagonal of the rotation matrix
  455. tr = mat[0][0] + mat[1][1] + mat[2][2];
  456. if (tr > 0.0f)
  457. {
  458. s = (float)sqrt(tr + 1.0f);
  459. q[3] = s * 0.5f;
  460. s = 0.5f / s;
  461. q[0] = (mat[2][1] - mat[1][2]) * s;
  462. q[1] = (mat[0][2] - mat[2][0]) * s;
  463. q[2] = (mat[1][0] - mat[0][1]) * s;
  464. }
  465. else
  466. {
  467. i = 0;
  468. if (mat[1][1] > mat[0][0]) i = 1;
  469. if (mat[2][2] > mat[i][i]) i = 2;
  470. j = _nxt[i];
  471. k = _nxt[j];
  472. s = (float)sqrt( (mat[i][i] - (mat[j][j]+mat[k][k])) + 1.0f);
  473. q[i] = s * 0.5f;
  474. if (s != 0.0f)
  475. {
  476. s = 0.5f/s;
  477. }
  478. q[3] = ( mat[k][j] - mat[j][k] ) * s;
  479. q[j] = ( mat[j][i] + mat[i][j] ) * s;
  480. q[k] = ( mat[k][i] + mat[i][k] ) * s;
  481. }
  482. return q;
  483. }
  484. Quaternion Build_Quaternion(const Matrix4 & mat)
  485. {
  486. float tr,s;
  487. int i,j,k;
  488. Quaternion q;
  489. // sum the diagonal of the rotation matrix
  490. tr = mat[0][0] + mat[1][1] + mat[2][2];
  491. if (tr > 0.0f)
  492. {
  493. s = (float)sqrt(tr + 1.0f);
  494. q[3] = s * 0.5f;
  495. s = 0.5f / s;
  496. q[0] = (mat[2][1] - mat[1][2]) * s;
  497. q[1] = (mat[0][2] - mat[2][0]) * s;
  498. q[2] = (mat[1][0] - mat[0][1]) * s;
  499. }
  500. else
  501. {
  502. i = 0;
  503. if (mat[1][1] > mat[0][0]) i = 1;
  504. if (mat[2][2] > mat[i][i]) i = 2;
  505. j = _nxt[i];
  506. k = _nxt[j];
  507. s = (float)sqrt( (mat[i][i] - (mat[j][j]+mat[k][k])) + 1.0f);
  508. q[i] = s * 0.5f;
  509. if (s != 0.0f)
  510. {
  511. s = 0.5f/s;
  512. }
  513. q[3] = ( mat[k][j] - mat[j][k] ) * s;
  514. q[j] = ( mat[j][i] + mat[i][j] ) * s;
  515. q[k] = ( mat[k][i] + mat[i][k] ) * s;
  516. }
  517. return q;
  518. }
  519. /***********************************************************************************************
  520. * Build_Matrix -- Creates a Matrix from a Quaternion *
  521. * *
  522. * INPUT: *
  523. * *
  524. * OUTPUT: *
  525. * *
  526. * WARNINGS: *
  527. * *
  528. * HISTORY: *
  529. * 02/28/1997 GH : Created. *
  530. *=============================================================================================*/
  531. Matrix3 Build_Matrix3(const Quaternion & q)
  532. {
  533. Matrix3 m;
  534. m[0][0] = (1.0f - 2.0f * (q[1] * q[1] + q[2] * q[2]));
  535. m[0][1] = (2.0f * (q[0] * q[1] - q[2] * q[3]));
  536. m[0][2] = (2.0f * (q[2] * q[0] + q[1] * q[3]));
  537. m[1][0] = (2.0f * (q[0] * q[1] + q[2] * q[3]));
  538. m[1][1] = (1.0f - 2.0f * (q[2] * q[2] + q[0] * q[0]));
  539. m[1][2] = (2.0f * (q[1] * q[2] - q[0] * q[3]));
  540. m[2][0] = (2.0f * (q[2] * q[0] - q[1] * q[3]));
  541. m[2][1] = (2.0f * (q[1] * q[2] + q[0] * q[3]));
  542. m[2][2] =(1.0f - 2.0f * (q[1] * q[1] + q[0] * q[0]));
  543. return m;
  544. }
  545. Matrix3D Build_Matrix3D(const Quaternion & q)
  546. {
  547. Matrix3D m;
  548. // initialize the rotation sub-matrix
  549. m[0][0] = (1.0f - 2.0f * (q[1] * q[1] + q[2] * q[2]));
  550. m[0][1] = (2.0f * (q[0] * q[1] - q[2] * q[3]));
  551. m[0][2] = (2.0f * (q[2] * q[0] + q[1] * q[3]));
  552. m[1][0] = (2.0f * (q[0] * q[1] + q[2] * q[3]));
  553. m[1][1] = (1.0f - 2.0f * (q[2] * q[2] + q[0] * q[0]));
  554. m[1][2] = (2.0f * (q[1] * q[2] - q[0] * q[3]));
  555. m[2][0] = (2.0f * (q[2] * q[0] - q[1] * q[3]));
  556. m[2][1] = (2.0f * (q[1] * q[2] + q[0] * q[3]));
  557. m[2][2] =(1.0f - 2.0f * (q[1] * q[1] + q[0] * q[0]));
  558. // no translation
  559. m[0][3] = m[1][3] = m[2][3] = 0.0f;
  560. return m;
  561. }
  562. // JAC - Modified to create matrix already transposed
  563. Matrix4 Build_Matrix4(const Quaternion & q)
  564. {
  565. Matrix4 m;
  566. // initialize the rotation sub-matrix
  567. m[0][0] = (1.0f - 2.0f * (q[1] * q[1] + q[2] * q[2]));
  568. m[0][1] = (2.0f * (q[0] * q[1] - q[2] * q[3]));
  569. m[0][2] = (2.0f * (q[2] * q[0] + q[1] * q[3]));
  570. m[1][0] = (2.0f * (q[0] * q[1] + q[2] * q[3]));
  571. m[1][1] = (1.0f - 2.0f * (q[2] * q[2] + q[0] * q[0]));
  572. m[1][2] = (2.0f * (q[1] * q[2] - q[0] * q[3]));
  573. m[2][0] = (2.0f * (q[2] * q[0] - q[1] * q[3]));
  574. m[2][1] = (2.0f * (q[1] * q[2] + q[0] * q[3]));
  575. m[2][2] = (1.0f - 2.0f * (q[1] * q[1] + q[0] * q[0]));
  576. // no translation
  577. m[0][3] = m[1][3] = m[2][3] = 0.0f;
  578. // last row
  579. m[3][0] = m[3][1] = m[3][2] = 0.0f;
  580. m[3][3] = 1.0f;
  581. return m;
  582. }
  583. void Quaternion::Rotate_X(float theta)
  584. {
  585. // TODO: optimize this
  586. *this = (*this) * Quaternion(Vector3(1,0,0),theta);
  587. }
  588. void Quaternion::Rotate_Y(float theta)
  589. {
  590. // TODO: optimize this
  591. *this = (*this) * Quaternion(Vector3(0,1,0),theta);
  592. }
  593. void Quaternion::Rotate_Z(float theta)
  594. {
  595. // TODO: optimize this
  596. *this = (*this) * Quaternion(Vector3(0,0,1),theta);
  597. }
  598. float Project_To_Sphere(float r, float x, float y)
  599. {
  600. float t, z;
  601. float d = (float)sqrt(x * x + y * y);
  602. // Commented out code to get it to compile. Kludge but this code shouldn't be needed here
  603. if (d < r * ((float)sqrt(2.0f)/(2.0f))) // inside sphere
  604. {
  605. z = (float)sqrt(r * r - d * d);
  606. }
  607. else
  608. { // on hyperbola
  609. t = r / (float)sqrt(2.0f);
  610. z = t * t / d;
  611. }
  612. return z;
  613. }
  614. void Quaternion::Randomize(void)
  615. {
  616. X = ((float) (rand() & 0xFFFF)) / 65536.0f;
  617. Y = ((float) (rand() & 0xFFFF)) / 65536.0f;
  618. Z = ((float) (rand() & 0xFFFF)) / 65536.0f;
  619. W = ((float) (rand() & 0xFFFF)) / 65536.0f;
  620. Normalize();
  621. }