w3dquat.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  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/max2w3d/w3dquat.cpp 29 2/03/00 4:55p Jason_a $ */
  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 "w3dquat.h"
  50. #include "matrix3d.h"
  51. #include "matrix4.h"
  52. #include "wwmath.h"
  53. #include <stdio.h>
  54. //#include <iostream.h>
  55. #include <stdlib.h>
  56. #include <math.h>
  57. #include <assert.h>
  58. #define SLERP_EPSILON 0.001
  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 = WWMath::Sqrt(X * X + Y * Y + Z * Z + W * W);
  104. if (0.0f == mag) {
  105. return;
  106. } else {
  107. X /= mag;
  108. Y /= mag;
  109. Z /= mag;
  110. W /= mag;
  111. }
  112. }
  113. /***********************************************************************************************
  114. * Quaternion::operator= -- Assignment operator *
  115. * *
  116. * INPUT: *
  117. * *
  118. * OUTPUT: *
  119. * *
  120. * WARNINGS: *
  121. * *
  122. * HISTORY: *
  123. * 02/24/1997 GH : Created. *
  124. *=============================================================================================*/
  125. Quaternion & Quaternion::operator = (const Quaternion & source)
  126. {
  127. X = source[0];
  128. Y = source[1];
  129. Z = source[2];
  130. W = source[3];
  131. return *this;
  132. }
  133. /***********************************************************************************************
  134. * Q::Make_Closest -- Use nearest representation to the given quaternion. *
  135. * *
  136. * INPUT: *
  137. * *
  138. * OUTPUT: *
  139. * *
  140. * WARNINGS: *
  141. * *
  142. * HISTORY: *
  143. * 02/28/1997 GH : Created. *
  144. *=============================================================================================*/
  145. Quaternion & Quaternion::Make_Closest(const Quaternion & qto)
  146. {
  147. float cos_t = qto.X * X + qto.Y * Y + qto.Z * Z + qto.W * W;
  148. // if we are on opposite hemisphere from qto, negate ourselves
  149. if (cos_t < 0.0) {
  150. X = -X;
  151. Y = -Y;
  152. Z = -Z;
  153. W = -W;
  154. }
  155. return *this;
  156. }
  157. /***********************************************************************************************
  158. * Trackball -- Computes a "trackball" quaternion given 2D mouse coordinates *
  159. * *
  160. * INPUT: *
  161. * x0,y0 - x1,y1 - "normalized" mouse coordinates for the mouse movement *
  162. * sphsize - size of the trackball sphere *
  163. * *
  164. * OUTPUT: *
  165. * a quaternion representing the rotation of a trackball *
  166. * *
  167. * WARNINGS: *
  168. * *
  169. * HISTORY: *
  170. * 02/28/1997 GH : Created. *
  171. *=============================================================================================*/
  172. Quaternion Trackball(float x0, float y0, float x1, float y1, float sphsize)
  173. {
  174. Vector3 a;
  175. Vector3 p1;
  176. Vector3 p2;
  177. Vector3 d;
  178. float phi,t;
  179. if ((x0 == x1) && (y0 == y1)) {
  180. return Quaternion(0.0f, 0.0f, 0.0f, 1.0f); // Zero rotation
  181. }
  182. // Compute z coordinates for projection of p1 and p2 to
  183. // deformed sphere
  184. p1[0] = x0;
  185. p1[1] = y0;
  186. p1[2] = project_to_sphere(sphsize, x0, y0);
  187. p2[0] = x1;
  188. p2[1] = y1;
  189. p2[2] = project_to_sphere(sphsize, x1, y1);
  190. // Find their cross product
  191. Vector3::Cross_Product(p2,p1,&a);
  192. // Compute how much to rotate
  193. d = p1 - p2;
  194. t = d.Length() / (2.0f * sphsize);
  195. // Avoid problems with out of control values
  196. if (t > 1.0f) t = 1.0f;
  197. if (t < -1.0f) t = -1.0f;
  198. phi = 2.0f * asin(t);
  199. return Axis_To_Quat(a, phi);
  200. }
  201. /***********************************************************************************************
  202. * Axis_To_Quat -- Creates a quaternion given an axis and angle of rotation *
  203. * *
  204. * INPUT: *
  205. * *
  206. * OUTPUT: *
  207. * *
  208. * WARNINGS: *
  209. * *
  210. * HISTORY: *
  211. * 02/28/1997 GH : Created. *
  212. *=============================================================================================*/
  213. Quaternion Axis_To_Quat(const Vector3 &a, float phi)
  214. {
  215. Quaternion q;
  216. Vector3 tmp = a;
  217. tmp.Normalize();
  218. q[0] = tmp[0];
  219. q[1] = tmp[1];
  220. q[2] = tmp[2];
  221. q.Scale(sinf(phi / 2.0f));
  222. q[3] = cosf(phi / 2.0f);
  223. return q;
  224. }
  225. /***********************************************************************************************
  226. * Slerp -- Spherical Linear interpolation! *
  227. * *
  228. * INPUT: *
  229. * p - start quaternion *
  230. * q - end quaternion *
  231. * alpha - interpolating parameter *
  232. * *
  233. * OUTPUT: *
  234. * *
  235. * WARNINGS: *
  236. * *
  237. * HISTORY: *
  238. * 02/28/1997 GH : Created. *
  239. *=============================================================================================*/
  240. Quaternion Slerp(const Quaternion & p,const Quaternion & q,float alpha)
  241. {
  242. float beta; // complementary interploation parameter
  243. float theta; // angle between p and q
  244. float sin_t,cos_t; // sine, cosine of theta
  245. float oo_sin_t;
  246. int qflip; // use flip of q?
  247. // cos theta = dot product of p and q
  248. cos_t = p.X * q.X + p.Y * q.Y + p.Z * q.Z + p.W * q.W;
  249. // if q is on opposite hemisphere from A, use -B instead
  250. if (cos_t < 0.0) {
  251. cos_t = -cos_t;
  252. qflip = true;
  253. } else {
  254. qflip = false;
  255. }
  256. if (1.0 - cos_t < SLERP_EPSILON) {
  257. // if q is very close to p, just linearly interpolate
  258. // between the two.
  259. beta = 1.0 - alpha;
  260. } else {
  261. // normal slerp!
  262. theta = acos(cos_t);
  263. sin_t = sinf(theta);
  264. oo_sin_t = 1.0 / sin_t;
  265. beta = sinf(theta - alpha*theta) * oo_sin_t;
  266. alpha = sinf(alpha*theta) * oo_sin_t;
  267. }
  268. if (qflip) {
  269. alpha = -alpha;
  270. }
  271. Quaternion res;
  272. res.X = beta*p.X + alpha*q.X;
  273. res.Y = beta*p.Y + alpha*q.Y;
  274. res.Z = beta*p.Z + alpha*q.Z;
  275. res.W = beta*p.W + alpha*q.W;
  276. return res;
  277. }
  278. /***********************************************************************************************
  279. * Slerp_Setup -- Get ready to call "Cached_Slerp" *
  280. * *
  281. * INPUT: *
  282. * *
  283. * OUTPUT: *
  284. * *
  285. * WARNINGS: *
  286. * *
  287. * HISTORY: *
  288. * 2/27/98 GTH : Created. *
  289. *=============================================================================================*/
  290. void Slerp_Setup(const Quaternion & p,const Quaternion & q,SlerpInfoStruct * slerpinfo)
  291. {
  292. float cos_t;
  293. assert(slerpinfo != NULL);
  294. // cos theta = dot product of p and q
  295. cos_t = p.X * q.X + p.Y * q.Y + p.Z * q.Z + p.W * q.W;
  296. // if q is on opposite hemisphere from A, use -B instead
  297. if (cos_t < 0.0) {
  298. cos_t = -cos_t;
  299. slerpinfo->Flip = true;
  300. } else {
  301. slerpinfo->Flip = false;
  302. }
  303. if (1.0 - cos_t < SLERP_EPSILON) {
  304. slerpinfo->Linear = true;
  305. slerpinfo->Theta = 0.0f;
  306. slerpinfo->SinT = 0.0f;
  307. } else {
  308. slerpinfo->Linear = false;
  309. slerpinfo->Theta = acos(cos_t);
  310. slerpinfo->SinT = sinf(slerpinfo->Theta);
  311. }
  312. }
  313. /***********************************************************************************************
  314. * Cached_Slerp -- Quaternion slerping, optimized with cached values *
  315. * *
  316. * INPUT: *
  317. * *
  318. * OUTPUT: *
  319. * *
  320. * WARNINGS: *
  321. * *
  322. * HISTORY: *
  323. * 2/27/98 GTH : Created. *
  324. *=============================================================================================*/
  325. Quaternion Cached_Slerp(const Quaternion & p,const Quaternion & q,float alpha,SlerpInfoStruct * slerpinfo)
  326. {
  327. float beta; // complementary interploation parameter
  328. float oo_sin_t;
  329. if (slerpinfo->Linear) {
  330. // if q is very close to p, just linearly interpolate
  331. // between the two.
  332. beta = 1.0 - alpha;
  333. } else {
  334. // normal slerp!
  335. oo_sin_t = 1.0 / slerpinfo->Theta;
  336. beta = sin(slerpinfo->Theta - alpha*slerpinfo->Theta) * oo_sin_t;
  337. alpha = sin(alpha*slerpinfo->Theta) * oo_sin_t;
  338. }
  339. if (slerpinfo->Flip) {
  340. alpha = -alpha;
  341. }
  342. Quaternion res;
  343. res.X = beta*p.X + alpha*q.X;
  344. res.Y = beta*p.Y + alpha*q.Y;
  345. res.Z = beta*p.Z + alpha*q.Z;
  346. res.W = beta*p.W + alpha*q.W;
  347. return res;
  348. }
  349. void Cached_Slerp(const Quaternion & p,const Quaternion & q,float alpha,SlerpInfoStruct * slerpinfo,Quaternion * set_q)
  350. {
  351. float beta; // complementary interploation parameter
  352. float oo_sin_t;
  353. if (slerpinfo->Linear) {
  354. // if q is very close to p, just linearly interpolate
  355. // between the two.
  356. beta = 1.0 - alpha;
  357. } else {
  358. // normal slerp!
  359. oo_sin_t = 1.0 / slerpinfo->Theta;
  360. beta = sin(slerpinfo->Theta - alpha*slerpinfo->Theta) * oo_sin_t;
  361. alpha = sin(alpha*slerpinfo->Theta) * oo_sin_t;
  362. }
  363. if (slerpinfo->Flip) {
  364. alpha = -alpha;
  365. }
  366. set_q->X = beta*p.X + alpha*q.X;
  367. set_q->Y = beta*p.Y + alpha*q.Y;
  368. set_q->Z = beta*p.Z + alpha*q.Z;
  369. set_q->W = beta*p.W + alpha*q.W;
  370. }
  371. /***********************************************************************************************
  372. * Build_Quaternion -- Creates a quaternion from a Matrix *
  373. * *
  374. * INPUT: *
  375. * *
  376. * OUTPUT: *
  377. * *
  378. * WARNINGS: *
  379. * Matrix MUST NOT have scaling! *
  380. * *
  381. * HISTORY: *
  382. * 02/28/1997 GH : Created. *
  383. *=============================================================================================*/
  384. Quaternion Build_Quaternion(const Matrix3D & mat)
  385. {
  386. float tr,s;
  387. int i,j,k;
  388. Quaternion q;
  389. // sum the diagonal of the rotation matrix
  390. tr = mat[0][0] + mat[1][1] + mat[2][2];
  391. if (tr > 0.0f) {
  392. s = sqrt(tr + 1.0);
  393. q[3] = s * 0.5;
  394. s = 0.5 / s;
  395. q[0] = (mat[2][1] - mat[1][2]) * s;
  396. q[1] = (mat[0][2] - mat[2][0]) * s;
  397. q[2] = (mat[1][0] - mat[0][1]) * s;
  398. } else {
  399. i=0;
  400. if (mat[1][1] > mat[0][0]) i = 1;
  401. if (mat[2][2] > mat[i][i]) i = 2;
  402. j = _nxt[i];
  403. k = _nxt[j];
  404. s = sqrt((mat[i][i] - (mat[j][j] + mat[k][k])) + 1.0);
  405. q[i] = s * 0.5;
  406. if (s != 0.0) {
  407. s = 0.5 / s;
  408. }
  409. q[3] = ( mat[k][j] - mat[j][k] ) * s;
  410. q[j] = ( mat[j][i] + mat[i][j] ) * s;
  411. q[k] = ( mat[k][i] + mat[i][k] ) * s;
  412. }
  413. return q;
  414. }
  415. Quaternion Build_Quaternion(const Matrix3 & mat)
  416. {
  417. float tr,s;
  418. int i,j,k;
  419. Quaternion q;
  420. // sum the diagonal of the rotation matrix
  421. tr = mat[0][0] + mat[1][1] + mat[2][2];
  422. if (tr > 0.0) {
  423. s = sqrt(tr + 1.0);
  424. q[3] = s * 0.5;
  425. s = 0.5 / 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. } else {
  430. i = 0;
  431. if (mat[1][1] > mat[0][0]) i = 1;
  432. if (mat[2][2] > mat[i][i]) i = 2;
  433. j = _nxt[i];
  434. k = _nxt[j];
  435. s = sqrt( (mat[i][i] - (mat[j][j]+mat[k][k])) + 1.0);
  436. q[i] = s * 0.5;
  437. if (s != 0.0) {
  438. s = 0.5/s;
  439. }
  440. q[3] = ( mat[k][j] - mat[j][k] ) * s;
  441. q[j] = ( mat[j][i] + mat[i][j] ) * s;
  442. q[k] = ( mat[k][i] + mat[i][k] ) * s;
  443. }
  444. return q;
  445. }
  446. Quaternion Build_Quaternion(const Matrix4 & mat)
  447. {
  448. float tr,s;
  449. int i,j,k;
  450. Quaternion q;
  451. // sum the diagonal of the rotation matrix
  452. tr = mat[0][0] + mat[1][1] + mat[2][2];
  453. if (tr > 0.0) {
  454. s = sqrt(tr + 1.0);
  455. q[3] = s * 0.5;
  456. s = 0.5 / s;
  457. q[0] = (mat[2][1] - mat[1][2]) * s;
  458. q[1] = (mat[0][2] - mat[2][0]) * s;
  459. q[2] = (mat[1][0] - mat[0][1]) * s;
  460. } else {
  461. i = 0;
  462. if (mat[1][1] > mat[0][0]) i = 1;
  463. if (mat[2][2] > mat[i][i]) i = 2;
  464. j = _nxt[i];
  465. k = _nxt[j];
  466. s = sqrt( (mat[i][i] - (mat[j][j]+mat[k][k])) + 1.0);
  467. q[i] = s * 0.5;
  468. if (s != 0.0) {
  469. s = 0.5/s;
  470. }
  471. q[3] = ( mat[k][j] - mat[j][k] ) * s;
  472. q[j] = ( mat[j][i] + mat[i][j] ) * s;
  473. q[k] = ( mat[k][i] + mat[i][k] ) * s;
  474. }
  475. return q;
  476. }
  477. /***********************************************************************************************
  478. * Build_Matrix -- Creates a Matrix from a Quaternion *
  479. * *
  480. * INPUT: *
  481. * *
  482. * OUTPUT: *
  483. * *
  484. * WARNINGS: *
  485. * *
  486. * HISTORY: *
  487. * 02/28/1997 GH : Created. *
  488. *=============================================================================================*/
  489. Matrix3 Build_Matrix3(const Quaternion & q)
  490. {
  491. Matrix3 m;
  492. m[0][0] = (float)(1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]));
  493. m[0][1] = (float)(2.0 * (q[0] * q[1] - q[2] * q[3]));
  494. m[0][2] = (float)(2.0 * (q[2] * q[0] + q[1] * q[3]));
  495. m[1][0] = (float)(2.0 * (q[0] * q[1] + q[2] * q[3]));
  496. m[1][1] = (float)(1.0 - 2.0f * (q[2] * q[2] + q[0] * q[0]));
  497. m[1][2] = (float)(2.0 * (q[1] * q[2] - q[0] * q[3]));
  498. m[2][0] = (float)(2.0 * (q[2] * q[0] - q[1] * q[3]));
  499. m[2][1] = (float)(2.0 * (q[1] * q[2] + q[0] * q[3]));
  500. m[2][2] =(float)(1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]));
  501. return m;
  502. }
  503. Matrix3D Build_Matrix3D(const Quaternion & q)
  504. {
  505. Matrix3D m;
  506. // initialize the rotation sub-matrix
  507. m[0][0] = (float)(1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]));
  508. m[0][1] = (float)(2.0 * (q[0] * q[1] - q[2] * q[3]));
  509. m[0][2] = (float)(2.0 * (q[2] * q[0] + q[1] * q[3]));
  510. m[1][0] = (float)(2.0 * (q[0] * q[1] + q[2] * q[3]));
  511. m[1][1] = (float)(1.0 - 2.0f * (q[2] * q[2] + q[0] * q[0]));
  512. m[1][2] = (float)(2.0 * (q[1] * q[2] - q[0] * q[3]));
  513. m[2][0] = (float)(2.0 * (q[2] * q[0] - q[1] * q[3]));
  514. m[2][1] = (float)(2.0 * (q[1] * q[2] + q[0] * q[3]));
  515. m[2][2] =(float)(1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]));
  516. // no translation
  517. m[0][3] = m[1][3] = m[2][3] = 0.0f;
  518. return m;
  519. }
  520. Matrix4 Build_Matrix4(const Quaternion & q)
  521. {
  522. Matrix4 m;
  523. // initialize the rotation sub-matrix
  524. m[0][0] = (float)(1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]));
  525. m[0][1] = (float)(2.0 * (q[0] * q[1] - q[2] * q[3]));
  526. m[0][2] = (float)(2.0 * (q[2] * q[0] + q[1] * q[3]));
  527. m[1][0] = (float)(2.0 * (q[0] * q[1] + q[2] * q[3]));
  528. m[1][1] = (float)(1.0 - 2.0f * (q[2] * q[2] + q[0] * q[0]));
  529. m[1][2] = (float)(2.0 * (q[1] * q[2] - q[0] * q[3]));
  530. m[2][0] = (float)(2.0 * (q[2] * q[0] - q[1] * q[3]));
  531. m[2][1] = (float)(2.0 * (q[1] * q[2] + q[0] * q[3]));
  532. m[2][2] = (float)(1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]));
  533. // no translation
  534. m[0][3] = m[1][3] = m[2][3] = 0.0f;
  535. // last row
  536. m[3][0] = m[3][1] = m[3][2] = 0.0f;
  537. m[3][3] = 1.0f;
  538. return m;
  539. }
  540. void Quaternion::Rotate_X(float theta)
  541. {
  542. // TODO: optimize this
  543. *this = (*this) * Quaternion(Vector3(1,0,0),theta);
  544. }
  545. void Quaternion::Rotate_Y(float theta)
  546. {
  547. // TODO: optimize this
  548. *this = (*this) * Quaternion(Vector3(0,1,0),theta);
  549. }
  550. void Quaternion::Rotate_Z(float theta)
  551. {
  552. // TODO: optimize this
  553. *this = (*this) * Quaternion(Vector3(0,0,1),theta);
  554. }
  555. float project_to_sphere(float r, float x, float y)
  556. {
  557. const float SQRT2 = 1.41421356f;
  558. float t, z;
  559. float d = WWMath::Sqrt(x * x + y * y);
  560. if (d < r * (SQRT2/(2.0f))) // inside sphere
  561. z = WWMath::Sqrt(r * r - d * d);
  562. else { // on hyperbola
  563. t = r / SQRT2;
  564. z = t * t / d;
  565. }
  566. return z;
  567. }
  568. void Quaternion::Randomize(void)
  569. {
  570. X = ((float) (rand() & 0xFFFF)) / 65536.0f;
  571. Y = ((float) (rand() & 0xFFFF)) / 65536.0f;
  572. Z = ((float) (rand() & 0xFFFF)) / 65536.0f;
  573. W = ((float) (rand() & 0xFFFF)) / 65536.0f;
  574. Normalize();
  575. }