Counter Strike : Global Offensive Source Code
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.

1353 lines
44 KiB

  1. //========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #if !defined(_STATIC_LINKED) || defined(_SHARED_LIB)
  9. #include "basetypes.h"
  10. #include "mathlib/vmatrix.h"
  11. #include "mathlib/mathlib.h"
  12. #include <string.h>
  13. #include "mathlib/vector4d.h"
  14. #include "ssemath.h"
  15. #include "tier0/dbg.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. #pragma warning (disable : 4700) // local variable 'x' used without having been initialized
  19. // ------------------------------------------------------------------------------------------- //
  20. // Helper functions.
  21. // ------------------------------------------------------------------------------------------- //
  22. #ifndef VECTOR_NO_SLOW_OPERATIONS
  23. VMatrix SetupMatrixIdentity()
  24. {
  25. return VMatrix(
  26. 1.0f, 0.0f, 0.0f, 0.0f,
  27. 0.0f, 1.0f, 0.0f, 0.0f,
  28. 0.0f, 0.0f, 1.0f, 0.0f,
  29. 0.0f, 0.0f, 0.0f, 1.0f);
  30. }
  31. VMatrix SetupMatrixTranslation(const Vector &vTranslation)
  32. {
  33. return VMatrix(
  34. 1.0f, 0.0f, 0.0f, vTranslation.x,
  35. 0.0f, 1.0f, 0.0f, vTranslation.y,
  36. 0.0f, 0.0f, 1.0f, vTranslation.z,
  37. 0.0f, 0.0f, 0.0f, 1.0f
  38. );
  39. }
  40. VMatrix SetupMatrixScale(const Vector &vScale)
  41. {
  42. return VMatrix(
  43. vScale.x, 0.0f, 0.0f, 0.0f,
  44. 0.0f, vScale.y, 0.0f, 0.0f,
  45. 0.0f, 0.0f, vScale.z, 0.0f,
  46. 0.0f, 0.0f, 0.0f, 1.0f
  47. );
  48. }
  49. VMatrix SetupMatrixReflection(const VPlane &thePlane)
  50. {
  51. VMatrix mReflect, mBack, mForward;
  52. Vector vOrigin, N;
  53. N = thePlane.m_Normal;
  54. mReflect.Init(
  55. -2.0f*N.x*N.x + 1.0f, -2.0f*N.x*N.y, -2.0f*N.x*N.z, 0.0f,
  56. -2.0f*N.y*N.x, -2.0f*N.y*N.y + 1.0f, -2.0f*N.y*N.z, 0.0f,
  57. -2.0f*N.z*N.x, -2.0f*N.z*N.y, -2.0f*N.z*N.z + 1.0f, 0.0f,
  58. 0.0f, 0.0f, 0.0f, 1.0f
  59. );
  60. vOrigin = thePlane.GetPointOnPlane();
  61. mBack.Identity();
  62. mBack.SetTranslation(-vOrigin);
  63. mForward.Identity();
  64. mForward.SetTranslation(vOrigin);
  65. // (multiplied in reverse order, so it translates to the origin point,
  66. // reflects, and translates back).
  67. return mForward * mReflect * mBack;
  68. }
  69. VMatrix SetupMatrixProjection(const Vector &vOrigin, const VPlane &thePlane)
  70. {
  71. vec_t dot;
  72. VMatrix mRet;
  73. #define PN thePlane.m_Normal
  74. #define PD thePlane.m_Dist;
  75. dot = PN[0]*vOrigin.x + PN[1]*vOrigin.y + PN[2]*vOrigin.z - PD;
  76. mRet.m[0][0] = dot - vOrigin.x * PN[0];
  77. mRet.m[0][1] = -vOrigin.x * PN[1];
  78. mRet.m[0][2] = -vOrigin.x * PN[2];
  79. mRet.m[0][3] = -vOrigin.x * -PD;
  80. mRet.m[1][0] = -vOrigin.y * PN[0];
  81. mRet.m[1][1] = dot - vOrigin.y * PN[1];
  82. mRet.m[1][2] = -vOrigin.y * PN[2];
  83. mRet.m[1][3] = -vOrigin.y * -PD;
  84. mRet.m[2][0] = -vOrigin.z * PN[0];
  85. mRet.m[2][1] = -vOrigin.z * PN[1];
  86. mRet.m[2][2] = dot - vOrigin.z * PN[2];
  87. mRet.m[2][3] = -vOrigin.z * -PD;
  88. mRet.m[3][0] = -PN[0];
  89. mRet.m[3][1] = -PN[1];
  90. mRet.m[3][2] = -PN[2];
  91. mRet.m[3][3] = dot + PD;
  92. #undef PN
  93. #undef PD
  94. return mRet;
  95. }
  96. VMatrix SetupMatrixAxisRot(const Vector &vAxis, vec_t fDegrees)
  97. {
  98. vec_t s, c, t; // sin, cos, 1-cos
  99. vec_t tx, ty, tz;
  100. vec_t sx, sy, sz;
  101. vec_t fRadians;
  102. fRadians = fDegrees * (M_PI / 180.0f);
  103. s = (vec_t)sin(fRadians);
  104. c = (vec_t)cos(fRadians);
  105. t = 1.0f - c;
  106. tx = t * vAxis.x; ty = t * vAxis.y; tz = t * vAxis.z;
  107. sx = s * vAxis.x; sy = s * vAxis.y; sz = s * vAxis.z;
  108. return VMatrix(
  109. tx*vAxis.x + c, tx*vAxis.y - sz, tx*vAxis.z + sy, 0.0f,
  110. tx*vAxis.y + sz, ty*vAxis.y + c, ty*vAxis.z - sx, 0.0f,
  111. tx*vAxis.z - sy, ty*vAxis.z + sx, tz*vAxis.z + c, 0.0f,
  112. 0.0f, 0.0f, 0.0f, 1.0f);
  113. }
  114. // Basically takes a cross product and then does the same thing as SetupMatrixAxisRot
  115. // above, but takes advantage of the fact that the sin angle is precomputed.
  116. VMatrix SetupMatrixAxisToAxisRot(const Vector &vFromAxis, const Vector &vToAxis)
  117. {
  118. Assert( vFromAxis.LengthSqr() == 1 ); // these axes
  119. Assert( vToAxis.LengthSqr() == 1 ); // must be normal.
  120. vec_t s, c, t; // sin(theta), cos(theta), 1-cos
  121. vec_t tx, ty, tz;
  122. vec_t sx, sy, sz;
  123. Vector vAxis = vFromAxis.Cross(vToAxis);
  124. s = vAxis.Length();
  125. c = vFromAxis.Dot(vToAxis);
  126. t = 1.0f - c;
  127. if ( s > 0 )
  128. {
  129. vAxis *= 1.0/s;
  130. tx = t * vAxis.x; ty = t * vAxis.y; tz = t * vAxis.z;
  131. sx = s * vAxis.x; sy = s * vAxis.y; sz = s * vAxis.z;
  132. return VMatrix(
  133. tx*vAxis.x + c, tx*vAxis.y - sz, tx*vAxis.z + sy, 0.0f,
  134. tx*vAxis.y + sz, ty*vAxis.y + c, ty*vAxis.z - sx, 0.0f,
  135. tx*vAxis.z - sy, ty*vAxis.z + sx, tz*vAxis.z + c, 0.0f,
  136. 0.0f, 0.0f, 0.0f, 1.0f);
  137. }
  138. else
  139. {
  140. return SetupMatrixIdentity();
  141. }
  142. }
  143. VMatrix SetupMatrixAngles(const QAngle &vAngles)
  144. {
  145. VMatrix mRet;
  146. MatrixFromAngles( vAngles, mRet );
  147. return mRet;
  148. }
  149. VMatrix SetupMatrixOrgAngles(const Vector &origin, const QAngle &vAngles)
  150. {
  151. VMatrix mRet;
  152. mRet.SetupMatrixOrgAngles( origin, vAngles );
  153. return mRet;
  154. }
  155. #endif // VECTOR_NO_SLOW_OPERATIONS
  156. #if 1
  157. bool PlaneIntersection( const VPlane &vp1, const VPlane &vp2, const VPlane &vp3, Vector &vOut )
  158. {
  159. Vector v2Cross3 = CrossProduct( vp2.m_Normal, vp3.m_Normal );
  160. float flDenom = DotProduct( vp1.m_Normal, v2Cross3 );
  161. if ( fabs( flDenom ) < FLT_EPSILON )
  162. return false;
  163. Vector vRet = vp1.m_Dist * v2Cross3 + vp2.m_Dist * CrossProduct( vp3.m_Normal, vp1.m_Normal ) + vp3.m_Dist * CrossProduct( vp1.m_Normal, vp2.m_Normal );
  164. vOut = vRet * ( 1.0 / flDenom );
  165. return true;
  166. }
  167. #else // old slow innaccurate code
  168. bool PlaneIntersection( const VPlane &vp1, const VPlane &vp2, const VPlane &vp3, Vector &vOut )
  169. {
  170. VMatrix mMat, mInverse;
  171. mMat.Init(
  172. vp1.m_Normal.x, vp1.m_Normal.y, vp1.m_Normal.z, -vp1.m_Dist,
  173. vp2.m_Normal.x, vp2.m_Normal.y, vp2.m_Normal.z, -vp2.m_Dist,
  174. vp3.m_Normal.x, vp3.m_Normal.y, vp3.m_Normal.z, -vp3.m_Dist,
  175. 0.0f, 0.0f, 0.0f, 1.0f
  176. );
  177. if(mMat.InverseGeneral(mInverse))
  178. {
  179. //vOut = mInverse * Vector(0.0f, 0.0f, 0.0f);
  180. mInverse.GetTranslation( vOut );
  181. return true;
  182. }
  183. else
  184. {
  185. return false;
  186. }
  187. }
  188. #endif
  189. // ------------------------------------------------------------------------------------------- //
  190. // VMatrix functions.
  191. // ------------------------------------------------------------------------------------------- //
  192. VMatrix& VMatrix::operator=(const VMatrix &mOther)
  193. {
  194. m[0][0] = mOther.m[0][0];
  195. m[0][1] = mOther.m[0][1];
  196. m[0][2] = mOther.m[0][2];
  197. m[0][3] = mOther.m[0][3];
  198. m[1][0] = mOther.m[1][0];
  199. m[1][1] = mOther.m[1][1];
  200. m[1][2] = mOther.m[1][2];
  201. m[1][3] = mOther.m[1][3];
  202. m[2][0] = mOther.m[2][0];
  203. m[2][1] = mOther.m[2][1];
  204. m[2][2] = mOther.m[2][2];
  205. m[2][3] = mOther.m[2][3];
  206. m[3][0] = mOther.m[3][0];
  207. m[3][1] = mOther.m[3][1];
  208. m[3][2] = mOther.m[3][2];
  209. m[3][3] = mOther.m[3][3];
  210. return *this;
  211. }
  212. bool VMatrix::operator==( const VMatrix& src ) const
  213. {
  214. return !memcmp( src.m, m, sizeof(m) );
  215. }
  216. void VMatrix::MatrixMul( const VMatrix &vm, VMatrix &out ) const
  217. {
  218. out.Init(
  219. m[0][0]*vm.m[0][0] + m[0][1]*vm.m[1][0] + m[0][2]*vm.m[2][0] + m[0][3]*vm.m[3][0],
  220. m[0][0]*vm.m[0][1] + m[0][1]*vm.m[1][1] + m[0][2]*vm.m[2][1] + m[0][3]*vm.m[3][1],
  221. m[0][0]*vm.m[0][2] + m[0][1]*vm.m[1][2] + m[0][2]*vm.m[2][2] + m[0][3]*vm.m[3][2],
  222. m[0][0]*vm.m[0][3] + m[0][1]*vm.m[1][3] + m[0][2]*vm.m[2][3] + m[0][3]*vm.m[3][3],
  223. m[1][0]*vm.m[0][0] + m[1][1]*vm.m[1][0] + m[1][2]*vm.m[2][0] + m[1][3]*vm.m[3][0],
  224. m[1][0]*vm.m[0][1] + m[1][1]*vm.m[1][1] + m[1][2]*vm.m[2][1] + m[1][3]*vm.m[3][1],
  225. m[1][0]*vm.m[0][2] + m[1][1]*vm.m[1][2] + m[1][2]*vm.m[2][2] + m[1][3]*vm.m[3][2],
  226. m[1][0]*vm.m[0][3] + m[1][1]*vm.m[1][3] + m[1][2]*vm.m[2][3] + m[1][3]*vm.m[3][3],
  227. m[2][0]*vm.m[0][0] + m[2][1]*vm.m[1][0] + m[2][2]*vm.m[2][0] + m[2][3]*vm.m[3][0],
  228. m[2][0]*vm.m[0][1] + m[2][1]*vm.m[1][1] + m[2][2]*vm.m[2][1] + m[2][3]*vm.m[3][1],
  229. m[2][0]*vm.m[0][2] + m[2][1]*vm.m[1][2] + m[2][2]*vm.m[2][2] + m[2][3]*vm.m[3][2],
  230. m[2][0]*vm.m[0][3] + m[2][1]*vm.m[1][3] + m[2][2]*vm.m[2][3] + m[2][3]*vm.m[3][3],
  231. m[3][0]*vm.m[0][0] + m[3][1]*vm.m[1][0] + m[3][2]*vm.m[2][0] + m[3][3]*vm.m[3][0],
  232. m[3][0]*vm.m[0][1] + m[3][1]*vm.m[1][1] + m[3][2]*vm.m[2][1] + m[3][3]*vm.m[3][1],
  233. m[3][0]*vm.m[0][2] + m[3][1]*vm.m[1][2] + m[3][2]*vm.m[2][2] + m[3][3]*vm.m[3][2],
  234. m[3][0]*vm.m[0][3] + m[3][1]*vm.m[1][3] + m[3][2]*vm.m[2][3] + m[3][3]*vm.m[3][3]
  235. );
  236. }
  237. #ifndef VECTOR_NO_SLOW_OPERATIONS
  238. VMatrix VMatrix::operator*(const VMatrix &vm) const
  239. {
  240. VMatrix ret;
  241. MatrixMul( vm, ret );
  242. return ret;
  243. }
  244. #endif
  245. bool VMatrix::InverseGeneral(VMatrix &vInverse) const
  246. {
  247. return MatrixInverseGeneral( *this, vInverse );
  248. }
  249. bool MatrixInverseGeneral(const VMatrix& src, VMatrix& dst)
  250. {
  251. int iRow, i, j, iTemp, iTest;
  252. vec_t mul, fTest, fLargest;
  253. vec_t mat[4][8];
  254. int rowMap[4], iLargest;
  255. vec_t *pOut, *pRow, *pScaleRow;
  256. // How it's done.
  257. // AX = I
  258. // A = this
  259. // X = the matrix we're looking for
  260. // I = identity
  261. // Setup AI
  262. for(i=0; i < 4; i++)
  263. {
  264. const vec_t *pIn = src[i];
  265. pOut = mat[i];
  266. for(j=0; j < 4; j++)
  267. {
  268. pOut[j] = pIn[j];
  269. }
  270. pOut[4] = 0.0f;
  271. pOut[5] = 0.0f;
  272. pOut[6] = 0.0f;
  273. pOut[7] = 0.0f;
  274. pOut[i+4] = 1.0f;
  275. rowMap[i] = i;
  276. }
  277. // Use row operations to get to reduced row-echelon form using these rules:
  278. // 1. Multiply or divide a row by a nonzero number.
  279. // 2. Add a multiple of one row to another.
  280. // 3. Interchange two rows.
  281. for(iRow=0; iRow < 4; iRow++)
  282. {
  283. // Find the row with the largest element in this column.
  284. fLargest = 1e-6f;
  285. iLargest = -1;
  286. for(iTest=iRow; iTest < 4; iTest++)
  287. {
  288. fTest = (vec_t)FloatMakePositive(mat[rowMap[iTest]][iRow]);
  289. if(fTest > fLargest)
  290. {
  291. iLargest = iTest;
  292. fLargest = fTest;
  293. }
  294. }
  295. // They're all too small.. sorry.
  296. if(iLargest == -1)
  297. {
  298. return false;
  299. }
  300. // Swap the rows.
  301. iTemp = rowMap[iLargest];
  302. rowMap[iLargest] = rowMap[iRow];
  303. rowMap[iRow] = iTemp;
  304. pRow = mat[rowMap[iRow]];
  305. // Divide this row by the element.
  306. mul = 1.0f / pRow[iRow];
  307. for(j=0; j < 8; j++)
  308. pRow[j] *= mul;
  309. pRow[iRow] = 1.0f; // Preserve accuracy...
  310. // Eliminate this element from the other rows using operation 2.
  311. for(i=0; i < 4; i++)
  312. {
  313. if(i == iRow)
  314. continue;
  315. pScaleRow = mat[rowMap[i]];
  316. // Multiply this row by -(iRow*the element).
  317. mul = -pScaleRow[iRow];
  318. for(j=0; j < 8; j++)
  319. {
  320. pScaleRow[j] += pRow[j] * mul;
  321. }
  322. pScaleRow[iRow] = 0.0f; // Preserve accuracy...
  323. }
  324. }
  325. // The inverse is on the right side of AX now (the identity is on the left).
  326. for(i=0; i < 4; i++)
  327. {
  328. const vec_t *pIn = mat[rowMap[i]] + 4;
  329. pOut = dst.m[i];
  330. for(j=0; j < 4; j++)
  331. {
  332. pOut[j] = pIn[j];
  333. }
  334. }
  335. return true;
  336. }
  337. //-----------------------------------------------------------------------------
  338. // Does a fast inverse, assuming the matrix only contains translation and rotation.
  339. //-----------------------------------------------------------------------------
  340. void MatrixInverseTR( const VMatrix& src, VMatrix &dst )
  341. {
  342. Vector vTrans, vNewTrans;
  343. // Transpose the upper 3x3.
  344. dst.m[0][0] = src.m[0][0]; dst.m[0][1] = src.m[1][0]; dst.m[0][2] = src.m[2][0];
  345. dst.m[1][0] = src.m[0][1]; dst.m[1][1] = src.m[1][1]; dst.m[1][2] = src.m[2][1];
  346. dst.m[2][0] = src.m[0][2]; dst.m[2][1] = src.m[1][2]; dst.m[2][2] = src.m[2][2];
  347. // Transform the translation.
  348. vTrans.Init( -src.m[0][3], -src.m[1][3], -src.m[2][3] );
  349. Vector3DMultiply( dst, vTrans, vNewTrans );
  350. MatrixSetColumn( dst, 3, vNewTrans );
  351. // Fill in the bottom row.
  352. dst.m[3][0] = dst.m[3][1] = dst.m[3][2] = 0.0f;
  353. dst.m[3][3] = 1.0f;
  354. }
  355. void VMatrix::InverseTR( VMatrix &ret ) const
  356. {
  357. MatrixInverseTR( *this, ret );
  358. }
  359. void MatrixInverseTranspose( const VMatrix& src, VMatrix& dst )
  360. {
  361. src.InverseGeneral( dst );
  362. MatrixTranspose( dst, dst );
  363. }
  364. //-----------------------------------------------------------------------------
  365. // Computes the inverse transpose
  366. //-----------------------------------------------------------------------------
  367. void MatrixInverseTranspose( const matrix3x4_t& src, matrix3x4_t& dst )
  368. {
  369. VMatrix tmp, out;
  370. tmp.CopyFrom3x4( src );
  371. ::MatrixInverseTranspose( tmp, out );
  372. out.Set3x4( dst );
  373. }
  374. #ifndef VECTOR_NO_SLOW_OPERATIONS
  375. VMatrix VMatrix::InverseTR() const
  376. {
  377. VMatrix ret;
  378. MatrixInverseTR( *this, ret );
  379. return ret;
  380. }
  381. Vector VMatrix::GetScale() const
  382. {
  383. Vector vecs[3];
  384. GetBasisVectors(vecs[0], vecs[1], vecs[2]);
  385. return Vector(
  386. vecs[0].Length(),
  387. vecs[1].Length(),
  388. vecs[2].Length()
  389. );
  390. }
  391. VMatrix VMatrix::Scale(const Vector &vScale)
  392. {
  393. return VMatrix(
  394. m[0][0]*vScale.x, m[0][1]*vScale.y, m[0][2]*vScale.z, m[0][3],
  395. m[1][0]*vScale.x, m[1][1]*vScale.y, m[1][2]*vScale.z, m[1][3],
  396. m[2][0]*vScale.x, m[2][1]*vScale.y, m[2][2]*vScale.z, m[2][3],
  397. m[3][0]*vScale.x, m[3][1]*vScale.y, m[3][2]*vScale.z, 1.0f
  398. );
  399. }
  400. VMatrix VMatrix::NormalizeBasisVectors() const
  401. {
  402. Vector vecs[3];
  403. VMatrix mRet;
  404. GetBasisVectors(vecs[0], vecs[1], vecs[2]);
  405. VectorNormalize( vecs[0] );
  406. VectorNormalize( vecs[1] );
  407. VectorNormalize( vecs[2] );
  408. mRet.SetBasisVectors(vecs[0], vecs[1], vecs[2]);
  409. // Set everything but basis vectors to identity.
  410. mRet.m[3][0] = mRet.m[3][1] = mRet.m[3][2] = 0.0f;
  411. mRet.m[3][3] = 1.0f;
  412. return mRet;
  413. }
  414. VMatrix VMatrix::Transpose() const
  415. {
  416. return VMatrix(
  417. m[0][0], m[1][0], m[2][0], m[3][0],
  418. m[0][1], m[1][1], m[2][1], m[3][1],
  419. m[0][2], m[1][2], m[2][2], m[3][2],
  420. m[0][3], m[1][3], m[2][3], m[3][3]);
  421. }
  422. // Transpose upper-left 3x3.
  423. VMatrix VMatrix::Transpose3x3() const
  424. {
  425. return VMatrix(
  426. m[0][0], m[1][0], m[2][0], m[0][3],
  427. m[0][1], m[1][1], m[2][1], m[1][3],
  428. m[0][2], m[1][2], m[2][2], m[2][3],
  429. m[3][0], m[3][1], m[3][2], m[3][3]);
  430. }
  431. #endif // VECTOR_NO_SLOW_OPERATIONS
  432. bool VMatrix::IsRotationMatrix() const
  433. {
  434. Vector &v1 = (Vector&)m[0][0];
  435. Vector &v2 = (Vector&)m[1][0];
  436. Vector &v3 = (Vector&)m[2][0];
  437. return
  438. FloatMakePositive( 1 - v1.Length() ) < 0.01f &&
  439. FloatMakePositive( 1 - v2.Length() ) < 0.01f &&
  440. FloatMakePositive( 1 - v3.Length() ) < 0.01f &&
  441. FloatMakePositive( v1.Dot(v2) ) < 0.01f &&
  442. FloatMakePositive( v1.Dot(v3) ) < 0.01f &&
  443. FloatMakePositive( v2.Dot(v3) ) < 0.01f;
  444. }
  445. void VMatrix::SetupMatrixOrgAngles( const Vector &origin, const QAngle &vAngles )
  446. {
  447. float sr, sp, sy, cr, cp, cy;
  448. SinCos( DEG2RAD( vAngles[YAW] ), &sy, &cy );
  449. SinCos( DEG2RAD( vAngles[PITCH] ), &sp, &cp );
  450. SinCos( DEG2RAD( vAngles[ROLL] ), &sr, &cr );
  451. // matrix = (YAW * PITCH) * ROLL
  452. m[0][0] = cp*cy;
  453. m[1][0] = cp*sy;
  454. m[2][0] = -sp;
  455. m[0][1] = sr*sp*cy+cr*-sy;
  456. m[1][1] = sr*sp*sy+cr*cy;
  457. m[2][1] = sr*cp;
  458. m[0][2] = (cr*sp*cy+-sr*-sy);
  459. m[1][2] = (cr*sp*sy+-sr*cy);
  460. m[2][2] = cr*cp;
  461. m[0][3] = 0.f;
  462. m[1][3] = 0.f;
  463. m[2][3] = 0.f;
  464. // Add translation
  465. m[0][3] = origin.x;
  466. m[1][3] = origin.y;
  467. m[2][3] = origin.z;
  468. m[3][0] = 0.0f;
  469. m[3][1] = 0.0f;
  470. m[3][2] = 0.0f;
  471. m[3][3] = 1.0f;
  472. }
  473. //-----------------------------------------------------------------------------
  474. // Sets matrix to identity
  475. //-----------------------------------------------------------------------------
  476. void MatrixSetIdentity( VMatrix &dst )
  477. {
  478. dst[0][0] = 1.0f; dst[0][1] = 0.0f; dst[0][2] = 0.0f; dst[0][3] = 0.0f;
  479. dst[1][0] = 0.0f; dst[1][1] = 1.0f; dst[1][2] = 0.0f; dst[1][3] = 0.0f;
  480. dst[2][0] = 0.0f; dst[2][1] = 0.0f; dst[2][2] = 1.0f; dst[2][3] = 0.0f;
  481. dst[3][0] = 0.0f; dst[3][1] = 0.0f; dst[3][2] = 0.0f; dst[3][3] = 1.0f;
  482. }
  483. //-----------------------------------------------------------------------------
  484. // Setup a matrix from euler angles.
  485. //-----------------------------------------------------------------------------
  486. void MatrixFromAngles( const QAngle& vAngles, VMatrix& dst )
  487. {
  488. dst.SetupMatrixOrgAngles( vec3_origin, vAngles );
  489. }
  490. //-----------------------------------------------------------------------------
  491. // Creates euler angles from a matrix
  492. //-----------------------------------------------------------------------------
  493. void MatrixToAngles( const VMatrix& src, QAngle& vAngles )
  494. {
  495. float forward[3];
  496. float left[3];
  497. float up[3];
  498. // Extract the basis vectors from the matrix. Since we only need the Z
  499. // component of the up vector, we don't get X and Y.
  500. forward[0] = src[0][0];
  501. forward[1] = src[1][0];
  502. forward[2] = src[2][0];
  503. left[0] = src[0][1];
  504. left[1] = src[1][1];
  505. left[2] = src[2][1];
  506. up[2] = src[2][2];
  507. float xyDist = sqrtf( forward[0] * forward[0] + forward[1] * forward[1] );
  508. // enough here to get angles?
  509. if ( xyDist > 0.001f )
  510. {
  511. // (yaw) y = ATAN( forward.y, forward.x ); -- in our space, forward is the X axis
  512. vAngles[1] = RAD2DEG( atan2f( forward[1], forward[0] ) );
  513. // The engine does pitch inverted from this, but we always end up negating it in the DLL
  514. // UNDONE: Fix the engine to make it consistent
  515. // (pitch) x = ATAN( -forward.z, sqrt(forward.x*forward.x+forward.y*forward.y) );
  516. vAngles[0] = RAD2DEG( atan2f( -forward[2], xyDist ) );
  517. // (roll) z = ATAN( left.z, up.z );
  518. vAngles[2] = RAD2DEG( atan2f( left[2], up[2] ) );
  519. }
  520. else // forward is mostly Z, gimbal lock-
  521. {
  522. // (yaw) y = ATAN( -left.x, left.y ); -- forward is mostly z, so use right for yaw
  523. vAngles[1] = RAD2DEG( atan2f( -left[0], left[1] ) );
  524. // The engine does pitch inverted from this, but we always end up negating it in the DLL
  525. // UNDONE: Fix the engine to make it consistent
  526. // (pitch) x = ATAN( -forward.z, sqrt(forward.x*forward.x+forward.y*forward.y) );
  527. vAngles[0] = RAD2DEG( atan2f( -forward[2], xyDist ) );
  528. // Assume no roll in this case as one degree of freedom has been lost (i.e. yaw == roll)
  529. vAngles[2] = 0;
  530. }
  531. }
  532. //-----------------------------------------------------------------------------
  533. // Transpose
  534. //-----------------------------------------------------------------------------
  535. inline void Swap( float& a, float& b )
  536. {
  537. float tmp = a;
  538. a = b;
  539. b = tmp;
  540. }
  541. void MatrixTranspose( const VMatrix& src, VMatrix& dst )
  542. {
  543. if (&src == &dst)
  544. {
  545. Swap( dst[0][1], dst[1][0] );
  546. Swap( dst[0][2], dst[2][0] );
  547. Swap( dst[0][3], dst[3][0] );
  548. Swap( dst[1][2], dst[2][1] );
  549. Swap( dst[1][3], dst[3][1] );
  550. Swap( dst[2][3], dst[3][2] );
  551. }
  552. else
  553. {
  554. dst[0][0] = src[0][0]; dst[0][1] = src[1][0]; dst[0][2] = src[2][0]; dst[0][3] = src[3][0];
  555. dst[1][0] = src[0][1]; dst[1][1] = src[1][1]; dst[1][2] = src[2][1]; dst[1][3] = src[3][1];
  556. dst[2][0] = src[0][2]; dst[2][1] = src[1][2]; dst[2][2] = src[2][2]; dst[2][3] = src[3][2];
  557. dst[3][0] = src[0][3]; dst[3][1] = src[1][3]; dst[3][2] = src[2][3]; dst[3][3] = src[3][3];
  558. }
  559. }
  560. //-----------------------------------------------------------------------------
  561. // Matrix copy
  562. //-----------------------------------------------------------------------------
  563. void MatrixCopy( const VMatrix& src, VMatrix& dst )
  564. {
  565. if (&src != &dst)
  566. {
  567. memcpy( dst.m, src.m, 16 * sizeof(float) );
  568. }
  569. }
  570. //-----------------------------------------------------------------------------
  571. // Matrix multiply
  572. //-----------------------------------------------------------------------------
  573. typedef float VMatrixRaw_t[4];
  574. void MatrixMultiply( const VMatrix& src1, const VMatrix& src2, VMatrix& dst )
  575. {
  576. // Make sure it works if src1 == dst or src2 == dst
  577. VMatrix tmp1, tmp2;
  578. const VMatrixRaw_t* s1 = (&src1 == &dst) ? tmp1.m : src1.m;
  579. const VMatrixRaw_t* s2 = (&src2 == &dst) ? tmp2.m : src2.m;
  580. if (&src1 == &dst)
  581. {
  582. MatrixCopy( src1, tmp1 );
  583. }
  584. if (&src2 == &dst)
  585. {
  586. MatrixCopy( src2, tmp2 );
  587. }
  588. dst[0][0] = s1[0][0] * s2[0][0] + s1[0][1] * s2[1][0] + s1[0][2] * s2[2][0] + s1[0][3] * s2[3][0];
  589. dst[0][1] = s1[0][0] * s2[0][1] + s1[0][1] * s2[1][1] + s1[0][2] * s2[2][1] + s1[0][3] * s2[3][1];
  590. dst[0][2] = s1[0][0] * s2[0][2] + s1[0][1] * s2[1][2] + s1[0][2] * s2[2][2] + s1[0][3] * s2[3][2];
  591. dst[0][3] = s1[0][0] * s2[0][3] + s1[0][1] * s2[1][3] + s1[0][2] * s2[2][3] + s1[0][3] * s2[3][3];
  592. dst[1][0] = s1[1][0] * s2[0][0] + s1[1][1] * s2[1][0] + s1[1][2] * s2[2][0] + s1[1][3] * s2[3][0];
  593. dst[1][1] = s1[1][0] * s2[0][1] + s1[1][1] * s2[1][1] + s1[1][2] * s2[2][1] + s1[1][3] * s2[3][1];
  594. dst[1][2] = s1[1][0] * s2[0][2] + s1[1][1] * s2[1][2] + s1[1][2] * s2[2][2] + s1[1][3] * s2[3][2];
  595. dst[1][3] = s1[1][0] * s2[0][3] + s1[1][1] * s2[1][3] + s1[1][2] * s2[2][3] + s1[1][3] * s2[3][3];
  596. dst[2][0] = s1[2][0] * s2[0][0] + s1[2][1] * s2[1][0] + s1[2][2] * s2[2][0] + s1[2][3] * s2[3][0];
  597. dst[2][1] = s1[2][0] * s2[0][1] + s1[2][1] * s2[1][1] + s1[2][2] * s2[2][1] + s1[2][3] * s2[3][1];
  598. dst[2][2] = s1[2][0] * s2[0][2] + s1[2][1] * s2[1][2] + s1[2][2] * s2[2][2] + s1[2][3] * s2[3][2];
  599. dst[2][3] = s1[2][0] * s2[0][3] + s1[2][1] * s2[1][3] + s1[2][2] * s2[2][3] + s1[2][3] * s2[3][3];
  600. dst[3][0] = s1[3][0] * s2[0][0] + s1[3][1] * s2[1][0] + s1[3][2] * s2[2][0] + s1[3][3] * s2[3][0];
  601. dst[3][1] = s1[3][0] * s2[0][1] + s1[3][1] * s2[1][1] + s1[3][2] * s2[2][1] + s1[3][3] * s2[3][1];
  602. dst[3][2] = s1[3][0] * s2[0][2] + s1[3][1] * s2[1][2] + s1[3][2] * s2[2][2] + s1[3][3] * s2[3][2];
  603. dst[3][3] = s1[3][0] * s2[0][3] + s1[3][1] * s2[1][3] + s1[3][2] * s2[2][3] + s1[3][3] * s2[3][3];
  604. }
  605. //-----------------------------------------------------------------------------
  606. // Matrix/vector multiply
  607. //-----------------------------------------------------------------------------
  608. void Vector4DMultiply( const VMatrix& src1, Vector4D const& src2, Vector4D& dst )
  609. {
  610. // Make sure it works if src2 == dst
  611. Vector4D tmp;
  612. Vector4D const&v = (&src2 == &dst) ? tmp : src2;
  613. if (&src2 == &dst)
  614. {
  615. Vector4DCopy( src2, tmp );
  616. }
  617. dst[0] = src1[0][0] * v[0] + src1[0][1] * v[1] + src1[0][2] * v[2] + src1[0][3] * v[3];
  618. dst[1] = src1[1][0] * v[0] + src1[1][1] * v[1] + src1[1][2] * v[2] + src1[1][3] * v[3];
  619. dst[2] = src1[2][0] * v[0] + src1[2][1] * v[1] + src1[2][2] * v[2] + src1[2][3] * v[3];
  620. dst[3] = src1[3][0] * v[0] + src1[3][1] * v[1] + src1[3][2] * v[2] + src1[3][3] * v[3];
  621. }
  622. //-----------------------------------------------------------------------------
  623. // Matrix/vector multiply
  624. //-----------------------------------------------------------------------------
  625. void Vector4DMultiplyPosition( const VMatrix& src1, Vector const& src2, Vector4D& dst )
  626. {
  627. // Make sure it works if src2 == dst
  628. Vector tmp;
  629. Vector const&v = ( &src2 == &dst.AsVector3D() ) ? static_cast<const Vector>(tmp) : src2;
  630. if (&src2 == &dst.AsVector3D())
  631. {
  632. VectorCopy( src2, tmp );
  633. }
  634. dst[0] = src1[0][0] * v[0] + src1[0][1] * v[1] + src1[0][2] * v[2] + src1[0][3];
  635. dst[1] = src1[1][0] * v[0] + src1[1][1] * v[1] + src1[1][2] * v[2] + src1[1][3];
  636. dst[2] = src1[2][0] * v[0] + src1[2][1] * v[1] + src1[2][2] * v[2] + src1[2][3];
  637. dst[3] = src1[3][0] * v[0] + src1[3][1] * v[1] + src1[3][2] * v[2] + src1[3][3];
  638. }
  639. //-----------------------------------------------------------------------------
  640. // Matrix/vector multiply
  641. //-----------------------------------------------------------------------------
  642. void Vector3DMultiply( const VMatrix &src1, const Vector &src2, Vector &dst )
  643. {
  644. // Make sure it works if src2 == dst
  645. Vector tmp;
  646. const Vector &v = (&src2 == &dst) ? static_cast<const Vector>(tmp) : src2;
  647. if( &src2 == &dst )
  648. {
  649. VectorCopy( src2, tmp );
  650. }
  651. dst[0] = src1[0][0] * v[0] + src1[0][1] * v[1] + src1[0][2] * v[2];
  652. dst[1] = src1[1][0] * v[0] + src1[1][1] * v[1] + src1[1][2] * v[2];
  653. dst[2] = src1[2][0] * v[0] + src1[2][1] * v[1] + src1[2][2] * v[2];
  654. }
  655. //-----------------------------------------------------------------------------
  656. // Vector3DMultiplyPositionProjective treats src2 as if it's a point
  657. // and does the perspective divide at the end
  658. //-----------------------------------------------------------------------------
  659. void Vector3DMultiplyPositionProjective( const VMatrix& src1, const Vector &src2, Vector& dst )
  660. {
  661. // Make sure it works if src2 == dst
  662. Vector tmp;
  663. const Vector &v = (&src2 == &dst) ? static_cast<const Vector>(tmp): src2;
  664. if( &src2 == &dst )
  665. {
  666. VectorCopy( src2, tmp );
  667. }
  668. float w = src1[3][0] * v[0] + src1[3][1] * v[1] + src1[3][2] * v[2] + src1[3][3];
  669. if ( w != 0.0f )
  670. {
  671. w = 1.0f / w;
  672. }
  673. dst[0] = src1[0][0] * v[0] + src1[0][1] * v[1] + src1[0][2] * v[2] + src1[0][3];
  674. dst[1] = src1[1][0] * v[0] + src1[1][1] * v[1] + src1[1][2] * v[2] + src1[1][3];
  675. dst[2] = src1[2][0] * v[0] + src1[2][1] * v[1] + src1[2][2] * v[2] + src1[2][3];
  676. dst *= w;
  677. }
  678. //-----------------------------------------------------------------------------
  679. // Vector3DMultiplyProjective treats src2 as if it's a direction
  680. // and does the perspective divide at the end
  681. //-----------------------------------------------------------------------------
  682. void Vector3DMultiplyProjective( const VMatrix& src1, const Vector &src2, Vector& dst )
  683. {
  684. // Make sure it works if src2 == dst
  685. Vector tmp;
  686. const Vector &v = (&src2 == &dst) ? static_cast<const Vector>(tmp) : src2;
  687. if( &src2 == &dst )
  688. {
  689. VectorCopy( src2, tmp );
  690. }
  691. float w;
  692. dst[0] = src1[0][0] * v[0] + src1[0][1] * v[1] + src1[0][2] * v[2];
  693. dst[1] = src1[1][0] * v[0] + src1[1][1] * v[1] + src1[1][2] * v[2];
  694. dst[2] = src1[2][0] * v[0] + src1[2][1] * v[1] + src1[2][2] * v[2];
  695. w = src1[3][0] * v[0] + src1[3][1] * v[1] + src1[3][2] * v[2];
  696. if (w != 0.0f)
  697. {
  698. dst /= w;
  699. }
  700. else
  701. {
  702. dst = vec3_origin;
  703. }
  704. }
  705. //-----------------------------------------------------------------------------
  706. // Multiplies the vector by the transpose of the matrix
  707. //-----------------------------------------------------------------------------
  708. void Vector4DMultiplyTranspose( const VMatrix& src1, Vector4D const& src2, Vector4D& dst )
  709. {
  710. // Make sure it works if src2 == dst
  711. bool srcEqualsDst = (&src2 == &dst);
  712. Vector4D tmp;
  713. Vector4D const&v = srcEqualsDst ? tmp : src2;
  714. if (srcEqualsDst)
  715. {
  716. Vector4DCopy( src2, tmp );
  717. }
  718. dst[0] = src1[0][0] * v[0] + src1[1][0] * v[1] + src1[2][0] * v[2] + src1[3][0] * v[3];
  719. dst[1] = src1[0][1] * v[0] + src1[1][1] * v[1] + src1[2][1] * v[2] + src1[3][1] * v[3];
  720. dst[2] = src1[0][2] * v[0] + src1[1][2] * v[1] + src1[2][2] * v[2] + src1[3][2] * v[3];
  721. dst[3] = src1[0][3] * v[0] + src1[1][3] * v[1] + src1[2][3] * v[2] + src1[3][3] * v[3];
  722. }
  723. //-----------------------------------------------------------------------------
  724. // Multiplies the vector by the transpose of the matrix
  725. //-----------------------------------------------------------------------------
  726. void Vector3DMultiplyTranspose( const VMatrix& src1, const Vector& src2, Vector& dst )
  727. {
  728. // Make sure it works if src2 == dst
  729. bool srcEqualsDst = (&src2 == &dst);
  730. Vector tmp;
  731. const Vector&v = srcEqualsDst ? static_cast<const Vector>(tmp) : src2;
  732. if (srcEqualsDst)
  733. {
  734. VectorCopy( src2, tmp );
  735. }
  736. dst[0] = src1[0][0] * v[0] + src1[1][0] * v[1] + src1[2][0] * v[2];
  737. dst[1] = src1[0][1] * v[0] + src1[1][1] * v[1] + src1[2][1] * v[2];
  738. dst[2] = src1[0][2] * v[0] + src1[1][2] * v[1] + src1[2][2] * v[2];
  739. }
  740. //-----------------------------------------------------------------------------
  741. // Transform a plane
  742. //-----------------------------------------------------------------------------
  743. void MatrixTransformPlane( const VMatrix &src, const cplane_t &inPlane, cplane_t &outPlane )
  744. {
  745. // What we want to do is the following:
  746. // 1) transform the normal into the new space.
  747. // 2) Determine a point on the old plane given by plane dist * plane normal
  748. // 3) Transform that point into the new space
  749. // 4) Plane dist = DotProduct( new normal, new point )
  750. // An optimized version, which works if the plane is orthogonal.
  751. // 1) Transform the normal into the new space
  752. // 2) Realize that transforming the old plane point into the new space
  753. // is given by [ d * n'x + Tx, d * n'y + Ty, d * n'z + Tz ]
  754. // where d = old plane dist, n' = transformed normal, Tn = translational component of transform
  755. // 3) Compute the new plane dist using the dot product of the normal result of #2
  756. // For a correct result, this should be an inverse-transpose matrix
  757. // but that only matters if there are nonuniform scale or skew factors in this matrix.
  758. Vector vTrans;
  759. Vector3DMultiply( src, inPlane.normal, outPlane.normal );
  760. outPlane.dist = inPlane.dist * DotProduct( outPlane.normal, outPlane.normal );
  761. outPlane.dist += DotProduct( outPlane.normal, src.GetTranslation(vTrans) );
  762. }
  763. #ifndef VECTOR_NO_SLOW_OPERATIONS
  764. VPlane VMatrix::operator*(const VPlane &thePlane) const
  765. {
  766. VPlane ret;
  767. TransformPlane( thePlane, ret );
  768. return ret;
  769. }
  770. #endif
  771. //-----------------------------------------------------------------------------
  772. // Builds a rotation matrix that rotates one direction vector into another
  773. //-----------------------------------------------------------------------------
  774. void MatrixBuildTranslation( VMatrix& dst, float x, float y, float z )
  775. {
  776. MatrixSetIdentity( dst );
  777. dst[0][3] = x;
  778. dst[1][3] = y;
  779. dst[2][3] = z;
  780. }
  781. void MatrixBuildTranslation( VMatrix& dst, const Vector &translation )
  782. {
  783. MatrixSetIdentity( dst );
  784. dst[0][3] = translation[0];
  785. dst[1][3] = translation[1];
  786. dst[2][3] = translation[2];
  787. }
  788. //-----------------------------------------------------------------------------
  789. // Purpose: Builds the matrix for a counterclockwise rotation about an arbitrary axis.
  790. //
  791. // | ax2 + (1 - ax2)cosQ axay(1 - cosQ) - azsinQ azax(1 - cosQ) + aysinQ |
  792. // Ra(Q) = | axay(1 - cosQ) + azsinQ ay2 + (1 - ay2)cosQ ayaz(1 - cosQ) - axsinQ |
  793. // | azax(1 - cosQ) - aysinQ ayaz(1 - cosQ) + axsinQ az2 + (1 - az2)cosQ |
  794. //
  795. // Input : mat -
  796. // vAxisOrRot -
  797. // angle -
  798. //-----------------------------------------------------------------------------
  799. void MatrixBuildRotationAboutAxis( VMatrix &dst, const Vector &vAxisOfRot, float angleDegrees )
  800. {
  801. MatrixBuildRotationAboutAxis( vAxisOfRot, angleDegrees, dst.As3x4() );
  802. dst[3][0] = 0;
  803. dst[3][1] = 0;
  804. dst[3][2] = 0;
  805. dst[3][3] = 1;
  806. }
  807. //-----------------------------------------------------------------------------
  808. // Builds a rotation matrix that rotates one direction vector into another
  809. //-----------------------------------------------------------------------------
  810. void MatrixBuildRotation( VMatrix &dst, const Vector& initialDirection, const Vector& finalDirection )
  811. {
  812. float angle = DotProduct( initialDirection, finalDirection );
  813. Assert( IsFinite(angle) );
  814. Vector axis;
  815. // No rotation required
  816. if (angle - 1.0 > -1e-3)
  817. {
  818. // parallel case
  819. MatrixSetIdentity(dst);
  820. return;
  821. }
  822. else if (angle + 1.0 < 1e-3)
  823. {
  824. // antiparallel case, pick any axis in the plane
  825. // perpendicular to the final direction. Choose the direction (x,y,z)
  826. // which has the minimum component of the final direction, use that
  827. // as an initial guess, then subtract out the component which is
  828. // parallel to the final direction
  829. int idx = 0;
  830. if (FloatMakePositive(finalDirection[1]) < FloatMakePositive(finalDirection[idx]))
  831. idx = 1;
  832. if (FloatMakePositive(finalDirection[2]) < FloatMakePositive(finalDirection[idx]))
  833. idx = 2;
  834. axis.Init( 0, 0, 0 );
  835. axis[idx] = 1.0f;
  836. VectorMA( axis, -DotProduct( axis, finalDirection ), finalDirection, axis );
  837. VectorNormalize(axis);
  838. angle = 180.0f;
  839. }
  840. else
  841. {
  842. CrossProduct( initialDirection, finalDirection, axis );
  843. VectorNormalize( axis );
  844. angle = acos(angle) * 180 / M_PI;
  845. }
  846. MatrixBuildRotationAboutAxis( dst, axis, angle );
  847. #ifdef _DEBUG
  848. Vector test;
  849. Vector3DMultiply( dst, initialDirection, test );
  850. test -= finalDirection;
  851. Assert( test.LengthSqr() < 1e-3 );
  852. #endif
  853. }
  854. //-----------------------------------------------------------------------------
  855. //-----------------------------------------------------------------------------
  856. void MatrixBuildRotateZ( VMatrix &dst, float angleDegrees )
  857. {
  858. float radians = angleDegrees * ( M_PI / 180.0f );
  859. float fSin = ( float )sin( radians );
  860. float fCos = ( float )cos( radians );
  861. dst[0][0] = fCos; dst[0][1] = -fSin; dst[0][2] = 0.0f; dst[0][3] = 0.0f;
  862. dst[1][0] = fSin; dst[1][1] = fCos; dst[1][2] = 0.0f; dst[1][3] = 0.0f;
  863. dst[2][0] = 0.0f; dst[2][1] = 0.0f; dst[2][2] = 1.0f; dst[2][3] = 0.0f;
  864. dst[3][0] = 0.0f; dst[3][1] = 0.0f; dst[3][2] = 0.0f; dst[3][3] = 1.0f;
  865. }
  866. // Builds a scale matrix
  867. void MatrixBuildScale( VMatrix &dst, float x, float y, float z )
  868. {
  869. dst[0][0] = x; dst[0][1] = 0.0f; dst[0][2] = 0.0f; dst[0][3] = 0.0f;
  870. dst[1][0] = 0.0f; dst[1][1] = y; dst[1][2] = 0.0f; dst[1][3] = 0.0f;
  871. dst[2][0] = 0.0f; dst[2][1] = 0.0f; dst[2][2] = z; dst[2][3] = 0.0f;
  872. dst[3][0] = 0.0f; dst[3][1] = 0.0f; dst[3][2] = 0.0f; dst[3][3] = 1.0f;
  873. }
  874. void MatrixBuildScale( VMatrix &dst, const Vector& scale )
  875. {
  876. MatrixBuildScale( dst, scale.x, scale.y, scale.z );
  877. }
  878. void MatrixBuildPerspective( VMatrix &dst, float fovX, float fovY, float zNear, float zFar )
  879. {
  880. // FIXME: collapse all of this into one matrix after we figure out what all should be in here.
  881. float width = 2 * zNear * tan( fovX * ( M_PI/180.0f ) * 0.5f );
  882. float height = 2 * zNear * tan( fovY * ( M_PI/180.0f ) * 0.5f );
  883. memset( dst.Base(), 0, sizeof( dst ) );
  884. dst[0][0] = 2.0F * zNear / width;
  885. dst[1][1] = 2.0F * zNear / height;
  886. dst[2][2] = -zFar / ( zNear - zFar );
  887. dst[3][2] = 1.0f;
  888. dst[2][3] = zNear * zFar / ( zNear - zFar );
  889. // negate X and Y so that X points right, and Y points up.
  890. VMatrix negateXY;
  891. negateXY.Identity();
  892. negateXY[0][0] = -1.0f;
  893. negateXY[1][1] = -1.0f;
  894. MatrixMultiply( negateXY, dst, dst );
  895. VMatrix addW;
  896. addW.Identity();
  897. addW[0][3] = 1.0f;
  898. addW[1][3] = 1.0f;
  899. addW[2][3] = 0.0f;
  900. MatrixMultiply( addW, dst, dst );
  901. VMatrix scaleHalf;
  902. scaleHalf.Identity();
  903. scaleHalf[0][0] = 0.5f;
  904. scaleHalf[1][1] = 0.5f;
  905. MatrixMultiply( scaleHalf, dst, dst );
  906. }
  907. static inline void CalculateAABBForNormalizedFrustum_Helper( float x, float y, float z, const VMatrix &volumeToWorld, Vector &mins, Vector &maxs )
  908. {
  909. Vector volumeSpacePos( x, y, z );
  910. // Make sure it's been clipped
  911. Assert( volumeSpacePos[0] >= -1e-3f );
  912. Assert( volumeSpacePos[0] - 1.0f <= 1e-3f );
  913. Assert( volumeSpacePos[1] >= -1e-3f );
  914. Assert( volumeSpacePos[1] - 1.0f <= 1e-3f );
  915. Assert( volumeSpacePos[2] >= -1e-3f );
  916. Assert( volumeSpacePos[2] - 1.0f <= 1e-3f );
  917. Vector worldPos;
  918. Vector3DMultiplyPositionProjective( volumeToWorld, volumeSpacePos, worldPos );
  919. AddPointToBounds( worldPos, mins, maxs );
  920. }
  921. //-----------------------------------------------------------------------------
  922. // Given an inverse projection matrix, take the extremes of the space in transformed into world space and
  923. // get a bounding box.
  924. //-----------------------------------------------------------------------------
  925. void CalculateAABBFromProjectionMatrixInverse( const VMatrix &volumeToWorld, Vector *pMins, Vector *pMaxs )
  926. {
  927. // FIXME: Could maybe do better than the compile with all of these multiplies by 0 and 1.
  928. ClearBounds( *pMins, *pMaxs );
  929. CalculateAABBForNormalizedFrustum_Helper( 0, 0, 0, volumeToWorld, *pMins, *pMaxs );
  930. CalculateAABBForNormalizedFrustum_Helper( 0, 0, 1, volumeToWorld, *pMins, *pMaxs );
  931. CalculateAABBForNormalizedFrustum_Helper( 0, 1, 0, volumeToWorld, *pMins, *pMaxs );
  932. CalculateAABBForNormalizedFrustum_Helper( 0, 1, 1, volumeToWorld, *pMins, *pMaxs );
  933. CalculateAABBForNormalizedFrustum_Helper( 1, 0, 0, volumeToWorld, *pMins, *pMaxs );
  934. CalculateAABBForNormalizedFrustum_Helper( 1, 0, 1, volumeToWorld, *pMins, *pMaxs );
  935. CalculateAABBForNormalizedFrustum_Helper( 1, 1, 0, volumeToWorld, *pMins, *pMaxs );
  936. CalculateAABBForNormalizedFrustum_Helper( 1, 1, 1, volumeToWorld, *pMins, *pMaxs );
  937. }
  938. void CalculateAABBFromProjectionMatrix( const VMatrix &worldToVolume, Vector *pMins, Vector *pMaxs )
  939. {
  940. VMatrix volumeToWorld;
  941. MatrixInverseGeneral( worldToVolume, volumeToWorld );
  942. CalculateAABBFromProjectionMatrixInverse( volumeToWorld, pMins, pMaxs );
  943. }
  944. //-----------------------------------------------------------------------------
  945. // Given an inverse projection matrix, take the extremes of the space in transformed into world space and
  946. // get a bounding sphere.
  947. //-----------------------------------------------------------------------------
  948. void CalculateSphereFromProjectionMatrixInverse( const VMatrix &volumeToWorld, Vector *pCenter, float *pflRadius )
  949. {
  950. // FIXME: Could maybe do better than the compile with all of these multiplies by 0 and 1.
  951. // Need 3 points: the endpoint of the line through the center of the near + far planes,
  952. // and one point on the far plane. From that, we can derive a point somewhere on the center line
  953. // which would produce the smallest bounding sphere.
  954. Vector vecCenterNear, vecCenterFar, vecNearEdge, vecFarEdge;
  955. Vector3DMultiplyPositionProjective( volumeToWorld, Vector( 0.5f, 0.5f, 0.0f ), vecCenterNear );
  956. Vector3DMultiplyPositionProjective( volumeToWorld, Vector( 0.5f, 0.5f, 1.0f ), vecCenterFar );
  957. Vector3DMultiplyPositionProjective( volumeToWorld, Vector( 0.0f, 0.0f, 0.0f ), vecNearEdge );
  958. Vector3DMultiplyPositionProjective( volumeToWorld, Vector( 0.0f, 0.0f, 1.0f ), vecFarEdge );
  959. // Let the distance between the near + far center points = l
  960. // Let the distance between the near center point + near edge point = h1
  961. // Let the distance between the far center point + far edge point = h2
  962. // Let the distance along the center line from the near point to the sphere center point = x
  963. // Then let the distance between the sphere center point + near edge point ==
  964. // the distance between the sphere center point + far edge point == r == radius of sphere
  965. // Then h1^2 + x^2 == r^2 == (l-x)^2 + h2^2
  966. // h1^x + x^2 = l^2 - 2 * l * x + x^2 + h2^2
  967. // 2 * l * x = l^2 + h2^2 - h1^2
  968. // x = (l^2 + h2^2 - h1^2) / (2 * l)
  969. // r = sqrt( hl^1 + x^2 )
  970. Vector vecDelta;
  971. VectorSubtract( vecCenterFar, vecCenterNear, vecDelta );
  972. float l = vecDelta.Length();
  973. float h1Sqr = vecCenterNear.DistToSqr( vecNearEdge );
  974. float h2Sqr = vecCenterFar.DistToSqr( vecFarEdge );
  975. float x = (l*l + h2Sqr - h1Sqr) / (2.0f * l);
  976. VectorMA( vecCenterNear, (x / l), vecDelta, *pCenter );
  977. *pflRadius = sqrt( h1Sqr + x*x );
  978. }
  979. //-----------------------------------------------------------------------------
  980. // Given a projection matrix, take the extremes of the space in transformed into world space and
  981. // get a bounding sphere.
  982. //-----------------------------------------------------------------------------
  983. void CalculateSphereFromProjectionMatrix( const VMatrix &worldToVolume, Vector *pCenter, float *pflRadius )
  984. {
  985. VMatrix volumeToWorld;
  986. MatrixInverseGeneral( worldToVolume, volumeToWorld );
  987. CalculateSphereFromProjectionMatrixInverse( volumeToWorld, pCenter, pflRadius );
  988. }
  989. static inline void FrustumPlanesFromMatrixHelper( const VMatrix &shadowToWorld, const Vector &p1, const Vector &p2, const Vector &p3, VPlane &plane )
  990. {
  991. Vector world1, world2, world3;
  992. Vector3DMultiplyPositionProjective( shadowToWorld, p1, world1 );
  993. Vector3DMultiplyPositionProjective( shadowToWorld, p2, world2 );
  994. Vector3DMultiplyPositionProjective( shadowToWorld, p3, world3 );
  995. Vector v1, v2;
  996. VectorSubtract( world2, world1, v1 );
  997. VectorSubtract( world3, world1, v2 );
  998. CrossProduct( v1, v2, plane.m_Normal );
  999. VectorNormalize( plane.m_Normal );
  1000. plane.m_Dist = DotProduct( plane.m_Normal, world1 );
  1001. }
  1002. void FrustumPlanesFromMatrix( const VMatrix &clipToWorld, Frustum_t &frustum )
  1003. {
  1004. VPlane planes[6];
  1005. FrustumPlanesFromMatrixHelper( clipToWorld,
  1006. Vector( 0.0f, 0.0f, 0.0f ), Vector( 1.0f, 0.0f, 0.0f ), Vector( 0.0f, 1.0f, 0.0f ), planes[FRUSTUM_NEARZ] );
  1007. FrustumPlanesFromMatrixHelper( clipToWorld,
  1008. Vector( 0.0f, 0.0f, 1.0f ), Vector( 0.0f, 1.0f, 1.0f ), Vector( 1.0f, 0.0f, 1.0f ), planes[FRUSTUM_FARZ] );
  1009. FrustumPlanesFromMatrixHelper( clipToWorld,
  1010. Vector( 1.0f, 0.0f, 0.0f ), Vector( 1.0f, 1.0f, 1.0f ), Vector( 1.0f, 1.0f, 0.0f ), planes[FRUSTUM_RIGHT] );
  1011. FrustumPlanesFromMatrixHelper( clipToWorld,
  1012. Vector( 0.0f, 0.0f, 0.0f ), Vector( 0.0f, 1.0f, 1.0f ), Vector( 0.0f, 0.0f, 1.0f ), planes[FRUSTUM_LEFT] );
  1013. FrustumPlanesFromMatrixHelper( clipToWorld,
  1014. Vector( 1.0f, 1.0f, 0.0f ), Vector( 1.0f, 1.0f, 1.0f ), Vector( 0.0f, 1.0f, 1.0f ), planes[FRUSTUM_TOP] );
  1015. FrustumPlanesFromMatrixHelper( clipToWorld,
  1016. Vector( 1.0f, 0.0f, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), Vector( 1.0f, 0.0f, 1.0f ), planes[FRUSTUM_BOTTOM] );
  1017. frustum.SetPlanes(planes);
  1018. }
  1019. // BEWARE: top/bottom are FLIPPED relative to D3DXMatrixOrthoOffCenterRH().
  1020. void MatrixBuildOrtho( VMatrix& dst, double left, double top, double right, double bottom, double zNear, double zFar )
  1021. {
  1022. // FIXME: This is being used incorrectly! Should read:
  1023. // D3DXMatrixOrthoOffCenterRH( &matrix, left, right, bottom, top, zNear, zFar );
  1024. // Which is certainly why we need these extra -1 scales in y. Bleah
  1025. // NOTE: The camera can be imagined as the following diagram:
  1026. // /z
  1027. // /
  1028. // /____ x Z is going into the screen
  1029. // |
  1030. // |
  1031. // |y
  1032. //
  1033. // (0,0,z) represents the upper-left corner of the screen.
  1034. // Our projection transform needs to transform from this space to a LH coordinate
  1035. // system that looks thusly:
  1036. //
  1037. // y| /z
  1038. // | /
  1039. // |/____ x Z is going into the screen
  1040. //
  1041. // Where x,y lies between -1 and 1, and z lies from 0 to 1
  1042. // This is because the viewport transformation from projection space to pixels
  1043. // introduces a -1 scale in the y coordinates
  1044. // D3DXMatrixOrthoOffCenterRH( &matrix, left, right, top, bottom, zNear, zFar );
  1045. dst.Init( 2.0f / ( right - left ), 0.0f, 0.0f, ( left + right ) / ( left - right ),
  1046. 0.0f, 2.0f / ( bottom - top ), 0.0f, ( bottom + top ) / ( top - bottom ),
  1047. 0.0f, 0.0f, 1.0f / ( zNear - zFar ), zNear / ( zNear - zFar ),
  1048. 0.0f, 0.0f, 0.0f, 1.0f );
  1049. }
  1050. void MatrixBuildPerspectiveX( VMatrix& dst, double flFovX, double flAspect, double flZNear, double flZFar )
  1051. {
  1052. float flWidth = 2.0f * flZNear * tanf( flFovX * M_PI / 360.0f );
  1053. float flHeight = flWidth / flAspect;
  1054. dst.Init( 2.0f * flZNear / flWidth, 0.0f, 0.0f, 0.0f,
  1055. 0.0f, 2.0f * flZNear/ flHeight, 0.0f, 0.0f,
  1056. 0.0f, 0.0f, flZFar / ( flZNear - flZFar ), flZNear * flZFar / ( flZNear - flZFar ),
  1057. 0.0f, 0.0f, -1.0f, 0.0f );
  1058. }
  1059. void MatrixBuildPerspectiveOffCenterX( VMatrix& dst, double flFovX, double flAspect, double flZNear, double flZFar, double bottom, double top, double left, double right )
  1060. {
  1061. float flWidth = 2.0f * flZNear * tanf( flFovX * M_PI / 360.0f );
  1062. float flHeight = flWidth / flAspect;
  1063. // bottom, top, left, right are 0..1 so convert to -<val>/2..<val>/2
  1064. float flLeft = -(flWidth/2.0f) * (1.0f - left) + left * (flWidth/2.0f);
  1065. float flRight = -(flWidth/2.0f) * (1.0f - right) + right * (flWidth/2.0f);
  1066. float flBottom = -(flHeight/2.0f) * (1.0f - bottom) + bottom * (flHeight/2.0f);
  1067. float flTop = -(flHeight/2.0f) * (1.0f - top) + top * (flHeight/2.0f);
  1068. dst.Init( (2.0f * flZNear) / (flRight-flLeft), 0.0f, (flLeft+flRight)/(flRight-flLeft), 0.0f,
  1069. 0.0f, 2.0f*flZNear/(flTop-flBottom), (flTop+flBottom)/(flTop-flBottom), 0.0f,
  1070. 0.0f, 0.0f, flZFar/(flZNear-flZFar), flZNear*flZFar/(flZNear-flZFar),
  1071. 0.0f, 0.0f, -1.0f, 0.0f );
  1072. }
  1073. void ExtractClipPlanesFromNonTransposedMatrix( const VMatrix &viewProjMatrix, VPlane *pPlanesOut, bool bD3DClippingRange )
  1074. {
  1075. // Left
  1076. Vector4D vPlane = MatrixGetRowAsVector4D( viewProjMatrix, 0 ) + MatrixGetRowAsVector4D( viewProjMatrix, 3 );
  1077. pPlanesOut[ FRUSTUM_LEFT ].Init( vPlane.AsVector3D(), -vPlane.w );
  1078. // Right
  1079. vPlane = -MatrixGetRowAsVector4D( viewProjMatrix, 0 ) + MatrixGetRowAsVector4D( viewProjMatrix, 3 );
  1080. pPlanesOut[ FRUSTUM_RIGHT ].Init( vPlane.AsVector3D(), -vPlane.w );
  1081. // Bottom
  1082. vPlane = MatrixGetRowAsVector4D( viewProjMatrix, 1 ) + MatrixGetRowAsVector4D( viewProjMatrix, 3 );
  1083. pPlanesOut[ FRUSTUM_BOTTOM ].Init( vPlane.AsVector3D(), -vPlane.w );
  1084. // Top
  1085. vPlane = -MatrixGetRowAsVector4D( viewProjMatrix, 1 ) + MatrixGetRowAsVector4D( viewProjMatrix, 3 );
  1086. pPlanesOut[ FRUSTUM_TOP ].Init( vPlane.AsVector3D(), -vPlane.w );
  1087. // Near
  1088. if ( bD3DClippingRange )
  1089. {
  1090. // [0,1] Z clipping range (D3D-style)
  1091. vPlane = MatrixGetRowAsVector4D( viewProjMatrix, 2 );
  1092. }
  1093. else
  1094. {
  1095. // [-1,1] Z clipping range (OpenGL-style)
  1096. vPlane = MatrixGetRowAsVector4D( viewProjMatrix, 2 ) + MatrixGetRowAsVector4D( viewProjMatrix, 3 );
  1097. }
  1098. pPlanesOut[ FRUSTUM_NEARZ ].Init( vPlane.AsVector3D(), -vPlane.w );
  1099. // Far
  1100. vPlane = -MatrixGetRowAsVector4D( viewProjMatrix, 2 ) + MatrixGetRowAsVector4D( viewProjMatrix, 3 );
  1101. pPlanesOut[ FRUSTUM_FARZ ].Init( vPlane.AsVector3D(), -vPlane.w );
  1102. for ( uint i = 0; i < FRUSTUM_NUMPLANES; ++i )
  1103. {
  1104. float flLen2 = pPlanesOut[i].m_Normal.x * pPlanesOut[i].m_Normal.x + pPlanesOut[i].m_Normal.y * pPlanesOut[i].m_Normal.y + pPlanesOut[i].m_Normal.z * pPlanesOut[i].m_Normal.z;
  1105. if ( flLen2 != 0.0f )
  1106. {
  1107. float flScale = 1.0f / sqrt( flLen2 );
  1108. pPlanesOut[i].m_Normal *= flScale;
  1109. pPlanesOut[i].m_Dist *= flScale;
  1110. }
  1111. }
  1112. }
  1113. #endif // !_STATIC_LINKED || _SHARED_LIB