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

https://github.com/jcvandan/Warpath · C++ · 2196 lines · 1621 code · 324 blank · 251 comment · 80 complexity · 3860ae4b84bb5f3dce093454987668a9 MD5 · raw file

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