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.

1293 lines
41 KiB

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