Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

947 lines
29 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. //
  9. // VMatrix always postmultiply vectors as in Ax = b.
  10. // Given a set of basis vectors ((F)orward, (L)eft, (U)p), and a (T)ranslation,
  11. // a matrix to transform a vector into that space looks like this:
  12. // Fx Lx Ux Tx
  13. // Fy Ly Uy Ty
  14. // Fz Lz Uz Tz
  15. // 0 0 0 1
  16. // Note that concatenating matrices needs to multiply them in reverse order.
  17. // ie: if I want to apply matrix A, B, then C, the equation needs to look like this:
  18. // C * B * A * v
  19. // ie:
  20. // v = A * v;
  21. // v = B * v;
  22. // v = C * v;
  23. //=============================================================================
  24. #ifndef VMATRIX_H
  25. #define VMATRIX_H
  26. #ifdef _WIN32
  27. #pragma once
  28. #endif
  29. #include <string.h>
  30. #include "mathlib/vector.h"
  31. #include "mathlib/vplane.h"
  32. #include "mathlib/vector4d.h"
  33. #include "mathlib/mathlib.h"
  34. struct cplane_t;
  35. class VMatrix
  36. {
  37. public:
  38. VMatrix();
  39. VMatrix(
  40. vec_t m00, vec_t m01, vec_t m02, vec_t m03,
  41. vec_t m10, vec_t m11, vec_t m12, vec_t m13,
  42. vec_t m20, vec_t m21, vec_t m22, vec_t m23,
  43. vec_t m30, vec_t m31, vec_t m32, vec_t m33
  44. );
  45. // Creates a matrix where the X axis = forward
  46. // the Y axis = left, and the Z axis = up
  47. VMatrix( const Vector& forward, const Vector& left, const Vector& up );
  48. VMatrix( const Vector& forward, const Vector& left, const Vector& up, const Vector& translation );
  49. // Construct from a 3x4 matrix
  50. VMatrix( const matrix3x4_t& matrix3x4 );
  51. // Set the values in the matrix.
  52. void Init(
  53. vec_t m00, vec_t m01, vec_t m02, vec_t m03,
  54. vec_t m10, vec_t m11, vec_t m12, vec_t m13,
  55. vec_t m20, vec_t m21, vec_t m22, vec_t m23,
  56. vec_t m30, vec_t m31, vec_t m32, vec_t m33
  57. );
  58. // Initialize from a 3x4
  59. void Init( const matrix3x4_t& matrix3x4 );
  60. // array access
  61. inline float* operator[](int i)
  62. {
  63. return m[i];
  64. }
  65. inline const float* operator[](int i) const
  66. {
  67. return m[i];
  68. }
  69. // Get a pointer to m[0][0]
  70. inline float *Base()
  71. {
  72. return &m[0][0];
  73. }
  74. inline const float *Base() const
  75. {
  76. return &m[0][0];
  77. }
  78. void SetLeft(const Vector &vLeft);
  79. void SetUp(const Vector &vUp);
  80. void SetForward(const Vector &vForward);
  81. void GetBasisVectors(Vector &vForward, Vector &vLeft, Vector &vUp) const;
  82. void SetBasisVectors(const Vector &vForward, const Vector &vLeft, const Vector &vUp);
  83. // Get/set the translation.
  84. Vector & GetTranslation( Vector &vTrans ) const;
  85. void SetTranslation(const Vector &vTrans);
  86. void PreTranslate(const Vector &vTrans);
  87. void PostTranslate(const Vector &vTrans);
  88. const matrix3x4_t& As3x4() const;
  89. void CopyFrom3x4( const matrix3x4_t &m3x4 );
  90. void Set3x4( matrix3x4_t& matrix3x4 ) const;
  91. bool operator==( const VMatrix& src ) const;
  92. bool operator!=( const VMatrix& src ) const { return !( *this == src ); }
  93. #ifndef VECTOR_NO_SLOW_OPERATIONS
  94. // Access the basis vectors.
  95. Vector GetLeft() const;
  96. Vector GetUp() const;
  97. Vector GetForward() const;
  98. Vector GetTranslation() const;
  99. #endif
  100. // Matrix->vector operations.
  101. public:
  102. // Multiply by a 3D vector (same as operator*).
  103. void V3Mul(const Vector &vIn, Vector &vOut) const;
  104. // Multiply by a 4D vector.
  105. void V4Mul(const Vector4D &vIn, Vector4D &vOut) const;
  106. #ifndef VECTOR_NO_SLOW_OPERATIONS
  107. // Applies the rotation (ignores translation in the matrix). (This just calls VMul3x3).
  108. Vector ApplyRotation(const Vector &vVec) const;
  109. // Multiply by a vector (divides by w, assumes input w is 1).
  110. Vector operator*(const Vector &vVec) const;
  111. // Multiply by the upper 3x3 part of the matrix (ie: only apply rotation).
  112. Vector VMul3x3(const Vector &vVec) const;
  113. // Apply the inverse (transposed) rotation (only works on pure rotation matrix)
  114. Vector VMul3x3Transpose(const Vector &vVec) const;
  115. // Multiply by the upper 3 rows.
  116. Vector VMul4x3(const Vector &vVec) const;
  117. // Apply the inverse (transposed) transformation (only works on pure rotation/translation)
  118. Vector VMul4x3Transpose(const Vector &vVec) const;
  119. #endif
  120. // Matrix->plane operations.
  121. public:
  122. // Transform the plane. The matrix can only contain translation and rotation.
  123. void TransformPlane( const VPlane &inPlane, VPlane &outPlane ) const;
  124. #ifndef VECTOR_NO_SLOW_OPERATIONS
  125. // Just calls TransformPlane and returns the result.
  126. VPlane operator*(const VPlane &thePlane) const;
  127. #endif
  128. // Matrix->matrix operations.
  129. public:
  130. VMatrix& operator=(const VMatrix &mOther);
  131. // Multiply two matrices (out = this * vm).
  132. void MatrixMul( const VMatrix &vm, VMatrix &out ) const;
  133. // Add two matrices.
  134. const VMatrix& operator+=(const VMatrix &other);
  135. #ifndef VECTOR_NO_SLOW_OPERATIONS
  136. // Just calls MatrixMul and returns the result.
  137. VMatrix operator*(const VMatrix &mOther) const;
  138. // Add/Subtract two matrices.
  139. VMatrix operator+(const VMatrix &other) const;
  140. VMatrix operator-(const VMatrix &other) const;
  141. // Negation.
  142. VMatrix operator-() const;
  143. // Return inverse matrix. Be careful because the results are undefined
  144. // if the matrix doesn't have an inverse (ie: InverseGeneral returns false).
  145. VMatrix operator~() const;
  146. #endif
  147. // Matrix operations.
  148. public:
  149. // Set to identity.
  150. void Identity();
  151. bool IsIdentity() const;
  152. // Setup a matrix for origin and angles.
  153. void SetupMatrixOrgAngles( const Vector &origin, const QAngle &vAngles );
  154. // Setup a matrix for angles and no translation.
  155. void SetupMatrixAngles( const QAngle &vAngles );
  156. // General inverse. This may fail so check the return!
  157. bool InverseGeneral(VMatrix &vInverse) const;
  158. // Does a fast inverse, assuming the matrix only contains translation and rotation.
  159. void InverseTR( VMatrix &mRet ) const;
  160. // Usually used for debug checks. Returns true if the upper 3x3 contains
  161. // unit vectors and they are all orthogonal.
  162. bool IsRotationMatrix() const;
  163. #ifndef VECTOR_NO_SLOW_OPERATIONS
  164. // This calls the other InverseTR and returns the result.
  165. VMatrix InverseTR() const;
  166. // Get the scale of the matrix's basis vectors.
  167. Vector GetScale() const;
  168. // (Fast) multiply by a scaling matrix setup from vScale.
  169. VMatrix Scale(const Vector &vScale);
  170. // Normalize the basis vectors.
  171. VMatrix NormalizeBasisVectors() const;
  172. // Transpose.
  173. VMatrix Transpose() const;
  174. // Transpose upper-left 3x3.
  175. VMatrix Transpose3x3() const;
  176. #endif
  177. public:
  178. // The matrix.
  179. vec_t m[4][4];
  180. };
  181. //-----------------------------------------------------------------------------
  182. // Helper functions.
  183. //-----------------------------------------------------------------------------
  184. #ifndef VECTOR_NO_SLOW_OPERATIONS
  185. // Setup an identity matrix.
  186. VMatrix SetupMatrixIdentity();
  187. // Setup as a scaling matrix.
  188. VMatrix SetupMatrixScale(const Vector &vScale);
  189. // Setup a translation matrix.
  190. VMatrix SetupMatrixTranslation(const Vector &vTranslation);
  191. // Setup a matrix to reflect around the plane.
  192. VMatrix SetupMatrixReflection(const VPlane &thePlane);
  193. // Setup a matrix to project from vOrigin onto thePlane.
  194. VMatrix SetupMatrixProjection(const Vector &vOrigin, const VPlane &thePlane);
  195. // Setup a matrix to rotate the specified amount around the specified axis.
  196. VMatrix SetupMatrixAxisRot(const Vector &vAxis, vec_t fDegrees);
  197. // Setup a matrix from euler angles. Just sets identity and calls MatrixAngles.
  198. VMatrix SetupMatrixAngles(const QAngle &vAngles);
  199. // Setup a matrix for origin and angles.
  200. VMatrix SetupMatrixOrgAngles(const Vector &origin, const QAngle &vAngles);
  201. #endif
  202. #define VMatToString(mat) (static_cast<const char *>(CFmtStr("[ (%f, %f, %f), (%f, %f, %f), (%f, %f, %f), (%f, %f, %f) ]", mat.m[0][0], mat.m[0][1], mat.m[0][2], mat.m[0][3], mat.m[1][0], mat.m[1][1], mat.m[1][2], mat.m[1][3], mat.m[2][0], mat.m[2][1], mat.m[2][2], mat.m[2][3], mat.m[3][0], mat.m[3][1], mat.m[3][2], mat.m[3][3] ))) // ** Note: this generates a temporary, don't hold reference!
  203. //-----------------------------------------------------------------------------
  204. // Returns the point at the intersection on the 3 planes.
  205. // Returns false if it can't be solved (2 or more planes are parallel).
  206. //-----------------------------------------------------------------------------
  207. bool PlaneIntersection( const VPlane &vp1, const VPlane &vp2, const VPlane &vp3, Vector &vOut );
  208. //-----------------------------------------------------------------------------
  209. // These methods are faster. Use them if you want faster code
  210. //-----------------------------------------------------------------------------
  211. void MatrixSetIdentity( VMatrix &dst );
  212. void MatrixTranspose( const VMatrix& src, VMatrix& dst );
  213. void MatrixCopy( const VMatrix& src, VMatrix& dst );
  214. void MatrixMultiply( const VMatrix& src1, const VMatrix& src2, VMatrix& dst );
  215. // Accessors
  216. void MatrixGetColumn( const VMatrix &src, int nCol, Vector *pColumn );
  217. void MatrixSetColumn( VMatrix &src, int nCol, const Vector &column );
  218. void MatrixGetRow( const VMatrix &src, int nCol, Vector *pColumn );
  219. void MatrixSetRow( VMatrix &src, int nCol, const Vector &column );
  220. // Vector3DMultiply treats src2 as if it's a direction vector
  221. void Vector3DMultiply( const VMatrix& src1, const Vector& src2, Vector& dst );
  222. // Vector3DMultiplyPosition treats src2 as if it's a point (adds the translation)
  223. inline void Vector3DMultiplyPosition( const VMatrix& src1, const VectorByValue src2, Vector& dst );
  224. // Vector3DMultiplyPositionProjective treats src2 as if it's a point
  225. // and does the perspective divide at the end
  226. void Vector3DMultiplyPositionProjective( const VMatrix& src1, const Vector &src2, Vector& dst );
  227. // Vector3DMultiplyPosition treats src2 as if it's a direction
  228. // and does the perspective divide at the end
  229. // NOTE: src1 had better be an inverse transpose to use this correctly
  230. void Vector3DMultiplyProjective( const VMatrix& src1, const Vector &src2, Vector& dst );
  231. void Vector4DMultiply( const VMatrix& src1, const Vector4D& src2, Vector4D& dst );
  232. // Same as Vector4DMultiply except that src2 has an implicit W of 1
  233. void Vector4DMultiplyPosition( const VMatrix& src1, const Vector &src2, Vector4D& dst );
  234. // Multiplies the vector by the transpose of the matrix
  235. void Vector3DMultiplyTranspose( const VMatrix& src1, const Vector& src2, Vector& dst );
  236. void Vector4DMultiplyTranspose( const VMatrix& src1, const Vector4D& src2, Vector4D& dst );
  237. // Transform a plane
  238. void MatrixTransformPlane( const VMatrix &src, const cplane_t &inPlane, cplane_t &outPlane );
  239. // Transform a plane that has an axis-aligned normal
  240. void MatrixTransformAxisAlignedPlane( const VMatrix &src, int nDim, float flSign, float flDist, cplane_t &outPlane );
  241. void MatrixBuildTranslation( VMatrix& dst, float x, float y, float z );
  242. void MatrixBuildTranslation( VMatrix& dst, const Vector &translation );
  243. inline void MatrixTranslate( VMatrix& dst, const Vector &translation )
  244. {
  245. VMatrix matTranslation, temp;
  246. MatrixBuildTranslation( matTranslation, translation );
  247. MatrixMultiply( dst, matTranslation, temp );
  248. dst = temp;
  249. }
  250. void MatrixBuildRotationAboutAxis( VMatrix& dst, const Vector& vAxisOfRot, float angleDegrees );
  251. void MatrixBuildRotateZ( VMatrix& dst, float angleDegrees );
  252. inline void MatrixRotate( VMatrix& dst, const Vector& vAxisOfRot, float angleDegrees )
  253. {
  254. VMatrix rotation, temp;
  255. MatrixBuildRotationAboutAxis( rotation, vAxisOfRot, angleDegrees );
  256. MatrixMultiply( dst, rotation, temp );
  257. dst = temp;
  258. }
  259. // Builds a rotation matrix that rotates one direction vector into another
  260. void MatrixBuildRotation( VMatrix &dst, const Vector& initialDirection, const Vector& finalDirection );
  261. // Builds a scale matrix
  262. void MatrixBuildScale( VMatrix &dst, float x, float y, float z );
  263. void MatrixBuildScale( VMatrix &dst, const Vector& scale );
  264. // Build a perspective matrix.
  265. // zNear and zFar are assumed to be positive.
  266. // You end up looking down positive Z, X is to the right, Y is up.
  267. // X range: [0..1]
  268. // Y range: [0..1]
  269. // Z range: [0..1]
  270. void MatrixBuildPerspective( VMatrix &dst, float fovX, float fovY, float zNear, float zFar );
  271. //-----------------------------------------------------------------------------
  272. // Given a projection matrix, take the extremes of the space in transformed into world space and
  273. // get a bounding box.
  274. //-----------------------------------------------------------------------------
  275. void CalculateAABBFromProjectionMatrix( const VMatrix &worldToVolume, Vector *pMins, Vector *pMaxs );
  276. //-----------------------------------------------------------------------------
  277. // Given a projection matrix, take the extremes of the space in transformed into world space and
  278. // get a bounding sphere.
  279. //-----------------------------------------------------------------------------
  280. void CalculateSphereFromProjectionMatrix( const VMatrix &worldToVolume, Vector *pCenter, float *pflRadius );
  281. //-----------------------------------------------------------------------------
  282. // Given an inverse projection matrix, take the extremes of the space in transformed into world space and
  283. // get a bounding box.
  284. //-----------------------------------------------------------------------------
  285. void CalculateAABBFromProjectionMatrixInverse( const VMatrix &volumeToWorld, Vector *pMins, Vector *pMaxs );
  286. //-----------------------------------------------------------------------------
  287. // Given an inverse projection matrix, take the extremes of the space in transformed into world space and
  288. // get a bounding sphere.
  289. //-----------------------------------------------------------------------------
  290. void CalculateSphereFromProjectionMatrixInverse( const VMatrix &volumeToWorld, Vector *pCenter, float *pflRadius );
  291. //-----------------------------------------------------------------------------
  292. // Calculate frustum planes given a clip->world space transform.
  293. //-----------------------------------------------------------------------------
  294. void FrustumPlanesFromMatrix( const VMatrix &clipToWorld, Frustum_t &frustum );
  295. //-----------------------------------------------------------------------------
  296. // Setup a matrix from euler angles.
  297. //-----------------------------------------------------------------------------
  298. void MatrixFromAngles( const QAngle& vAngles, VMatrix& dst );
  299. //-----------------------------------------------------------------------------
  300. // Creates euler angles from a matrix
  301. //-----------------------------------------------------------------------------
  302. void MatrixToAngles( const VMatrix& src, QAngle& vAngles );
  303. //-----------------------------------------------------------------------------
  304. // Does a fast inverse, assuming the matrix only contains translation and rotation.
  305. //-----------------------------------------------------------------------------
  306. void MatrixInverseTR( const VMatrix& src, VMatrix &dst );
  307. //-----------------------------------------------------------------------------
  308. // Inverts any matrix at all
  309. //-----------------------------------------------------------------------------
  310. bool MatrixInverseGeneral(const VMatrix& src, VMatrix& dst);
  311. //-----------------------------------------------------------------------------
  312. // Computes the inverse transpose
  313. //-----------------------------------------------------------------------------
  314. void MatrixInverseTranspose( const VMatrix& src, VMatrix& dst );
  315. //-----------------------------------------------------------------------------
  316. // VMatrix inlines.
  317. //-----------------------------------------------------------------------------
  318. inline VMatrix::VMatrix()
  319. {
  320. }
  321. inline VMatrix::VMatrix(
  322. vec_t m00, vec_t m01, vec_t m02, vec_t m03,
  323. vec_t m10, vec_t m11, vec_t m12, vec_t m13,
  324. vec_t m20, vec_t m21, vec_t m22, vec_t m23,
  325. vec_t m30, vec_t m31, vec_t m32, vec_t m33)
  326. {
  327. Init(
  328. m00, m01, m02, m03,
  329. m10, m11, m12, m13,
  330. m20, m21, m22, m23,
  331. m30, m31, m32, m33
  332. );
  333. }
  334. inline VMatrix::VMatrix( const matrix3x4_t& matrix3x4 )
  335. {
  336. Init( matrix3x4 );
  337. }
  338. //-----------------------------------------------------------------------------
  339. // Creates a matrix where the X axis = forward
  340. // the Y axis = left, and the Z axis = up
  341. //-----------------------------------------------------------------------------
  342. inline VMatrix::VMatrix( const Vector& xAxis, const Vector& yAxis, const Vector& zAxis )
  343. {
  344. Init(
  345. xAxis.x, yAxis.x, zAxis.x, 0.0f,
  346. xAxis.y, yAxis.y, zAxis.y, 0.0f,
  347. xAxis.z, yAxis.z, zAxis.z, 0.0f,
  348. 0.0f, 0.0f, 0.0f, 1.0f
  349. );
  350. }
  351. inline VMatrix::VMatrix( const Vector& xAxis, const Vector& yAxis, const Vector& zAxis, const Vector& translation )
  352. {
  353. Init(
  354. xAxis.x, yAxis.x, zAxis.x, translation.x,
  355. xAxis.y, yAxis.y, zAxis.y, translation.y,
  356. xAxis.z, yAxis.z, zAxis.z, translation.z,
  357. 0.0f, 0.0f, 0.0f, 1.0f
  358. );
  359. }
  360. inline void VMatrix::Init(
  361. vec_t m00, vec_t m01, vec_t m02, vec_t m03,
  362. vec_t m10, vec_t m11, vec_t m12, vec_t m13,
  363. vec_t m20, vec_t m21, vec_t m22, vec_t m23,
  364. vec_t m30, vec_t m31, vec_t m32, vec_t m33
  365. )
  366. {
  367. m[0][0] = m00;
  368. m[0][1] = m01;
  369. m[0][2] = m02;
  370. m[0][3] = m03;
  371. m[1][0] = m10;
  372. m[1][1] = m11;
  373. m[1][2] = m12;
  374. m[1][3] = m13;
  375. m[2][0] = m20;
  376. m[2][1] = m21;
  377. m[2][2] = m22;
  378. m[2][3] = m23;
  379. m[3][0] = m30;
  380. m[3][1] = m31;
  381. m[3][2] = m32;
  382. m[3][3] = m33;
  383. }
  384. //-----------------------------------------------------------------------------
  385. // Initialize from a 3x4
  386. //-----------------------------------------------------------------------------
  387. inline void VMatrix::Init( const matrix3x4_t& matrix3x4 )
  388. {
  389. memcpy(m, matrix3x4.Base(), sizeof( matrix3x4_t ) );
  390. m[3][0] = 0.0f;
  391. m[3][1] = 0.0f;
  392. m[3][2] = 0.0f;
  393. m[3][3] = 1.0f;
  394. }
  395. //-----------------------------------------------------------------------------
  396. // Methods related to the basis vectors of the matrix
  397. //-----------------------------------------------------------------------------
  398. #ifndef VECTOR_NO_SLOW_OPERATIONS
  399. inline Vector VMatrix::GetForward() const
  400. {
  401. return Vector(m[0][0], m[1][0], m[2][0]);
  402. }
  403. inline Vector VMatrix::GetLeft() const
  404. {
  405. return Vector(m[0][1], m[1][1], m[2][1]);
  406. }
  407. inline Vector VMatrix::GetUp() const
  408. {
  409. return Vector(m[0][2], m[1][2], m[2][2]);
  410. }
  411. #endif
  412. inline void VMatrix::SetForward(const Vector &vForward)
  413. {
  414. m[0][0] = vForward.x;
  415. m[1][0] = vForward.y;
  416. m[2][0] = vForward.z;
  417. }
  418. inline void VMatrix::SetLeft(const Vector &vLeft)
  419. {
  420. m[0][1] = vLeft.x;
  421. m[1][1] = vLeft.y;
  422. m[2][1] = vLeft.z;
  423. }
  424. inline void VMatrix::SetUp(const Vector &vUp)
  425. {
  426. m[0][2] = vUp.x;
  427. m[1][2] = vUp.y;
  428. m[2][2] = vUp.z;
  429. }
  430. inline void VMatrix::GetBasisVectors(Vector &vForward, Vector &vLeft, Vector &vUp) const
  431. {
  432. vForward.Init( m[0][0], m[1][0], m[2][0] );
  433. vLeft.Init( m[0][1], m[1][1], m[2][1] );
  434. vUp.Init( m[0][2], m[1][2], m[2][2] );
  435. }
  436. inline void VMatrix::SetBasisVectors(const Vector &vForward, const Vector &vLeft, const Vector &vUp)
  437. {
  438. SetForward(vForward);
  439. SetLeft(vLeft);
  440. SetUp(vUp);
  441. }
  442. //-----------------------------------------------------------------------------
  443. // Methods related to the translation component of the matrix
  444. //-----------------------------------------------------------------------------
  445. #ifndef VECTOR_NO_SLOW_OPERATIONS
  446. inline Vector VMatrix::GetTranslation() const
  447. {
  448. return Vector(m[0][3], m[1][3], m[2][3]);
  449. }
  450. #endif
  451. inline Vector& VMatrix::GetTranslation( Vector &vTrans ) const
  452. {
  453. vTrans.x = m[0][3];
  454. vTrans.y = m[1][3];
  455. vTrans.z = m[2][3];
  456. return vTrans;
  457. }
  458. inline void VMatrix::SetTranslation(const Vector &vTrans)
  459. {
  460. m[0][3] = vTrans.x;
  461. m[1][3] = vTrans.y;
  462. m[2][3] = vTrans.z;
  463. }
  464. //-----------------------------------------------------------------------------
  465. // appply translation to this matrix in the input space
  466. //-----------------------------------------------------------------------------
  467. inline void VMatrix::PreTranslate(const Vector &vTrans)
  468. {
  469. Vector tmp;
  470. Vector3DMultiplyPosition( *this, vTrans, tmp );
  471. m[0][3] = tmp.x;
  472. m[1][3] = tmp.y;
  473. m[2][3] = tmp.z;
  474. }
  475. //-----------------------------------------------------------------------------
  476. // appply translation to this matrix in the output space
  477. //-----------------------------------------------------------------------------
  478. inline void VMatrix::PostTranslate(const Vector &vTrans)
  479. {
  480. m[0][3] += vTrans.x;
  481. m[1][3] += vTrans.y;
  482. m[2][3] += vTrans.z;
  483. }
  484. inline const matrix3x4_t& VMatrix::As3x4() const
  485. {
  486. return *((const matrix3x4_t*)this);
  487. }
  488. inline void VMatrix::CopyFrom3x4( const matrix3x4_t &m3x4 )
  489. {
  490. memcpy( m, m3x4.Base(), sizeof( matrix3x4_t ) );
  491. m[3][0] = m[3][1] = m[3][2] = 0;
  492. m[3][3] = 1;
  493. }
  494. inline void VMatrix::Set3x4( matrix3x4_t& matrix3x4 ) const
  495. {
  496. memcpy(matrix3x4.Base(), m, sizeof( matrix3x4_t ) );
  497. }
  498. //-----------------------------------------------------------------------------
  499. // Matrix math operations
  500. //-----------------------------------------------------------------------------
  501. inline const VMatrix& VMatrix::operator+=(const VMatrix &other)
  502. {
  503. for(int i=0; i < 4; i++)
  504. {
  505. for(int j=0; j < 4; j++)
  506. {
  507. m[i][j] += other.m[i][j];
  508. }
  509. }
  510. return *this;
  511. }
  512. #ifndef VECTOR_NO_SLOW_OPERATIONS
  513. inline VMatrix VMatrix::operator+(const VMatrix &other) const
  514. {
  515. VMatrix ret;
  516. for(int i=0; i < 16; i++)
  517. {
  518. ((float*)ret.m)[i] = ((float*)m)[i] + ((float*)other.m)[i];
  519. }
  520. return ret;
  521. }
  522. inline VMatrix VMatrix::operator-(const VMatrix &other) const
  523. {
  524. VMatrix ret;
  525. for(int i=0; i < 4; i++)
  526. {
  527. for(int j=0; j < 4; j++)
  528. {
  529. ret.m[i][j] = m[i][j] - other.m[i][j];
  530. }
  531. }
  532. return ret;
  533. }
  534. inline VMatrix VMatrix::operator-() const
  535. {
  536. VMatrix ret;
  537. for( int i=0; i < 16; i++ )
  538. {
  539. ((float*)ret.m)[i] = ((float*)m)[i];
  540. }
  541. return ret;
  542. }
  543. #endif // VECTOR_NO_SLOW_OPERATIONS
  544. //-----------------------------------------------------------------------------
  545. // Vector transformation
  546. //-----------------------------------------------------------------------------
  547. #ifndef VECTOR_NO_SLOW_OPERATIONS
  548. inline Vector VMatrix::operator*(const Vector &vVec) const
  549. {
  550. Vector vRet;
  551. vRet.x = m[0][0]*vVec.x + m[0][1]*vVec.y + m[0][2]*vVec.z + m[0][3];
  552. vRet.y = m[1][0]*vVec.x + m[1][1]*vVec.y + m[1][2]*vVec.z + m[1][3];
  553. vRet.z = m[2][0]*vVec.x + m[2][1]*vVec.y + m[2][2]*vVec.z + m[2][3];
  554. return vRet;
  555. }
  556. inline Vector VMatrix::VMul4x3(const Vector &vVec) const
  557. {
  558. Vector vResult;
  559. Vector3DMultiplyPosition( *this, vVec, vResult );
  560. return vResult;
  561. }
  562. inline Vector VMatrix::VMul4x3Transpose(const Vector &vVec) const
  563. {
  564. Vector tmp = vVec;
  565. tmp.x -= m[0][3];
  566. tmp.y -= m[1][3];
  567. tmp.z -= m[2][3];
  568. return Vector(
  569. m[0][0]*tmp.x + m[1][0]*tmp.y + m[2][0]*tmp.z,
  570. m[0][1]*tmp.x + m[1][1]*tmp.y + m[2][1]*tmp.z,
  571. m[0][2]*tmp.x + m[1][2]*tmp.y + m[2][2]*tmp.z
  572. );
  573. }
  574. inline Vector VMatrix::VMul3x3(const Vector &vVec) const
  575. {
  576. return Vector(
  577. m[0][0]*vVec.x + m[0][1]*vVec.y + m[0][2]*vVec.z,
  578. m[1][0]*vVec.x + m[1][1]*vVec.y + m[1][2]*vVec.z,
  579. m[2][0]*vVec.x + m[2][1]*vVec.y + m[2][2]*vVec.z
  580. );
  581. }
  582. inline Vector VMatrix::VMul3x3Transpose(const Vector &vVec) const
  583. {
  584. return Vector(
  585. m[0][0]*vVec.x + m[1][0]*vVec.y + m[2][0]*vVec.z,
  586. m[0][1]*vVec.x + m[1][1]*vVec.y + m[2][1]*vVec.z,
  587. m[0][2]*vVec.x + m[1][2]*vVec.y + m[2][2]*vVec.z
  588. );
  589. }
  590. #endif // VECTOR_NO_SLOW_OPERATIONS
  591. inline void VMatrix::V3Mul(const Vector &vIn, Vector &vOut) const
  592. {
  593. vec_t rw;
  594. rw = 1.0f / (m[3][0]*vIn.x + m[3][1]*vIn.y + m[3][2]*vIn.z + m[3][3]);
  595. vOut.x = (m[0][0]*vIn.x + m[0][1]*vIn.y + m[0][2]*vIn.z + m[0][3]) * rw;
  596. vOut.y = (m[1][0]*vIn.x + m[1][1]*vIn.y + m[1][2]*vIn.z + m[1][3]) * rw;
  597. vOut.z = (m[2][0]*vIn.x + m[2][1]*vIn.y + m[2][2]*vIn.z + m[2][3]) * rw;
  598. }
  599. inline void VMatrix::V4Mul(const Vector4D &vIn, Vector4D &vOut) const
  600. {
  601. vOut[0] = m[0][0]*vIn[0] + m[0][1]*vIn[1] + m[0][2]*vIn[2] + m[0][3]*vIn[3];
  602. vOut[1] = m[1][0]*vIn[0] + m[1][1]*vIn[1] + m[1][2]*vIn[2] + m[1][3]*vIn[3];
  603. vOut[2] = m[2][0]*vIn[0] + m[2][1]*vIn[1] + m[2][2]*vIn[2] + m[2][3]*vIn[3];
  604. vOut[3] = m[3][0]*vIn[0] + m[3][1]*vIn[1] + m[3][2]*vIn[2] + m[3][3]*vIn[3];
  605. }
  606. //-----------------------------------------------------------------------------
  607. // Plane transformation
  608. //-----------------------------------------------------------------------------
  609. inline void VMatrix::TransformPlane( const VPlane &inPlane, VPlane &outPlane ) const
  610. {
  611. Vector vTrans;
  612. Vector3DMultiply( *this, inPlane.m_Normal, outPlane.m_Normal );
  613. outPlane.m_Dist = inPlane.m_Dist * DotProduct( outPlane.m_Normal, outPlane.m_Normal );
  614. outPlane.m_Dist += DotProduct( outPlane.m_Normal, GetTranslation( vTrans ) );
  615. }
  616. //-----------------------------------------------------------------------------
  617. // Other random stuff
  618. //-----------------------------------------------------------------------------
  619. inline void VMatrix::Identity()
  620. {
  621. MatrixSetIdentity( *this );
  622. }
  623. inline bool VMatrix::IsIdentity() const
  624. {
  625. return
  626. m[0][0] == 1.0f && m[0][1] == 0.0f && m[0][2] == 0.0f && m[0][3] == 0.0f &&
  627. m[1][0] == 0.0f && m[1][1] == 1.0f && m[1][2] == 0.0f && m[1][3] == 0.0f &&
  628. m[2][0] == 0.0f && m[2][1] == 0.0f && m[2][2] == 1.0f && m[2][3] == 0.0f &&
  629. m[3][0] == 0.0f && m[3][1] == 0.0f && m[3][2] == 0.0f && m[3][3] == 1.0f;
  630. }
  631. #ifndef VECTOR_NO_SLOW_OPERATIONS
  632. inline Vector VMatrix::ApplyRotation(const Vector &vVec) const
  633. {
  634. return VMul3x3(vVec);
  635. }
  636. inline VMatrix VMatrix::operator~() const
  637. {
  638. VMatrix mRet;
  639. InverseGeneral(mRet);
  640. return mRet;
  641. }
  642. #endif
  643. //-----------------------------------------------------------------------------
  644. // Accessors
  645. //-----------------------------------------------------------------------------
  646. inline void MatrixGetColumn( const VMatrix &src, int nCol, Vector *pColumn )
  647. {
  648. Assert( (nCol >= 0) && (nCol <= 3) );
  649. pColumn->x = src[0][nCol];
  650. pColumn->y = src[1][nCol];
  651. pColumn->z = src[2][nCol];
  652. }
  653. inline void MatrixSetColumn( VMatrix &src, int nCol, const Vector &column )
  654. {
  655. Assert( (nCol >= 0) && (nCol <= 3) );
  656. src.m[0][nCol] = column.x;
  657. src.m[1][nCol] = column.y;
  658. src.m[2][nCol] = column.z;
  659. }
  660. inline void MatrixGetRow( const VMatrix &src, int nRow, Vector *pRow )
  661. {
  662. Assert( (nRow >= 0) && (nRow <= 3) );
  663. *pRow = *(Vector*)src[nRow];
  664. }
  665. inline void MatrixSetRow( VMatrix &dst, int nRow, const Vector &row )
  666. {
  667. Assert( (nRow >= 0) && (nRow <= 3) );
  668. *(Vector*)dst[nRow] = row;
  669. }
  670. //-----------------------------------------------------------------------------
  671. // Vector3DMultiplyPosition treats src2 as if it's a point (adds the translation)
  672. //-----------------------------------------------------------------------------
  673. // NJS: src2 is passed in as a full vector rather than a reference to prevent the need
  674. // for 2 branches and a potential copy in the body. (ie, handling the case when the src2
  675. // reference is the same as the dst reference ).
  676. inline void Vector3DMultiplyPosition( const VMatrix& src1, const VectorByValue src2, Vector& dst )
  677. {
  678. dst[0] = src1[0][0] * src2.x + src1[0][1] * src2.y + src1[0][2] * src2.z + src1[0][3];
  679. dst[1] = src1[1][0] * src2.x + src1[1][1] * src2.y + src1[1][2] * src2.z + src1[1][3];
  680. dst[2] = src1[2][0] * src2.x + src1[2][1] * src2.y + src1[2][2] * src2.z + src1[2][3];
  681. }
  682. //-----------------------------------------------------------------------------
  683. // Transform a plane that has an axis-aligned normal
  684. //-----------------------------------------------------------------------------
  685. inline void MatrixTransformAxisAlignedPlane( const VMatrix &src, int nDim, float flSign, float flDist, cplane_t &outPlane )
  686. {
  687. // See MatrixTransformPlane in the .cpp file for an explanation of the algorithm.
  688. MatrixGetColumn( src, nDim, &outPlane.normal );
  689. outPlane.normal *= flSign;
  690. outPlane.dist = flDist * DotProduct( outPlane.normal, outPlane.normal );
  691. // NOTE: Writing this out by hand because it doesn't inline (inline depth isn't large enough)
  692. // This should read outPlane.dist += DotProduct( outPlane.normal, src.GetTranslation );
  693. outPlane.dist += outPlane.normal.x * src.m[0][3] + outPlane.normal.y * src.m[1][3] + outPlane.normal.z * src.m[2][3];
  694. }
  695. //-----------------------------------------------------------------------------
  696. // Matrix equality test
  697. //-----------------------------------------------------------------------------
  698. inline bool MatricesAreEqual( const VMatrix &src1, const VMatrix &src2, float flTolerance )
  699. {
  700. for ( int i = 0; i < 3; ++i )
  701. {
  702. for ( int j = 0; j < 3; ++j )
  703. {
  704. if ( fabs( src1[i][j] - src2[i][j] ) > flTolerance )
  705. return false;
  706. }
  707. }
  708. return true;
  709. }
  710. //-----------------------------------------------------------------------------
  711. //
  712. //-----------------------------------------------------------------------------
  713. void MatrixBuildOrtho( VMatrix& dst, double left, double top, double right, double bottom, double zNear, double zFar );
  714. void MatrixBuildPerspectiveX( VMatrix& dst, double flFovX, double flAspect, double flZNear, double flZFar );
  715. void MatrixBuildPerspectiveOffCenterX( VMatrix& dst, double flFovX, double flAspect, double flZNear, double flZFar, double bottom, double top, double left, double right );
  716. void MatrixBuildPerspectiveZRange( VMatrix& dst, double flZNear, double flZFar );
  717. inline void MatrixOrtho( VMatrix& dst, double left, double top, double right, double bottom, double zNear, double zFar )
  718. {
  719. VMatrix mat;
  720. MatrixBuildOrtho( mat, left, top, right, bottom, zNear, zFar );
  721. VMatrix temp;
  722. MatrixMultiply( dst, mat, temp );
  723. dst = temp;
  724. }
  725. inline void MatrixPerspectiveX( VMatrix& dst, double flFovX, double flAspect, double flZNear, double flZFar )
  726. {
  727. VMatrix mat;
  728. MatrixBuildPerspectiveX( mat, flFovX, flAspect, flZNear, flZFar );
  729. VMatrix temp;
  730. MatrixMultiply( dst, mat, temp );
  731. dst = temp;
  732. }
  733. inline void MatrixPerspectiveOffCenterX( VMatrix& dst, double flFovX, double flAspect, double flZNear, double flZFar, double bottom, double top, double left, double right )
  734. {
  735. VMatrix mat;
  736. MatrixBuildPerspectiveOffCenterX( mat, flFovX, flAspect, flZNear, flZFar, bottom, top, left, right );
  737. VMatrix temp;
  738. MatrixMultiply( dst, mat, temp );
  739. dst = temp;
  740. }
  741. #endif