/Daniel Ormisher 20279203 - Warpath/Source/Math/CMatrix3x3.cpp

https://github.com/jcvandan/Warpath · C++ · 2159 lines · 1551 code · 341 blank · 267 comment · 77 complexity · 1e263469bd37333e827a3c62f1c1557b MD5 · raw file

  1. /**************************************************************************************************
  2. Module: CMatrix3x3.h
  3. Author: Laurent Noel
  4. Date created: 12/06/06
  5. Implementation of the concrete class CMatrix3x3, a 3x3 matrix of 32-bit floats. Designed for
  6. transformation matrices for 3D graphics or affine transformations for 2D graphics
  7. See notes at top of header for some background to this class. Also see "Essential Mathematics
  8. for Games & Interactive Applications" (Van Verth & Bishop) for the mathematics behind the more
  9. complex code (e.g rotation conversions)
  10. Copyright 2006, University of Central Lancashire and Laurent Noel
  11. Change history:
  12. V1.0 Created 12/06/06 - LN
  13. **************************************************************************************************/
  14. #include "CMatrix3x3.h"
  15. #include "Error.h"
  16. #include "CMatrix2x2.h"
  17. #include "CQuaternion.h"
  18. namespace gen
  19. {
  20. /*-----------------------------------------------------------------------------------------
  21. Constructors/Destructors
  22. -----------------------------------------------------------------------------------------*/
  23. // Construct by value
  24. CMatrix3x3::CMatrix3x3
  25. (
  26. const TFloat32 elt00, const TFloat32 elt01, const TFloat32 elt02,
  27. const TFloat32 elt10, const TFloat32 elt11, const TFloat32 elt12,
  28. const TFloat32 elt20, const TFloat32 elt21, const TFloat32 elt22
  29. )
  30. {
  31. e00 = elt00;
  32. e01 = elt01;
  33. e02 = elt02;
  34. e10 = elt10;
  35. e11 = elt11;
  36. e12 = elt12;
  37. e20 = elt20;
  38. e21 = elt21;
  39. e22 = elt22;
  40. }
  41. // Construct through pointer to 9 floats, may specify row/column order of data
  42. CMatrix3x3::CMatrix3x3
  43. (
  44. const TFloat32* pfElts,
  45. const bool bRows /*= true*/
  46. )
  47. {
  48. GEN_GUARD_OPT;
  49. GEN_ASSERT_OPT( pfElts, "Invalid parameter" );
  50. if (bRows)
  51. {
  52. e00 = pfElts[0];
  53. e01 = pfElts[1];
  54. e02 = pfElts[2];
  55. e10 = pfElts[3];
  56. e11 = pfElts[4];
  57. e12 = pfElts[5];
  58. e20 = pfElts[6];
  59. e21 = pfElts[7];
  60. e22 = pfElts[8];
  61. }
  62. else
  63. {
  64. e00 = pfElts[0];
  65. e10 = pfElts[1];
  66. e20 = pfElts[2];
  67. e01 = pfElts[3];
  68. e11 = pfElts[4];
  69. e21 = pfElts[5];
  70. e02 = pfElts[6];
  71. e12 = pfElts[7];
  72. e22 = pfElts[8];
  73. }
  74. GEN_ENDGUARD_OPT;
  75. }
  76. // Construct by row or column using CVector3's, may specify if setting rows or columns
  77. CMatrix3x3::CMatrix3x3
  78. (
  79. const CVector3& v0,
  80. const CVector3& v1,
  81. const CVector3& v2,
  82. const bool bRows /*= true*/
  83. )
  84. {
  85. if (bRows)
  86. {
  87. e00 = v0.x;
  88. e01 = v0.y;
  89. e02 = v0.z;
  90. e10 = v1.x;
  91. e11 = v1.y;
  92. e12 = v1.z;
  93. e20 = v2.x;
  94. e21 = v2.y;
  95. e22 = v2.z;
  96. }
  97. else
  98. {
  99. e00 = v0.x;
  100. e10 = v0.y;
  101. e20 = v0.z;
  102. e01 = v1.x;
  103. e11 = v1.y;
  104. e21 = v1.z;
  105. e02 = v2.x;
  106. e12 = v2.y;
  107. e22 = v2.z;
  108. }
  109. }
  110. // Construct by row or column using CVector2's, remaining elements taken from identity matrix
  111. // May specify if setting rows or columns
  112. CMatrix3x3::CMatrix3x3
  113. (
  114. const CVector2& v0,
  115. const CVector2& v1,
  116. const CVector2& v2,
  117. const bool bRows /*= true*/
  118. )
  119. {
  120. if (bRows)
  121. {
  122. e00 = v0.x;
  123. e01 = v0.y;
  124. e02 = 0.0f;
  125. e10 = v1.x;
  126. e11 = v1.y;
  127. e12 = 0.0f;
  128. e20 = v2.x;
  129. e21 = v2.y;
  130. e22 = 0.0f;
  131. }
  132. else
  133. {
  134. e00 = v0.x;
  135. e10 = v0.y;
  136. e01 = v1.x;
  137. e11 = v1.y;
  138. e02 = v2.x;
  139. e12 = v2.y;
  140. e20 = 0.0f;
  141. e21 = 0.0f;
  142. e22 = 1.0f;
  143. }
  144. }
  145. // Construct matrix transformation from euler angles and optional scaling. Matrix is effectively
  146. // built in this order: M = Scale*Rotation
  147. CMatrix3x3::CMatrix3x3
  148. (
  149. const CVector3& angles,
  150. const ERotationOrder eRotOrder /*= kZXY*/,
  151. const CVector3& scale /*= CVector3::kOne*/
  152. )
  153. {
  154. // First build rotation matrix
  155. MakeRotation( angles, eRotOrder );
  156. // Scale matrix
  157. e00 *= scale.x;
  158. e01 *= scale.x;
  159. e02 *= scale.x;
  160. e10 *= scale.y;
  161. e11 *= scale.y;
  162. e12 *= scale.y;
  163. e20 *= scale.z;
  164. e21 *= scale.z;
  165. e22 *= scale.z;
  166. }
  167. // Construct matrix transformation from quaternion and optional scaling. Matrix is effectively
  168. // built in this order: M = Scale*Rotation
  169. CMatrix3x3::CMatrix3x3
  170. (
  171. const CQuaternion& quat,
  172. const CVector3& scale /*= CVector3::kOne*/
  173. )
  174. {
  175. // Efficiently precalculate some values from the quaternion
  176. TFloat32 xx = 2*quat.x;
  177. TFloat32 yy = 2*quat.y;
  178. TFloat32 zz = 2*quat.z;
  179. TFloat32 xy = xx*quat.y;
  180. TFloat32 yz = yy*quat.z;
  181. TFloat32 zx = zz*quat.x;
  182. TFloat32 wx = quat.w*xx;
  183. TFloat32 wy = quat.w*yy;
  184. TFloat32 wz = quat.w*zz;
  185. xx *= quat.x;
  186. yy *= quat.y;
  187. zz *= quat.z;
  188. // Fill upper 3x3 matrix, combining scaling with rotation values from the quaternion
  189. e00 = scale.x * (1 - yy - zz);
  190. e01 = scale.x * (xy + wz);
  191. e02 = scale.x * (zx - wy);
  192. e10 = scale.y * (xy - wz);
  193. e11 = scale.y * (1 - xx - zz);
  194. e12 = scale.y * (yz + wx);
  195. e20 = scale.z * (zx + wy);
  196. e21 = scale.z * (yz - wx);
  197. e22 = scale.z * (1 - xx - yy);
  198. }
  199. // Construct matrix transformation from axis/angle of rotation and optional scaling. Matrix is
  200. // effectively built in this order: M = Scale*Rotation
  201. CMatrix3x3::CMatrix3x3
  202. (
  203. const CVector3& axis,
  204. const TFloat32 fAngle,
  205. const CVector3& scale /*= CVector3::kOne*/
  206. )
  207. {
  208. // First build rotation matrix
  209. MakeRotation( axis, fAngle );
  210. // Scale matrix
  211. e00 *= scale.x;
  212. e01 *= scale.x;
  213. e02 *= scale.x;
  214. e10 *= scale.y;
  215. e11 *= scale.y;
  216. e12 *= scale.y;
  217. e20 *= scale.z;
  218. e21 *= scale.z;
  219. e22 *= scale.z;
  220. }
  221. // Construct 2D affine transformation from position (translation) only
  222. CMatrix3x3::CMatrix3x3( const CVector2& position )
  223. {
  224. // Take most elements from identity
  225. e00 = 1.0f;
  226. e01 = 0.0f;
  227. e02 = 0.0f;
  228. e10 = 0.0f;
  229. e11 = 1.0f;
  230. e12 = 0.0f;
  231. // Put position (translation) in bottom row
  232. e20 = position.x;
  233. e21 = position.y;
  234. e22 = 1.0f;
  235. }
  236. // Construct 2D affine transformation from position, rotation angle and optional scaling, with
  237. // remaining elements taken from the identity matrix. Matrix is effectively built in this
  238. // order: M = Scale*Rotation*Translation
  239. CMatrix3x3::CMatrix3x3
  240. (
  241. const CVector2& position,
  242. const TFloat32 fAngle,
  243. const CVector2& scale /*= CVector2::kOne*/
  244. )
  245. {
  246. TFloat32 s, c;
  247. SinCos( fAngle, &s, &c );
  248. e00 = c * scale.x;
  249. e01 = s * scale.x;
  250. e02 = 0.0f;
  251. e10 = -s * scale.y;
  252. e11 = c * scale.y;
  253. e12 = 0.0f;
  254. e20 = position.x;
  255. e21 = position.y;
  256. e22 = 1.0f;
  257. }
  258. // Construct from a CMatrix2x2 and optional 2D position, with remaining elements taken from
  259. // the identity matrix
  260. CMatrix3x3::CMatrix3x3
  261. (
  262. const CMatrix2x2& m,
  263. const CVector2& position /*= CVector2::kOrigin*/
  264. )
  265. {
  266. // Copy 2x2 elements, adding extra identity elements
  267. e00 = m.e00;
  268. e01 = m.e01;
  269. e02 = 0.0f;
  270. e10 = m.e10;
  271. e11 = m.e11;
  272. e12 = 0.0f;
  273. // Put position (translation) in bottom row
  274. e20 = position.x;
  275. e21 = position.y;
  276. e22 = 1.0f;
  277. }
  278. // Copy constructor
  279. CMatrix3x3::CMatrix3x3( const CMatrix3x3& m )
  280. {
  281. e00 = m.e00;
  282. e01 = m.e01;
  283. e02 = m.e02;
  284. e10 = m.e10;
  285. e11 = m.e11;
  286. e12 = m.e12;
  287. e20 = m.e20;
  288. e21 = m.e21;
  289. e22 = m.e22;
  290. }
  291. // Assignment operator
  292. CMatrix3x3& CMatrix3x3::operator=( const CMatrix3x3& m )
  293. {
  294. if ( this != &m )
  295. {
  296. e00 = m.e00;
  297. e01 = m.e01;
  298. e02 = m.e02;
  299. e10 = m.e10;
  300. e11 = m.e11;
  301. e12 = m.e12;
  302. e20 = m.e20;
  303. e21 = m.e21;
  304. e22 = m.e22;
  305. }
  306. return *this;
  307. }
  308. /*-----------------------------------------------------------------------------------------
  309. Setters
  310. -----------------------------------------------------------------------------------------*/
  311. // Set by value
  312. void CMatrix3x3::Set
  313. (
  314. const TFloat32 elt00, const TFloat32 elt01, const TFloat32 elt02,
  315. const TFloat32 elt10, const TFloat32 elt11, const TFloat32 elt12,
  316. const TFloat32 elt20, const TFloat32 elt21, const TFloat32 elt22
  317. )
  318. {
  319. e00 = elt00;
  320. e01 = elt01;
  321. e02 = elt02;
  322. e10 = elt10;
  323. e11 = elt11;
  324. e12 = elt12;
  325. e20 = elt20;
  326. e21 = elt21;
  327. e22 = elt22;
  328. }
  329. // Set through pointer to 9 floats, may specify column/row order of data
  330. void CMatrix3x3::Set
  331. (
  332. const TFloat32* pfElts,
  333. const bool bRows /*= true*/
  334. )
  335. {
  336. GEN_GUARD_OPT;
  337. GEN_ASSERT_OPT( pfElts, "Invalid parameter" );
  338. if (bRows)
  339. {
  340. e00 = pfElts[0];
  341. e01 = pfElts[1];
  342. e02 = pfElts[2];
  343. e10 = pfElts[3];
  344. e11 = pfElts[4];
  345. e12 = pfElts[5];
  346. e20 = pfElts[6];
  347. e21 = pfElts[7];
  348. e22 = pfElts[8];
  349. }
  350. else
  351. {
  352. e00 = pfElts[0];
  353. e10 = pfElts[1];
  354. e20 = pfElts[2];
  355. e01 = pfElts[3];
  356. e11 = pfElts[4];
  357. e21 = pfElts[5];
  358. e02 = pfElts[6];
  359. e12 = pfElts[7];
  360. e22 = pfElts[8];
  361. }
  362. GEN_ENDGUARD_OPT;
  363. }
  364. /*-----------------------------------------------------------------------------------------
  365. Row/column getters & setters
  366. -----------------------------------------------------------------------------------------*/
  367. // Get a single row (range 0-2) of the matrix
  368. CVector3 CMatrix3x3::GetRow( const TUInt32 iRow ) const
  369. {
  370. GEN_GUARD_OPT;
  371. GEN_ASSERT_OPT( iRow < 3, "Invalid parameter" );
  372. return CVector3( &e00 + iRow * 3 );
  373. GEN_ENDGUARD_OPT;
  374. }
  375. // Get a single column (range 0-2) of the matrix
  376. CVector3 CMatrix3x3::GetColumn( const TUInt32 iCol ) const
  377. {
  378. GEN_GUARD_OPT;
  379. GEN_ASSERT_OPT( iCol < 3, "Invalid parameter" );
  380. const TFloat32* pfElts = &e00 + iCol;
  381. return CVector3( pfElts[0], pfElts[3], pfElts[6] );
  382. GEN_ENDGUARD_OPT;
  383. }
  384. // Set a single row (range 0-2) of the matrix
  385. void CMatrix3x3::SetRow
  386. (
  387. const TUInt32 iRow,
  388. const CVector3& v
  389. )
  390. {
  391. GEN_GUARD_OPT;
  392. GEN_ASSERT_OPT( iRow < 3, "Invalid parameter" );
  393. TFloat32* pfElts = &e00 + iRow * 3;
  394. pfElts[0] = v.x;
  395. pfElts[1] = v.y;
  396. pfElts[2] = v.z;
  397. GEN_ENDGUARD_OPT;
  398. }
  399. // Set a single row (range 0-2) of the matrix using a CVector2. Third element left unchanged
  400. void CMatrix3x3::SetRow
  401. (
  402. const TUInt32 iRow,
  403. const CVector2& v
  404. )
  405. {
  406. GEN_GUARD_OPT;
  407. GEN_ASSERT_OPT( iRow < 3, "Invalid parameter" );
  408. TFloat32* pfElts = &e00 + iRow * 3;
  409. pfElts[0] = v.x;
  410. pfElts[1] = v.y;
  411. GEN_ENDGUARD_OPT;
  412. }
  413. // Set a single column (range 0-2) of the matrix
  414. void CMatrix3x3::SetColumn
  415. (
  416. const TUInt32 iCol,
  417. const CVector3& v
  418. )
  419. {
  420. GEN_GUARD_OPT;
  421. GEN_ASSERT_OPT( iCol < 3, "Invalid parameter" );
  422. TFloat32* pfElts = &e00 + iCol;
  423. pfElts[0] = v.x;
  424. pfElts[3] = v.y;
  425. pfElts[6] = v.z;
  426. GEN_ENDGUARD_OPT;
  427. }
  428. // Set a single column (range 0-2) of the matrix using a CVector2. Third element left unchanged
  429. void CMatrix3x3::SetColumn
  430. (
  431. const TUInt32 iCol,
  432. const CVector2& v
  433. )
  434. {
  435. GEN_GUARD_OPT;
  436. GEN_ASSERT_OPT( iCol < 3, "Invalid parameter" );
  437. TFloat32* pfElts = &e00 + iCol;
  438. pfElts[0] = v.x;
  439. pfElts[3] = v.y;
  440. GEN_ENDGUARD_OPT;
  441. }
  442. // Set all rows of the matrix at once
  443. void CMatrix3x3::SetRows
  444. (
  445. const CVector3& v0,
  446. const CVector3& v1,
  447. const CVector3& v2
  448. )
  449. {
  450. e00 = v0.x;
  451. e01 = v0.y;
  452. e02 = v0.z;
  453. e10 = v1.x;
  454. e11 = v1.y;
  455. e12 = v1.z;
  456. e20 = v2.x;
  457. e21 = v2.y;
  458. e22 = v2.z;
  459. }
  460. // Set all rows of the matrix at once using CVector2, with remaining elements taken from the
  461. // identity matrix
  462. void CMatrix3x3::SetRows
  463. (
  464. const CVector2& v0,
  465. const CVector2& v1,
  466. const CVector2& v2
  467. )
  468. {
  469. e00 = v0.x;
  470. e01 = v0.y;
  471. e02 = 0.0f;
  472. e10 = v1.x;
  473. e11 = v1.y;
  474. e12 = 0.0f;
  475. e20 = v2.x;
  476. e21 = v2.y;
  477. e22 = 1.0f;
  478. }
  479. // Set all columns of the matrix at once
  480. void CMatrix3x3::SetColumns
  481. (
  482. const CVector3& v0,
  483. const CVector3& v1,
  484. const CVector3& v2
  485. )
  486. {
  487. e00 = v0.x;
  488. e10 = v0.y;
  489. e20 = v0.z;
  490. e01 = v1.x;
  491. e11 = v1.y;
  492. e21 = v1.z;
  493. e02 = v2.x;
  494. e12 = v2.y;
  495. e22 = v2.z;
  496. }
  497. // Set all columns of the matrix at once using CVector2, with remaining elements taken from the
  498. // identity matrix
  499. void CMatrix3x3::SetColumns
  500. (
  501. const CVector2& v0,
  502. const CVector2& v1,
  503. const CVector2& v2
  504. )
  505. {
  506. e00 = v0.x;
  507. e10 = v0.y;
  508. e01 = v1.x;
  509. e11 = v1.y;
  510. e02 = v2.x;
  511. e12 = v2.y;
  512. e20 = 0.0f;
  513. e21 = 0.0f;
  514. e22 = 1.0f;
  515. }
  516. /*-----------------------------------------------------------------------------------------
  517. Creation and Decomposition of Affine Matrices
  518. -----------------------------------------------------------------------------------------*/
  519. // Make matrix a transformation using Euler angles & optional scaling, with remaining elements
  520. // taken from the identity matrix. May specify order to apply rotations. Matrix is built in
  521. // this order: M = Scale*Rotation
  522. void CMatrix3x3::MakeTransformEuler
  523. (
  524. const CVector3& angles,
  525. const ERotationOrder eRotOrder /*= kZXY*/,
  526. const CVector3& scale /*= CVector3::kOne*/
  527. )
  528. {
  529. // First build rotation matrix
  530. MakeRotation( angles, eRotOrder );
  531. // Scale matrix
  532. e00 *= scale.x;
  533. e01 *= scale.x;
  534. e02 *= scale.x;
  535. e10 *= scale.y;
  536. e11 *= scale.y;
  537. e12 *= scale.y;
  538. e20 *= scale.z;
  539. e21 *= scale.z;
  540. e22 *= scale.z;
  541. }
  542. // Make matrix a transformation using quaternion & optional scaling, with remaining elements
  543. // taken from the identity matrix. Matrix is built in this order: M = Scale*Rotation
  544. void CMatrix3x3::MakeTransformQuaternion
  545. (
  546. const CQuaternion& quat,
  547. const CVector3& scale /*= CVector3::kOne*/
  548. )
  549. {
  550. // Efficiently precalculate some values from the quaternion
  551. TFloat32 xx = 2*quat.x;
  552. TFloat32 yy = 2*quat.y;
  553. TFloat32 zz = 2*quat.z;
  554. TFloat32 xy = xx*quat.y;
  555. TFloat32 yz = yy*quat.z;
  556. TFloat32 zx = zz*quat.x;
  557. TFloat32 wx = quat.w*xx;
  558. TFloat32 wy = quat.w*yy;
  559. TFloat32 wz = quat.w*zz;
  560. xx *= quat.x;
  561. yy *= quat.y;
  562. zz *= quat.z;
  563. // Fill upper 3x3 matrix, combining scaling with rotation values from the quaternion
  564. e00 = scale.x * (1 - yy - zz);
  565. e01 = scale.x * (xy + wz);
  566. e02 = scale.x * (zx - wy);
  567. e10 = scale.y * (xy - wz);
  568. e11 = scale.y * (1 - xx - zz);
  569. e12 = scale.y * (yz + wx);
  570. e20 = scale.z * (zx + wy);
  571. e21 = scale.z * (yz - wx);
  572. e22 = scale.z * (1 - xx - yy);
  573. }
  574. // Make matrix a transformation using angle/axis of rotation and optional scaling, with
  575. // remaining elements taken from the identity matrix
  576. // Matrix is built in this order: M = Scale*Rotation*Translation
  577. void CMatrix3x3::MakeTransformAxisAngle
  578. (
  579. const CVector3& axis,
  580. const TFloat32 fAngle,
  581. const CVector3& scale /*= CVector3::kOne*/
  582. )
  583. {
  584. // First build rotation matrix
  585. MakeRotation( axis, fAngle );
  586. // Scale matrix
  587. e00 *= scale.x;
  588. e01 *= scale.x;
  589. e02 *= scale.x;
  590. e10 *= scale.y;
  591. e11 *= scale.y;
  592. e12 *= scale.y;
  593. e20 *= scale.z;
  594. e21 *= scale.z;
  595. e22 *= scale.z;
  596. }
  597. // Decompose transformation into Euler angles of rotation (X, Y & Z angles of rotation around
  598. // each axis) and scale. Optionally pass order of rotations. Pass NULL for any unneeded
  599. // parameters. Assumes matrix is built in this order: M = Scale*Rotation
  600. void CMatrix3x3::DecomposeTransformEuler
  601. (
  602. CVector3* pAngles,
  603. CVector3* pScale,
  604. const ERotationOrder eRotOrder /*= kZXY*/
  605. ) const
  606. {
  607. GEN_GUARD;
  608. // Calculate matrix scaling
  609. TFloat32 scaleX = Sqrt( e00*e00 + e01*e01 + e02*e02 );
  610. TFloat32 scaleY = Sqrt( e10*e10 + e11*e11 + e12*e12 );
  611. TFloat32 scaleZ = Sqrt( e20*e20 + e21*e21 + e22*e22 );
  612. // Get rotations if required
  613. if (pAngles)
  614. {
  615. // Calculate inverse scaling to extract rotational values only
  616. GEN_ASSERT( !IsZero(scaleX) && !IsZero(scaleY) && !IsZero(scaleZ), "Singular matrix" );
  617. TFloat32 invScaleX = 1.0f / scaleX;
  618. TFloat32 invScaleY = 1.0f / scaleY;
  619. TFloat32 invScaleZ = 1.0f / scaleZ;
  620. TFloat32 sX, cX, sY, cY, sZ, cZ;
  621. switch (eRotOrder)
  622. {
  623. case kZYX:
  624. {
  625. sY = e20 * invScaleX;
  626. cY = Sqrt( 1.0f - sY*sY );
  627. // If no gimbal lock...
  628. if (!IsZero( cY ))
  629. {
  630. TFloat32 invCY = 1.0f / cY;
  631. sZ = -e10 * invCY * invScaleY;
  632. cZ = e00 * invCY * invScaleX;
  633. sX = -e21 * invCY * invScaleZ;
  634. cX = e22 * invCY * invScaleZ;
  635. }
  636. else
  637. {
  638. // Gimbal lock - force Z angle to 0
  639. sZ = 0.0f;
  640. cZ = 1.0f;
  641. sX = e12 * invScaleY;
  642. cX = e11 * invScaleY;
  643. }
  644. break;
  645. }
  646. case kYZX:
  647. {
  648. sZ = -e10 * invScaleY;
  649. cZ = Sqrt( 1.0f - sZ*sZ );
  650. // If no gimbal lock...
  651. if (!IsZero( cZ ))
  652. {
  653. TFloat32 invCZ = 1.0f / cZ;
  654. sY = e20 * invCZ * invScaleZ;
  655. cY = e00 * invCZ * invScaleX;
  656. sX = e12 * invCZ * invScaleY;
  657. cX = e11 * invCZ * invScaleY;
  658. }
  659. else
  660. {
  661. // Gimbal lock - force Y angle to 0
  662. sY = 0.0f;
  663. cY = 1.0f;
  664. sX = -e21 * invScaleZ;
  665. cX = e22 * invScaleZ;
  666. }
  667. break;
  668. }
  669. case kXZY:
  670. {
  671. sZ = e01 * invScaleX;
  672. cZ = Sqrt( 1.0f - sZ*sZ );
  673. // If no gimbal lock...
  674. if (!IsZero( cZ ))
  675. {
  676. TFloat32 invCZ = 1.0f / cZ;
  677. sX = -e21 * invCZ * invScaleZ;
  678. cX = e11 * invCZ * invScaleY;
  679. sY = -e02 * invCZ * invScaleX;
  680. cY = e00 * invCZ * invScaleX;
  681. }
  682. else
  683. {
  684. // Gimbal lock - force X angle to 0
  685. sX = 0.0f;
  686. cX = 1.0f;
  687. sY = e20 * invScaleZ;
  688. cY = e22 * invScaleZ;
  689. }
  690. break;
  691. }
  692. case kZXY:
  693. {
  694. sX = -e21 * invScaleZ;
  695. cX = Sqrt( 1.0f - sX*sX );
  696. // If no gimbal lock...
  697. if (!IsZero( cX ))
  698. {
  699. TFloat32 invCX = 1.0f / cX;
  700. sZ = e01 * invCX * invScaleX;
  701. cZ = e11 * invCX * invScaleY;
  702. sY = e20 * invCX * invScaleZ;
  703. cY = e22 * invCX * invScaleZ;
  704. }
  705. else
  706. {
  707. // Gimbal lock - force Z angle to 0
  708. sZ = 0.0f;
  709. cZ = 1.0f;
  710. sY = -e02 * invScaleX;
  711. cY = e00 * invScaleX;
  712. }
  713. break;
  714. }
  715. case kYXZ:
  716. {
  717. sX = e12 * invScaleY;
  718. cX = Sqrt( 1.0f - sX*sX );
  719. // If no gimbal lock...
  720. if (!IsZero( cX ))
  721. {
  722. TFloat32 invCX = 1.0f / cX;
  723. sY = -e02 * invCX * invScaleX;
  724. cY = e22 * invCX * invScaleZ;
  725. sZ = -e10 * invCX * invScaleY;
  726. cZ = e11 * invCX * invScaleY;
  727. }
  728. else
  729. {
  730. // Gimbal lock - force Y angle to 0
  731. sY = 0.0f;
  732. cY = 1.0f;
  733. sZ = e01 * invScaleX;
  734. cZ = e00 * invScaleX;
  735. }
  736. break;
  737. }
  738. case kXYZ:
  739. {
  740. sY = -e02 * invScaleX;
  741. cY = Sqrt( 1.0f - sY*sY );
  742. // If no gimbal lock...
  743. if (!IsZero( cY ))
  744. {
  745. TFloat32 invCY = 1.0f / cY;
  746. sX = e12 * invCY * invScaleY;
  747. cX = e22 * invCY * invScaleZ;
  748. sZ = e01 * invCY * invScaleX;
  749. cZ = e00 * invCY * invScaleX;
  750. }
  751. else
  752. {
  753. // Gimbal lock - force X angle to 0
  754. sX = 0.0f;
  755. cX = 1.0f;
  756. sZ = -e10 * invScaleY;
  757. cZ = e11 * invScaleY;
  758. }
  759. break;
  760. }
  761. default:
  762. GEN_ERROR( "Invalid parameter" );
  763. }
  764. pAngles->x = ATan( sX, cX );
  765. pAngles->y = ATan( sY, cY );
  766. pAngles->z = ATan( sZ, cZ );
  767. }
  768. // Return scale if required
  769. if (pScale)
  770. {
  771. pScale->x = scaleX;
  772. pScale->y = scaleY;
  773. pScale->z = scaleZ;
  774. }
  775. GEN_ENDGUARD;
  776. }
  777. // Decompose transformation into quaternion of rotation and scale. Pass NULL for any unneeded
  778. // parameters. Assumes built in this order: M = Scale*Rotation
  779. void CMatrix3x3::DecomposeTransformQuaternion
  780. (
  781. CQuaternion* pQuat,
  782. CVector3* pScale
  783. ) const
  784. {
  785. // Calculate matrix scaling
  786. TFloat32 scaleX = Sqrt( e00*e00 + e01*e01 + e02*e02 );
  787. TFloat32 scaleY = Sqrt( e10*e10 + e11*e11 + e12*e12 );
  788. TFloat32 scaleZ = Sqrt( e20*e20 + e21*e21 + e22*e22 );
  789. // Return quaternion if required - similar to angle-axis process below
  790. if (pQuat)
  791. {
  792. // Calculate inverse scaling to extract rotational values only
  793. GEN_ASSERT( !IsZero(scaleX) && !IsZero(scaleY) && !IsZero(scaleZ), "Singular matrix" );
  794. TFloat32 invScaleX = 1.0f / scaleX;
  795. TFloat32 invScaleY = 1.0f / scaleY;
  796. TFloat32 invScaleZ = 1.0f / scaleZ;
  797. // Calculate trace of matrix (the sum of diagonal elements)
  798. TFloat32 diagX = e00 * invScaleX; // Remove scaling
  799. TFloat32 diagY = e11 * invScaleY;
  800. TFloat32 diagZ = e22 * invScaleZ;
  801. TFloat32 trace = diagX + diagY + diagZ;
  802. // Simple method if trace is positive
  803. if (trace > 0.0f)
  804. {
  805. // Derive quaternion from remaining elements
  806. TFloat32 cosAng = Sqrt( trace + 1.0f );
  807. pQuat->w = cosAng * 0.5f;
  808. TFloat32 invCosAng = 0.5f / cosAng;
  809. pQuat->x = (e12*invScaleY - e21*invScaleZ) * invCosAng;
  810. pQuat->y = (e20*invScaleZ - e02*invScaleX) * invCosAng;
  811. pQuat->z = (e01*invScaleX - e10*invScaleY) * invCosAng;
  812. }
  813. else
  814. {
  815. // Find largest x,y or z axis component by manipulating diagonal elts
  816. TFloat32 maxAxis, invMaxAxis;
  817. if (diagX > diagY)
  818. {
  819. if (diagX > diagZ)
  820. {
  821. maxAxis = Sqrt( diagX - diagY - diagZ + 1.0f );
  822. pQuat->x = 0.5f * maxAxis;
  823. invMaxAxis = 0.5f / maxAxis;
  824. pQuat->y = (e01*invScaleX + e10*invScaleY) * invMaxAxis;
  825. pQuat->z = (e20*invScaleZ + e02*invScaleX) * invMaxAxis;
  826. pQuat->w = (e12*invScaleY - e21*invScaleZ) * invMaxAxis;
  827. }
  828. else
  829. {
  830. maxAxis = Sqrt( diagZ - diagX - diagY + 1.0f );
  831. pQuat->z = 0.5f * maxAxis;
  832. invMaxAxis = 0.5f / maxAxis;
  833. pQuat->x = (e20*invScaleZ + e02*invScaleX) * invMaxAxis;
  834. pQuat->y = (e12*invScaleY + e21*invScaleZ) * invMaxAxis;
  835. pQuat->w = (e01*invScaleX - e10*invScaleY) * invMaxAxis;
  836. }
  837. }
  838. else if (diagY > diagZ)
  839. {
  840. maxAxis = Sqrt( diagY - diagZ - diagX + 1.0f );
  841. pQuat->y = 0.5f * maxAxis;
  842. invMaxAxis = 0.5f / maxAxis;
  843. pQuat->z = (e12*invScaleY + e21*invScaleZ) * invMaxAxis;
  844. pQuat->x = (e01*invScaleX + e10*invScaleY) * invMaxAxis;
  845. pQuat->w = (e20*invScaleZ - e02*invScaleX) * invMaxAxis;
  846. }
  847. else
  848. {
  849. maxAxis = Sqrt( diagZ - diagX - diagY + 1.0f );
  850. pQuat->z = 0.5f * maxAxis;
  851. invMaxAxis = 0.5f / maxAxis;
  852. pQuat->x = (e20*invScaleZ + e02*invScaleX) * invMaxAxis;
  853. pQuat->y = (e12*invScaleY + e21*invScaleZ) * invMaxAxis;
  854. pQuat->w = (e01*invScaleX - e10*invScaleY) * invMaxAxis;
  855. }
  856. }
  857. }
  858. // Return scale if required
  859. if (pScale)
  860. {
  861. pScale->x = scaleX;
  862. pScale->y = scaleY;
  863. pScale->z = scaleZ;
  864. }
  865. }
  866. // Decompose transformation into angle/axis of rotation (an axis and amount of rotation around
  867. // that axis) and scale. Pass NULL for any unneeded parameters. Assumes matrix is built in this
  868. // order: M = Scale*Rotation
  869. void CMatrix3x3::DecomposeTransformAxisAngle
  870. (
  871. CVector3* pAxis,
  872. TFloat32* pfAngle,
  873. CVector3* pScale
  874. ) const
  875. {
  876. // Calculate matrix scaling
  877. TFloat32 scaleX = Sqrt( e00*e00 + e01*e01 + e02*e02 );
  878. TFloat32 scaleY = Sqrt( e10*e10 + e11*e11 + e12*e12 );
  879. TFloat32 scaleZ = Sqrt( e20*e20 + e21*e21 + e22*e22 );
  880. // Return angle/axis if required
  881. if (pAxis || pfAngle)
  882. {
  883. // Calculate inverse scaling to extract rotational values only
  884. GEN_ASSERT( !IsZero(scaleX) && !IsZero(scaleY) && !IsZero(scaleZ), "Singular matrix" );
  885. TFloat32 invScaleX = 1.0f / scaleX;
  886. TFloat32 invScaleY = 1.0f / scaleY;
  887. TFloat32 invScaleZ = 1.0f / scaleZ;
  888. // Calculate rotation using trace of matrix (the sum of diagonal elements)
  889. TFloat32 diagX = e00 * invScaleX; // Remove scaling
  890. TFloat32 diagY = e11 * invScaleY;
  891. TFloat32 diagZ = e22 * invScaleZ;
  892. TFloat32 cosAngle = (diagX + diagY + diagZ - 1.0f) * 0.5f;
  893. TFloat32 angle = ACos( cosAngle );
  894. // Return angle if required
  895. if (pfAngle)
  896. {
  897. *pfAngle = angle;
  898. }
  899. // Get axis if required
  900. if (pAxis)
  901. {
  902. // Rotation of 0 gives free choice of axis
  903. if (IsZero( angle ))
  904. {
  905. *pAxis = CVector3::kZAxis;
  906. }
  907. // Otherwise if rotation is not 180 degrees...
  908. else if (!IsZero( angle - kfPi ))
  909. {
  910. pAxis->Set( e12 *invScaleY - e21 * invScaleZ,
  911. e20 *invScaleZ - e02 * invScaleX,
  912. e01 *invScaleX - e10 * invScaleY );
  913. pAxis->Normalise();
  914. }
  915. // Or if rotation is 180 degrees
  916. else
  917. {
  918. // Find largest x,y or z axis component by manipulating diagonal elts
  919. TFloat32 maxAxis, invMaxAxis;
  920. if (diagX > diagY)
  921. {
  922. if (diagX > diagZ)
  923. {
  924. maxAxis = Sqrt(diagX - diagY - diagZ + 1.0f);
  925. pAxis->x = 0.5f * maxAxis;
  926. // Use this component to calculate others using other matrix elts
  927. invMaxAxis = 1.0f / maxAxis;
  928. pAxis->y = e01 * invMaxAxis;
  929. pAxis->z = e02 * invMaxAxis;
  930. }
  931. else
  932. {
  933. maxAxis = Sqrt(diagZ - diagX - diagY + 1.0f);
  934. pAxis->z = 0.5f * maxAxis;
  935. invMaxAxis = 1.0f / maxAxis;
  936. pAxis->x = e02 * invMaxAxis;
  937. pAxis->y = e12 * invMaxAxis;
  938. }
  939. }
  940. else if (diagY > diagZ)
  941. {
  942. maxAxis = Sqrt(diagY - diagZ - diagX + 1.0f);
  943. pAxis->y = 0.5f * maxAxis;
  944. invMaxAxis = 1.0f / maxAxis;
  945. pAxis->x = e01 * invMaxAxis;
  946. pAxis->z = e12 * invMaxAxis;
  947. }
  948. else
  949. {
  950. maxAxis = Sqrt(diagZ - diagX - diagY + 1.0f);
  951. pAxis->z = 0.5f * maxAxis;
  952. invMaxAxis = 1.0f / maxAxis;
  953. pAxis->x = e02 * invMaxAxis;
  954. pAxis->y = e12 * invMaxAxis;
  955. }
  956. }
  957. }
  958. }
  959. // Get scale if required
  960. if (pScale)
  961. {
  962. pScale->x = scaleX;
  963. pScale->y = scaleY;
  964. pScale->z = scaleZ;
  965. }
  966. }
  967. /*-----------------------------------------------------------------------------------------
  968. Creation and Decomposition of 2D Affine Matrices
  969. -----------------------------------------------------------------------------------------*/
  970. // Make 2D affine transformation from position, and optional rotation angle & scaling, with
  971. // remaining elements taken from the identity matrix. Matrix is effectively built in this
  972. // order: M = Scale*Rotation*Translation
  973. void CMatrix3x3::MakeAffine2D
  974. (
  975. const CVector2& position,
  976. const TFloat32 fAngle /*= 0.0f*/,
  977. const CVector2& scale /*= CVector2::kOne*/
  978. )
  979. {
  980. TFloat32 s, c;
  981. SinCos( fAngle, &s, &c );
  982. e00 = c * scale.x;
  983. e01 = s * scale.x;
  984. e02 = 0.0f;
  985. e10 = -s * scale.y;
  986. e11 = c * scale.y;
  987. e12 = 0.0f;
  988. e20 = position.x;
  989. e21 = position.y;
  990. e22 = 1.0f;
  991. }
  992. // Decompose 2D affine transformation into position, angle of rotation & scale. Pass NULL for
  993. // unneeded parameters. Assumes matrix is built in this order: M = Scale*Rotation*Translation
  994. void CMatrix3x3::DecomposeAffine2D
  995. (
  996. CVector2* pPosition,
  997. TFloat32* pfAngle,
  998. CVector2* pScale
  999. ) const
  1000. {
  1001. GEN_GUARD;
  1002. // Get position if required
  1003. if (pPosition)
  1004. {
  1005. pPosition->x = e20;
  1006. pPosition->y = e21;
  1007. }
  1008. // Calculate matrix scaling
  1009. TFloat32 scaleX = Sqrt( e00*e00 + e01*e01 );
  1010. TFloat32 scaleY = Sqrt( e10*e10 + e11*e11 );
  1011. // Get rotation angle if required
  1012. if (pfAngle)
  1013. {
  1014. // Calculate inverse scaling to extract rotational values only
  1015. GEN_ASSERT( !IsZero(scaleX) && !IsZero(scaleY), "Singular matrix" );
  1016. TFloat32 invScaleX = 1.0f / scaleX;
  1017. *pfAngle = ATan( e01 * invScaleX, e00 * invScaleX );
  1018. }
  1019. // Return scale if required
  1020. if (pScale)
  1021. {
  1022. pScale->x = scaleX;
  1023. pScale->y = scaleY;
  1024. }
  1025. GEN_ENDGUARD;
  1026. }
  1027. /*-----------------------------------------------------------------------------------------
  1028. Manipulation of Transformation Matrices
  1029. -----------------------------------------------------------------------------------------*/
  1030. // Get the X, Y & Z scaling of a transformation matrix
  1031. CVector3 CMatrix3x3::GetScale() const
  1032. {
  1033. CVector3 scale;
  1034. scale.x = Sqrt( e00*e00 + e01*e01 + e02*e02 );
  1035. scale.y = Sqrt( e10*e10 + e11*e11 + e12*e12 );
  1036. scale.z = Sqrt( e20*e20 + e21*e21 + e22*e22 );
  1037. return scale;
  1038. }
  1039. // Set the X scaling of a transformation matrix. Removes any previous scaling.
  1040. // Will not change other components of the transformation (e.g. rotation)
  1041. void CMatrix3x3::SetScaleX( const TFloat32 x )
  1042. {
  1043. TFloat32 scaleSq = Sqrt( e00*e00 + e01*e01 + e02*e02 );
  1044. if (!IsZero(scaleSq)) // No effect on zero axes
  1045. {
  1046. TFloat32 rescale = x * InvSqrt( scaleSq );
  1047. e00 *= rescale;
  1048. e01 *= rescale;
  1049. e02 *= rescale;
  1050. }
  1051. }
  1052. // Set the Y scaling of a transformation matrix. Removes any previous scaling.
  1053. // Will not change other components of the transformation (e.g. rotation)
  1054. void CMatrix3x3::SetScaleY( const TFloat32 y )
  1055. {
  1056. TFloat32 scaleSq = Sqrt( e10*e10 + e11*e11 + e12*e12 );
  1057. if (!IsZero(scaleSq)) // No effect on zero axes
  1058. {
  1059. TFloat32 rescale = y * InvSqrt( scaleSq );
  1060. e10 *= rescale;
  1061. e11 *= rescale;
  1062. e12 *= rescale;
  1063. }
  1064. }
  1065. // Set the Z scaling of a transformation matrix. Removes any previous scaling.
  1066. // Will not change other components of the transformation (e.g. rotation)
  1067. void CMatrix3x3::SetScaleZ( const TFloat32 z )
  1068. {
  1069. TFloat32 scaleSq = Sqrt( e20*e20 + e21*e21 + e22*e22 );
  1070. if (!IsZero(scaleSq)) // No effect on zero axes
  1071. {
  1072. TFloat32 rescale = z * InvSqrt( scaleSq );
  1073. e20 *= rescale;
  1074. e21 *= rescale;
  1075. e22 *= rescale;
  1076. }
  1077. }
  1078. // Set the X, Y & Z scaling of a transformation matrix. Removes any previous scaling.
  1079. // Will not change other components of the transformation (e.g. rotation)
  1080. void CMatrix3x3::SetScale( const CVector3& scale )
  1081. {
  1082. TFloat32 rescale;
  1083. TFloat32 scaleSq = Sqrt( e00*e00 + e01*e01 + e02*e02 );
  1084. if (!IsZero(scaleSq)) // No effect on zero axes
  1085. {
  1086. rescale = scale.x * InvSqrt( scaleSq );
  1087. e00 *= rescale;
  1088. e01 *= rescale;
  1089. e02 *= rescale;
  1090. }
  1091. scaleSq = Sqrt( e10*e10 + e11*e11 + e12*e12 );
  1092. if (!IsZero(scaleSq)) // No effect on zero axes
  1093. {
  1094. rescale = scale.y * InvSqrt( scaleSq );
  1095. e10 *= rescale;
  1096. e11 *= rescale;
  1097. e12 *= rescale;
  1098. }
  1099. scaleSq = Sqrt( e20*e20 + e21*e21 + e22*e22 );
  1100. if (!IsZero(scaleSq)) // No effect on zero axes
  1101. {
  1102. rescale = scale.z * InvSqrt( scaleSq );
  1103. e20 *= rescale;
  1104. e21 *= rescale;
  1105. e22 *= rescale;
  1106. }
  1107. }
  1108. // Set a uniform scaling for a transformation matrix. Removes any previous scaling.
  1109. // Will not change other components of the transformation (rotation)
  1110. void CMatrix3x3::SetScale( const TFloat32 fScale )
  1111. {
  1112. TFloat32 rescale;
  1113. TFloat32 scaleSq = Sqrt( e00*e00 + e01*e01 + e02*e02 );
  1114. if (!IsZero(scaleSq)) // No effect on zero axes
  1115. {
  1116. rescale = fScale * InvSqrt( scaleSq );
  1117. e00 *= rescale;
  1118. e01 *= rescale;
  1119. e02 *= rescale;
  1120. }
  1121. scaleSq = Sqrt( e10*e10 + e11*e11 + e12*e12 );
  1122. if (!IsZero(scaleSq)) // No effect on zero axes
  1123. {
  1124. rescale = fScale * InvSqrt( scaleSq );
  1125. e10 *= rescale;
  1126. e11 *= rescale;
  1127. e12 *= rescale;
  1128. }
  1129. scaleSq = Sqrt( e20*e20 + e21*e21 + e22*e22 );
  1130. if (!IsZero(scaleSq)) // No effect on zero axes
  1131. {
  1132. rescale = fScale * InvSqrt( scaleSq );
  1133. e20 *= rescale;
  1134. e21 *= rescale;
  1135. e22 *= rescale;
  1136. }
  1137. }
  1138. /*-----------------------------------------------------------------------------------------
  1139. Manipulation of 2D Affine Matrices
  1140. -----------------------------------------------------------------------------------------*/
  1141. // Get the X & Y scaling of a 2D affine transformation matrix
  1142. CVector2 CMatrix3x3::GetScale2D() const
  1143. {
  1144. CVector2 scale;
  1145. scale.x = Sqrt( e00*e00 + e01*e01 );
  1146. scale.y = Sqrt( e10*e10 + e11*e11 );
  1147. return scale;
  1148. }
  1149. // Set the X scaling of a 2D affine transformation matrix. Removes any previous scaling.
  1150. // Will not change other components of the transformation (position, rotation etc.)
  1151. void CMatrix3x3::SetScaleX2D( const TFloat32 x )
  1152. {
  1153. TFloat32 scaleSq = Sqrt( e00*e00 + e01*e01 );
  1154. if (!IsZero(scaleSq)) // No effect on zero axes
  1155. {
  1156. TFloat32 rescale = x * InvSqrt( scaleSq );
  1157. e00 *= rescale;
  1158. e01 *= rescale;
  1159. }
  1160. }
  1161. // Set the Y scaling of a 2D affine transformation matrix. Removes any previous scaling.
  1162. // Will not change other components of the transformation (position, rotation etc.)
  1163. void CMatrix3x3::SetScaleY2D( const TFloat32 y )
  1164. {
  1165. TFloat32 scaleSq = Sqrt( e10*e10 + e11*e11 );
  1166. if (!IsZero(scaleSq)) // No effect on zero axes
  1167. {
  1168. TFloat32 rescale = y * InvSqrt( scaleSq );
  1169. e10 *= rescale;
  1170. e11 *= rescale;
  1171. }
  1172. }
  1173. // Set the X & Y scaling of a 2D affine transformation matrix. Removes any previous scaling.
  1174. // Will not change other components of the transformation (position, rotation etc.)
  1175. void CMatrix3x3::SetScale2D( const CVector2& scale )
  1176. {
  1177. TFloat32 rescale;
  1178. TFloat32 scaleSq = Sqrt( e00*e00 + e01*e01 );
  1179. if (!IsZero(scaleSq)) // No effect on zero axes
  1180. {
  1181. rescale = scale.x * InvSqrt( scaleSq );
  1182. e00 *= rescale;
  1183. e01 *= rescale;
  1184. }
  1185. scaleSq = Sqrt( e10*e10 + e11*e11 );
  1186. if (!IsZero(scaleSq)) // No effect on zero axes
  1187. {
  1188. rescale = scale.y * InvSqrt( scaleSq );
  1189. e10 *= rescale;
  1190. e11 *= rescale;
  1191. }
  1192. }
  1193. // Set a uniform scaling for a 2D affine transformation matrix. Removes any previous scaling.
  1194. // Will not change other components of the transformation (position, rotation etc.)
  1195. void CMatrix3x3::SetScale2D( const TFloat32 fScale )
  1196. {
  1197. TFloat32 rescale;
  1198. TFloat32 scaleSq = Sqrt( e00*e00 + e01*e01 );
  1199. if (!IsZero(scaleSq)) // No effect on zero axes
  1200. {
  1201. rescale = fScale * InvSqrt( scaleSq );
  1202. e00 *= rescale;
  1203. e01 *= rescale;
  1204. }
  1205. scaleSq = Sqrt( e10*e10 + e11*e11 );
  1206. if (!IsZero(scaleSq)) // No effect on zero axes
  1207. {
  1208. rescale = fScale * InvSqrt( scaleSq );
  1209. e10 *= rescale;
  1210. e11 *= rescale;
  1211. }
  1212. }
  1213. /*-----------------------------------------------------------------------------------------
  1214. Comparisons
  1215. -----------------------------------------------------------------------------------------*/
  1216. // Test if matrix is the identity
  1217. // Uses BaseMath.h float approximation function 'IsZero' with default epsilon (margin of error)
  1218. bool CMatrix3x3::IsIdentity() const
  1219. {
  1220. return IsZero( e00 - 1.0f ) && IsZero( e11 - 1.0f ) && IsZero( e22 - 1.0f ) &&
  1221. IsZero( e01 ) && IsZero( e02 ) &&
  1222. IsZero( e10 ) && IsZero( e12 ) &&
  1223. IsZero( e20 ) && IsZero( e21 );
  1224. }
  1225. /*-----------------------------------------------------------------------------------------
  1226. Othogonality
  1227. -----------------------------------------------------------------------------------------*/
  1228. // See extensive notes in header file
  1229. // Test if matrix has orthogonal rows, i.e. if the three rows are vectors at right angles to
  1230. // each other. Will also be orthonormal if it contains no scaling
  1231. bool CMatrix3x3::IsOrthogonal() const
  1232. {
  1233. // Check dot product of each pair of rows is zero
  1234. return IsZero( e00*e10 + e01*e11 + e02*e12 ) &&
  1235. IsZero( e10*e20 + e11*e21 + e12*e22 ) &&
  1236. IsZero( e20*e00 + e21*e01 + e22*e02 );
  1237. }
  1238. // Test if matrix has orthonormal rows, i.e. if the three rows are *normals* at right angles to
  1239. // each other. Scaled matrices cannot be orthonormal (can be orthogonal)
  1240. bool CMatrix3x3::IsOrthonormal() const
  1241. {
  1242. // Check each row is length 1 and dot product of each pair of rows is zero
  1243. return IsZero( e00*e00 + e01*e01 + e02*e02 - 1.0f ) &&
  1244. IsZero( e10*e10 + e11*e11 + e12*e12 - 1.0f ) &&
  1245. IsZero( e20*e20 + e21*e21 + e22*e22 - 1.0f ) &&
  1246. IsZero( e00*e10 + e01*e11 + e02*e12 ) &&
  1247. IsZero( e10*e20 + e11*e21 + e12*e22 ) &&
  1248. IsZero( e20*e00 + e21*e01 + e22*e02 );
  1249. }
  1250. // Orthogonalise the rows/columns of the matrix. Generally used to "correct" matrices that
  1251. // become non-orthogonal after repeated calculations/floating point rounding
  1252. // May pass scaling for resultant rows - default is 1, leading to "orthonormalisation"
  1253. void CMatrix3x3::Orthogonalise( const CVector3& scale /*= CVector3::kOne*/ )
  1254. {
  1255. GEN_GUARD;
  1256. // Normalise first vector (x-axis)
  1257. TFloat32 origScaleX = e00*e00 + e01*e01 + e02*e02;
  1258. GEN_ASSERT( !IsZero(origScaleX), "Singular matrix" );
  1259. TFloat32 invOrigScaleX = InvSqrt( origScaleX );
  1260. e00 *= invOrigScaleX;
  1261. e01 *= invOrigScaleX;
  1262. e02 *= invOrigScaleX;
  1263. // Orthogonalise second vector (y-axis) with first
  1264. TFloat32 proj10 = e10*e00 + e11*e01 + e12*e02;
  1265. e10 -= proj10 * e00;
  1266. e11 -= proj10 * e01;
  1267. e12 -= proj10 * e02;
  1268. // Normalise second vector
  1269. TFloat32 origScaleY = e10*e10 + e11*e11 + e12*e12;
  1270. GEN_ASSERT( !IsZero(origScaleY), "Singular matrix" );
  1271. TFloat32 invOrigScaleY = InvSqrt( origScaleY );
  1272. e10 *= invOrigScaleY;
  1273. e11 *= invOrigScaleY;
  1274. e12 *= invOrigScaleY;
  1275. // Get third vector from cross product of first two (result is already normalised)
  1276. e20 = e01*e12 - e02*e11;
  1277. e21 = e02*e10 - e00*e12;
  1278. e22 = e00*e11 - e01*e10;
  1279. // Rescale each vector
  1280. e00 *= scale.x;
  1281. e01 *= scale.x;
  1282. e02 *= scale.x;
  1283. e10 *= scale.y;
  1284. e11 *= scale.y;
  1285. e12 *= scale.y;
  1286. e20 *= scale.z;
  1287. e21 *= scale.z;
  1288. e22 *= scale.z;
  1289. GEN_ENDGUARD;
  1290. }
  1291. // Return a copy of given matrix with orthogonalised rows/columns. Generally used to "correct"
  1292. // matrices that become non-orthogonal after repeated calculations/floating point rounding
  1293. // May pass scaling for resultant rows - default is 1, leading to "orthonormalisation"
  1294. CMatrix3x3 Orthogonalise
  1295. (
  1296. const CMatrix3x3& m,
  1297. const CVector3& scale /*= CVector3::kOne*/
  1298. )
  1299. {
  1300. GEN_GUARD;
  1301. CMatrix3x3 mOut;
  1302. // Normalise first vector (x-axis)
  1303. TFloat32 origScaleX = m.e00*m.e00 + m.e01*m.e01 + m.e02*m.e02;
  1304. GEN_ASSERT( !IsZero(origScaleX), "Singular matrix" );
  1305. TFloat32 invOrigScaleX = InvSqrt( origScaleX );
  1306. mOut.e00 = m.e00 * invOrigScaleX;
  1307. mOut.e01 = m.e01 * invOrigScaleX;
  1308. mOut.e02 = m.e02 * invOrigScaleX;
  1309. // Orthogonalise second vector (y-axis) with first
  1310. TFloat32 proj10 = m.e10*mOut.e00 + m.e11*mOut.e01 + m.e12*mOut.e02;
  1311. mOut.e10 = m.e10 - proj10 * mOut.e00;
  1312. mOut.e11 = m.e11 - proj10 * mOut.e01;
  1313. mOut.e12 = m.e12 - proj10 * mOut.e02;
  1314. // Normalise second vector
  1315. TFloat32 origScaleY = mOut.e10*mOut.e10 + mOut.e11*mOut.e11 + mOut.e12*mOut.e12;
  1316. GEN_ASSERT( !IsZero(origScaleY), "Singular matrix" );
  1317. TFloat32 invOrigScaleY = InvSqrt( origScaleY );
  1318. mOut.e10 *= invOrigScaleY;
  1319. mOut.e11 *= invOrigScaleY;
  1320. mOut.e12 *= invOrigScaleY;
  1321. // Get third vector from cross product of first two (result is already normalised)
  1322. mOut.e20 = mOut.e01*mOut.e12 - mOut.e02*mOut.e11;
  1323. mOut.e21 = mOut.e02*mOut.e10 - mOut.e00*mOut.e12;
  1324. mOut.e22 = mOut.e00*mOut.e11 - mOut.e01*mOut.e10;
  1325. // Rescale each vector
  1326. mOut.e00 *= scale.x;
  1327. mOut.e01 *= scale.x;
  1328. mOut.e02 *= scale.x;
  1329. mOut.e10 *= scale.y;
  1330. mOut.e11 *= scale.y;
  1331. mOut.e12 *= scale.y;
  1332. mOut.e20 *= scale.z;
  1333. mOut.e21 *= scale.z;
  1334. mOut.e22 *= scale.z;
  1335. return mOut;
  1336. GEN_ENDGUARD;
  1337. }
  1338. // Test if upper-left 2x2 matrix has orthogonal rows, i.e. if the two rows are vectors
  1339. // at right angles to each other. Will also be orthonormal if it contains no scaling
  1340. bool CMatrix3x3::IsOrthogonal2x2() const
  1341. {
  1342. // Check dot product of each pair of rows is zero
  1343. return IsZero( e00*e10 + e01*e11) && IsZero( e10*e20 + e11*e21);
  1344. }
  1345. // Test if upper-left 2x2 matrix has orthonormal rows, i.e. if the two rows are *normals*
  1346. // at right angles to each other. Scaled matrices cannot be orthonormal (can be orthogonal)
  1347. bool CMatrix3x3::IsOrthonormal2x2() const
  1348. {
  1349. // Check each row is length 1 and dot product of each pair of rows is zero
  1350. return IsZero( e00*e00 + e01*e01 - 1.0f ) && IsZero( e10*e10 + e11*e11 - 1.0f ) &&
  1351. IsZero( e00*e10 + e01*e11 ) && IsZero( e10*e20 + e11*e21 );
  1352. }
  1353. // Orthogonalise the rows/columns of the upper-left 2x2 matrix. Generally used to "correct"
  1354. // matrices that become non-orthogonal after repeated calculations/floating point rounding
  1355. // May pass scaling for resultant rows - default is 1, leading to "orthonormalisation"
  1356. void CMatrix3x3::Orthogonalise2x2( const CVector2& scale /*= CVector2::kOne*/ )
  1357. {
  1358. GEN_GUARD;
  1359. // Normalise first vector
  1360. TFloat32 origScaleX = e00*e00 + e01*e01;
  1361. GEN_ASSERT( !IsZero(origScaleX), "Singular matrix" );
  1362. TFloat32 invOrigScaleX = InvSqrt( origScaleX );
  1363. e00 *= invOrigScaleX;
  1364. e01 *= invOrigScaleX;
  1365. // Second vector is simply perpendicular to first, only need to select cw or ccw direction
  1366. TFloat32 ccwPerpDot = e00*e11 - e01*e10;
  1367. if (ccwPerpDot >= 0.0f)
  1368. {
  1369. e11 = e00;
  1370. e10 = -e01;
  1371. }
  1372. else
  1373. {
  1374. e11 = -e00;
  1375. e10 = e01;
  1376. }
  1377. // Rescale each vector
  1378. e00 *= scale.x;
  1379. e01 *= scale.x;
  1380. e10 *= scale.y;
  1381. e11 *= scale.y;
  1382. GEN_ENDGUARD;
  1383. }
  1384. // Return a copy of given matrix with orthogonalised rows/columns in the upper-left 2x2 matrix.
  1385. // Generally used to "correct" matrices that become non-orthogonal after repeated calculations /
  1386. // floating point rounding. May pass scaling for resultant rows - default is 1, leading to
  1387. // "orthonormalisation"
  1388. CMatrix3x3 Orthogonalise2x2
  1389. (
  1390. const CMatrix3x3& m,
  1391. const CVector2& scale /*= CVector2::kOne*/
  1392. )
  1393. {
  1394. GEN_GUARD;
  1395. CMatrix3x3 mOut;
  1396. // Normalise first vector
  1397. TFloat32 origScaleX = m.e00*m.e00 + m.e01*m.e01;
  1398. GEN_ASSERT( !IsZero(origScaleX), "Singular matrix" );
  1399. TFloat32 invOrigScaleX = InvSqrt( origScaleX );
  1400. mOut.e00 = m.e00 * invOrigScaleX;
  1401. mOut.e01 = m.e01 * invOrigScaleX;
  1402. // Second vector is simply perpendicular to first, only need to select cw or ccw direction
  1403. TFloat32 ccwPerpDot = mOut.e00*m.e11 - mOut.e01*m.e10;
  1404. if (ccwPerpDot >= 0.0f)
  1405. {
  1406. mOut.e11 = mOut.e00;
  1407. mOut.e10 = -mOut.e01;
  1408. }
  1409. else
  1410. {
  1411. mOut.e11 = -mOut.e00;
  1412. mOut.e10 = mOut.e01;
  1413. }
  1414. // Rescale each vector
  1415. mOut.e00 *= scale.x;
  1416. mOut.e01 *= scale.x;
  1417. mOut.e10 *= scale.y;
  1418. mOut.e11 *= scale.y;
  1419. return mOut;
  1420. GEN_ENDGUARD;
  1421. }
  1422. /*-----------------------------------------------------------------------------------------
  1423. Inverse related
  1424. -----------------------------------------------------------------------------------------*/
  1425. // Set this matrix to its transpose (matrix reflected through its diagonal)
  1426. // This is also the (most efficient) inverse for a rotation matrix
  1427. void CMatrix3x3::Transpose()
  1428. {
  1429. TFloat32 t;
  1430. t = e01;
  1431. e01 = e10;
  1432. e10 = t;
  1433. t = e02;
  1434. e02 = e20;
  1435. e20 = t;
  1436. t = e12;
  1437. e12 = e21;
  1438. e21 = t;
  1439. }
  1440. // Return the transpose of given matrix (matrix reflected through its diagonal)
  1441. // This is also the (most efficient) inverse for a rotation matrix
  1442. CMatrix3x3 Transpose( const CMatrix3x3& m )
  1443. {
  1444. CMatrix3x3 transMat;
  1445. transMat.e00 = m.e00;
  1446. transMat.e01 = m.e10;
  1447. transMat.e02 = m.e20;
  1448. transMat.e10 = m.e01;
  1449. transMat.e11 = m.e11;
  1450. transMat.e12 = m.e21;
  1451. transMat.e20 = m.e02;
  1452. transMat.e21 = m.e12;
  1453. transMat.e22 = m.e22;
  1454. return transMat;
  1455. }
  1456. // Set this matrix to its inverse assuming it has orthogonal rows, i.e. it is a transformation
  1457. // matrix with no shear. Most efficient inverse for transformations with rotation & scale only
  1458. void CMatrix3x3::InvertRotScale()
  1459. {
  1460. GEN_GUARD;
  1461. // Get X, Y & Z scaling (squared)
  1462. TFloat32 scaleSqX = e00*e00 + e01*e01 + e02*e02;
  1463. TFloat32 scaleSqY = e10*e10 + e11*e11 + e12*e12;
  1464. TFloat32 scaleSqZ = e20*e20 + e21*e21 + e22*e22;
  1465. // Calculate scaling inverse
  1466. GEN_ASSERT( !IsZero(scaleSqX) && !IsZero(scaleSqY) && !IsZero(scaleSqZ), "Singular matrix" );
  1467. TFloat32 invScaleX = 1.0f / scaleSqX;
  1468. TFloat32 invScaleY = 1.0f / scaleSqY;
  1469. TFloat32 invScaleZ = 1.0f / scaleSqZ;
  1470. // Inverse is just the transpose with scaling inverse factored in
  1471. TFloat32 t;
  1472. e00 *= invScaleX;
  1473. e11 *= invScaleY;
  1474. e22 *= invScaleZ;
  1475. t = e01;
  1476. e01 = e10 * invScaleY;
  1477. e10 = t * invScaleX;
  1478. t = e02;
  1479. e02 = e20 * invScaleZ;
  1480. e20 = t * invScaleX;
  1481. t = e12;
  1482. e12 = e21 * invScaleZ;
  1483. e21 = t * invScaleY;
  1484. GEN_ENDGUARD;
  1485. }
  1486. // Return the inverse of given matrix assuming it has orthogonal rows, i.e. it is a transformation
  1487. // matrix with no shear. Most efficient inverse for transformations with rotation & scale only
  1488. CMatrix3x3 InverseRotScale( const CMatrix3x3& m )
  1489. {
  1490. GEN_GUARD;
  1491. CMatrix3x3 mOut;
  1492. // Get X, Y & Z scaling (squared)
  1493. TFloat32 scaleSqX = m.e00*m.e00 + m.e01*m.e01 + m.e02*m.e02;
  1494. TFloat32 scaleSqY = m.e10*m.e10 + m.e11*m.e11 + m.e12*m.e12;
  1495. TFloat32 scaleSqZ = m.e20*m.e20 + m.e21*m.e21 + m.e22*m.e22;
  1496. // Calculate scaling inverse
  1497. GEN_ASSERT( !IsZero(scaleSqX) && !IsZero(scaleSqY) && !IsZero(scaleSqZ), "Singular matrix" );
  1498. TFloat32 invScaleX = 1.0f / scaleSqX;
  1499. TFloat32 invScaleY = 1.0f / scaleSqY;
  1500. TFloat32 invScaleZ = 1.0f / scaleSqZ;
  1501. // Inverse is just the transpose with scaling inverse factored in
  1502. mOut.e00 = m.e00 * invScaleX;
  1503. mOut.e01 = m.e10 * invScaleY;
  1504. mOut.e02 = m.e20 * invScaleZ;
  1505. mOut.e10 = m.e01 * invScaleX;
  1506. mOut.e11 = m.e11 * invScaleY;
  1507. mOut.e12 = m.e21 * invScaleZ;
  1508. mOut.e20 = m.e02 * invScaleX;
  1509. mOut.e21 = m.e12 * invScaleY;
  1510. mOut.e22 = m.e22 * invScaleZ;
  1511. return mOut;
  1512. GEN_ENDGUARD;
  1513. }
  1514. // Set this matrix to its inverse assuming that it is a 2D affine matrix
  1515. void CMatrix3x3::InvertAffine2D()
  1516. {
  1517. GEN_GUARD;
  1518. // Calculate determinant of upper left 2x2
  1519. TFloat32 det = e00*e11 - e01*e10;
  1520. GEN_ASSERT( !IsZero(det), "Singular matrix" );
  1521. // Calculate inverse of upper left 2x2
  1522. TFloat32 invDet = 1.0f / det;
  1523. TFloat32 t;
  1524. t = invDet * e00;
  1525. e00 = invDet * e11;
  1526. e11 = t;
  1527. e01 *= invDet;
  1528. e10 *= invDet;
  1529. // Transform negative translation by inverted 3x3 to get inverse
  1530. e20 = -e20*e00 - e21*e10;
  1531. e21 = -e20*e01 - e21*e11;
  1532. GEN_ENDGUARD;
  1533. }
  1534. // Return the inverse of given matrix assuming only that it is a 2D affine matrix
  1535. CMatrix3x3 InverseAffine2D( const CMatrix3x3& m )
  1536. {
  1537. GEN_GUARD;
  1538. CMatrix3x3 mOut;
  1539. // Calculate determinant of upper left 2x2
  1540. TFloat32 det = m.e00*m.e11 - m.e01*m.e10;
  1541. GEN_ASSERT( !IsZero(det), "Singular matrix" );
  1542. // Calculate inverse of upper left 2x2
  1543. TFloat32 invDet = 1.0f / det;
  1544. mOut.e00 = invDet * m.e11;
  1545. mOut.e01 = invDet * m.e01;
  1546. mOut.e02 = 0.0f;
  1547. mOut.e10 = invDet * m.e10;
  1548. mOut.e11 = invDet * m.e00;
  1549. mOut.e12 = 0.0f;
  1550. // Transform negative translation by inverted 3x3 to get inverse
  1551. mOut.e20 = -m.e20*mOut.e00 - m.e21*mOut.e10;
  1552. mOut.e21 = -m.e20*mOut.e01 - m.e21*mOut.e11;
  1553. mOut.e22 = 1.0f;
  1554. return mOut;
  1555. GEN_ENDGUARD;
  1556. }
  1557. // Set this matrix to its inverse. Most general, least efficient inverse function
  1558. void CMatrix3x3::Invert()
  1559. {
  1560. *this = Inverse( *this ); // TODO: Just use non-member version
  1561. }
  1562. // Return the inverse of given matrix. Most general, least efficient inverse function
  1563. CMatrix3x3 Inverse( const CMatrix3x3& m )
  1564. {
  1565. GEN_GUARD;
  1566. CMatrix3x3 mOut;
  1567. // Calculate determinant of upper left 3x3
  1568. TFloat32 det0 = m.e11*m.e22 - m.e21*m.e12;
  1569. TFloat32 det1 = m.e12*m.e20 - m.e22*m.e10;
  1570. TFloat32 det2 = m.e10*m.e21 - m.e20*m.e11;
  1571. TFloat32 det = m.e00*det0 +m.e01*det1 + m.e02*det2;
  1572. GEN_ASSERT( !IsZero(det), "Singular matrix" );
  1573. // Calculate inverse of upper left 3x3
  1574. TFloat32 invDet = 1.0f / det;
  1575. mOut.e00 = invDet * det0;
  1576. mOut.e10 = invDet * det1;
  1577. mOut.e20 = invDet * det2;
  1578. mOut.e01 = invDet * (m.e21*m.e02 - m.e01*m.e22);
  1579. mOut.e11 = invDet * (m.e22*m.e00 - m.e02*m.e20);
  1580. mOut.e21 = invDet * (m.e20*m.e01 - m.e00*m.e21);
  1581. mOut.e02 = invDet * (m.e01*m.e12 - m.e11*m.e02);
  1582. mOut.e12 = invDet * (m.e02*m.e10 - m.e12*m.e00);
  1583. mOut.e22 = invDet * (m.e00*m.e11 - m.e10*m.e01);
  1584. return mOut;
  1585. GEN_ENDGUARD;
  1586. }
  1587. /*-----------------------------------------------------------------------------------------
  1588. Transformation Matrices
  1589. -----------------------------------------------------------------------------------------*/
  1590. // Make this matrix the identity matrix
  1591. void CMatrix3x3::MakeIdentity()
  1592. {
  1593. e00 = 1.0f;
  1594. e01 = 0.0f;
  1595. e02 = 0.0f;
  1596. e10 = 0.0f;
  1597. e11 = 1.0f;
  1598. e12 = 0.0f;
  1599. e20 = 0.0f;
  1600. e21 = 0.0f;
  1601. e22 = 1.0f;
  1602. }
  1603. // Make this matrix an X-axis rotation by the given angle (radians)
  1604. void CMatrix3x3::MakeRotationX( const TFloat32 x )
  1605. {
  1606. TFloat32 sX, cX;
  1607. SinCos( x, &sX, &cX );
  1608. e00 = 1.0f;
  1609. e01 = 0.0f;
  1610. e02 = 0.0f;
  1611. e10 = 0.0f;
  1612. e11 = cX;
  1613. e12 = sX;
  1614. e20 = 0.0f;
  1615. e21 = -sX;
  1616. e22 = cX;
  1617. }
  1618. // Make this matrix a Y-axis rotation by the given angle (radians)
  1619. void CMatrix3x3::MakeRotationY( const TFloat32 y )
  1620. {
  1621. TFloat32 sY, cY;
  1622. SinCos( y, &sY, &cY );
  1623. e00 = cY;
  1624. e01 = 0.0f;
  1625. e02 = -sY;
  1626. e10 = 0.0f;
  1627. e11 = 1.0f;
  1628. e12 = 0.0f;
  1629. e20 = sY;
  1630. e21 = 0.0f;
  1631. e22 = cY;
  1632. }
  1633. // Make this matrix a Z-axis rotation by the given angle (radians)
  1634. void CMatrix3x3::MakeRotationZ( const TFloat32 z )
  1635. {
  1636. TFloat32 sZ, cZ;
  1637. SinCos( z, &sZ, &cZ );
  1638. e00 = cZ;
  1639. e01 = sZ;
  1640. e02 = 0.0f;
  1641. e10 = -sZ;
  1642. e11 = cZ;
  1643. e12 = 0.0f;
  1644. e20 = 0.0f;
  1645. e21 = 0.0f;
  1646. e22 = 1.0f;
  1647. }
  1648. // Make a matrix that is a combined rotation around the X, Y & Z axes by the given angles
  1649. // (radians), applied in the order specified
  1650. void CMatrix3x3::MakeRotation
  1651. (
  1652. const CVector3 angles,
  1653. const ERotationOrder eRotOrder /*= kZXY*/
  1654. )
  1655. {
  1656. GEN_GUARD;
  1657. TFloat32 sX, cX, sY, cY, sZ, cZ;
  1658. SinCos( angles.x, &sX, &cX );
  1659. SinCos( angles.y, &sY, &cY );
  1660. SinCos( angles.z, &sZ, &cZ );
  1661. switch (eRotOrder)
  1662. {
  1663. case kZYX:
  1664. {
  1665. e00 = cZ * cY;
  1666. e01 = sZ * cX + cZ * sY * sX;
  1667. e02 = sZ * sX + -cZ * sY * cX;
  1668. e10 = -sZ * cY;
  1669. e11 = cZ * cX + -sZ * sY * sX;
  1670. e12 = cZ * sX + sZ * sY * cX;
  1671. e20 = sY;
  1672. e21 = -cY * sX;
  1673. e22 = cY * cX;
  1674. break;
  1675. }
  1676. case kYZX:
  1677. {
  1678. e00 = cY * cZ;
  1679. e01 = cY * sZ * cX + sY * sX;
  1680. e02 = cY * sZ * sX + -sY * cX;
  1681. e10 = -sZ;
  1682. e11 = cZ * cX;
  1683. e12 = cZ * sX;
  1684. e20 = sY * cZ;
  1685. e21 = sY * sZ * cX + -cY * sX;
  1686. e22 = sY * sZ * sX + cY * cX;
  1687. break;
  1688. }
  1689. case kXZY:
  1690. {
  1691. e00 = cZ * cY;
  1692. e01 = sZ;
  1693. e02 = -cZ * sY;
  1694. e10 = -cX * sZ * cY + sX * sY;
  1695. e11 = cX * cZ;
  1696. e12 = cX * sZ * sY + sX * cY;
  1697. e20 = sX * sZ * cY + cX * sY;
  1698. e21 = -sX * cZ;
  1699. e22 = -sX * sZ * sY + cX * cY;
  1700. break;
  1701. }
  1702. case kZXY:
  1703. {
  1704. e00 = cZ * cY + sZ * sX * sY;
  1705. e01 = sZ * cX;
  1706. e02 = -cZ * sY + sZ * sX * cY;
  1707. e10 = -sZ * cY + cZ * sX * sY;
  1708. e11 = cZ * cX;
  1709. e12 = sZ * sY + cZ * sX * cY;
  1710. e20 = cX * sY;
  1711. e21 = -sX;
  1712. e22 = cX * cY;
  1713. break;
  1714. }
  1715. case kYXZ:
  1716. {
  1717. e00 = cY * cZ + -sY * sX * sZ;
  1718. e01 = cY * sZ + sY * sX * cZ;
  1719. e02 = -sY * cX;
  1720. e10 = -cX * sZ;
  1721. e11 = cX * cZ;
  1722. e12 = sX;
  1723. e20 = sY * cZ + cY * sX * sZ;
  1724. e21 = sY * sZ + -cY * sX * cZ;
  1725. e22 = cY * cX;
  1726. break;
  1727. }
  1728. case kXYZ:
  1729. {
  1730. e00 = cY * cZ;
  1731. e01 = cY * sZ;
  1732. e02 = -sY;
  1733. e10 = sX * sY * cZ + -cX * sZ;
  1734. e11 = sX * sY * sZ + cX * cZ;
  1735. e12 = sX * cY;
  1736. e20 = cX * sY * cZ + sX * sZ;
  1737. e21 = cX * sY * sZ + -sX * cZ;
  1738. e22 = cX * cY;
  1739. break;
  1740. }
  1741. default:
  1742. GEN_ERROR( "Invalid parameter" );
  1743. }
  1744. GEN_ENDGUARD;
  1745. }
  1746. // Make this matrix a rotation around the given axis by the given angle (radians)
  1747. void CMatrix3x3::MakeRotation
  1748. (
  1749. const CVector3& axis,
  1750. const TFloat32 fAngle
  1751. )
  1752. {
  1753. GEN_GUARD;
  1754. TFloat32 s, c;
  1755. SinCos( fAngle, &s, &c );
  1756. TFloat32 t = 1.0f - c;
  1757. CVector3 axisNorm = Normalise( axis );
  1758. GEN_ASSERT( !axisNorm.IsZero(), "Zero length axis" );
  1759. TFloat32 sx = s * axisNorm.x;
  1760. TFloat32 sy = s * axisNorm.y;
  1761. TFloat32 sz = s * axisNorm.z;
  1762. TFloat32 tx = t * axisNorm.x;
  1763. TFloat32 ty = t * axisNorm.y;
  1764. TFloat32 tz = t * axisNorm.z;
  1765. TFloat32 txy = ty * axisNorm.x;
  1766. TFloat32 tyz = tz * axisNorm.y;
  1767. TFloat32 tzx = tx * axisNorm.z;
  1768. e00 = tx * axisNorm.x + c;
  1769. e01 = txy + sz;
  1770. e02 = tzx - sy;
  1771. e10 = txy - sz;
  1772. e11 = ty * axisNorm.y + c;
  1773. e12 = tyz + sx;
  1774. e20 = tzx + sy;
  1775. e21 = tyz - sx;
  1776. e22 = tz * axisNorm.z + c;
  1777. GEN_ENDGUARD;
  1778. }
  1779. // Make this matrix a scaling in X, Y and Z by the values provided in the given vector
  1780. void CMatrix3x3::MakeScaling( const CVector3& scale )
  1781. {
  1782. e00 = scale.x;
  1783. e01 = 0.0f;
  1784. e02 = 0.0f;
  1785. e10 = 0.0f;
  1786. e11 = scale.y;
  1787. e12 = 0.0f;
  1788. e20 = 0.0f;
  1789. e21 = 0.0f;
  1790. e22 = scale.z;
  1791. }
  1792. // Make this matrix a uniform scaling by the given amount
  1793. void CMatrix3x3::MakeScaling( const TFloat32 fScale )
  1794. {
  1795. e00 = fScale;
  1796. e01 = 0.0f;
  1797. e02 = 0.0f;
  1798. e10 = 0.0f;
  1799. e11 = fScale;
  1800. e12 = 0.0f;
  1801. e20 = 0.0f;
  1802. e21 = 0.0f;
  1803. e22 = fScale;
  1804. }
  1805. /*-----------------------------------------------------------------------------------------
  1806. Transformation Matrices - non-member functions
  1807. -----------------------------------------------------------------------------------------*/
  1808. // Same as class member functions, but these return a new matrix (by value). Can be used
  1809. // as temporaries in calculations, e.g.
  1810. // CMatrix3x3 m = MatrixScaling( 3.0f ) * MatrixRotationX( ToRadians(45.0f) );
  1811. // Return an identity matrix - non-member function
  1812. CMatrix3x3 Matrix3x3Identity()
  1813. {
  1814. CM