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.

332 lines
6.1 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #ifndef NMATRIX_H
  8. #define NMATRIX_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include <assert.h>
  13. #include "nvector.h"
  14. #define NMatrixMN NMatrix<M,N>
  15. template<int M, int N>
  16. class NMatrix
  17. {
  18. public:
  19. NMatrixMN() {}
  20. static NMatrixMN SetupNMatrixNull(); // Return a matrix of all zeros.
  21. static NMatrixMN SetupNMatrixIdentity(); // Return an identity matrix.
  22. NMatrixMN const& operator=( NMatrixMN const &other );
  23. NMatrixMN operator+( NMatrixMN const &v ) const;
  24. NMatrixMN const& operator+=( NMatrixMN const &v );
  25. NMatrixMN operator-() const;
  26. NMatrixMN operator-( NMatrixMN const &v ) const;
  27. // Multiplies the column vector on the right-hand side.
  28. NVector<M> operator*( NVector<N> const &v ) const;
  29. // Can't get the compiler to work with a real MxN * NxR matrix multiply...
  30. NMatrix<M,M> operator*( NMatrix<N,M> const &b ) const;
  31. NMatrixMN operator*( float val ) const;
  32. bool InverseGeneral( NMatrixMN &mInverse ) const;
  33. NMatrix<N,M> Transpose() const;
  34. public:
  35. float m[M][N];
  36. };
  37. // Return the matrix generated by multiplying a column vector 'a' by row vector 'b'.
  38. template<int N>
  39. inline NMatrix<N,N> OuterProduct( NVectorN const &a, NVectorN const &b )
  40. {
  41. NMatrix<N,N> ret;
  42. for( int i=0; i < N; i++ )
  43. for( int j=0; j < N; j++ )
  44. ret.m[i][j] = a.v[i] * b.v[j];
  45. return ret;
  46. }
  47. // -------------------------------------------------------------------------------- //
  48. // NMatrix inlines.
  49. // -------------------------------------------------------------------------------- //
  50. template<int M, int N>
  51. inline NMatrixMN NMatrixMN::SetupNMatrixNull()
  52. {
  53. NMatrix ret;
  54. memset( ret.m, 0, sizeof(float)*M*N );
  55. return ret;
  56. }
  57. template<int M, int N>
  58. inline NMatrixMN NMatrixMN::SetupNMatrixIdentity()
  59. {
  60. assert( M == N ); // Identity matrices must be square.
  61. NMatrix ret;
  62. memset( ret.m, 0, sizeof(float)*M*N );
  63. for( int i=0; i < N; i++ )
  64. ret.m[i][i] = 1;
  65. return ret;
  66. }
  67. template<int M, int N>
  68. inline NMatrixMN const &NMatrixMN::operator=( NMatrixMN const &v )
  69. {
  70. memcpy( m, v.m, sizeof(float)*M*N );
  71. return *this;
  72. }
  73. template<int M, int N>
  74. inline NMatrixMN NMatrixMN::operator+( NMatrixMN const &v ) const
  75. {
  76. NMatrixMN ret;
  77. for( int i=0; i < M; i++ )
  78. for( int j=0; j < N; j++ )
  79. ret.m[i][j] = m[i][j] + v.m[i][j];
  80. return ret;
  81. }
  82. template<int M, int N>
  83. inline NMatrixMN const &NMatrixMN::operator+=( NMatrixMN const &v )
  84. {
  85. for( int i=0; i < M; i++ )
  86. for( int j=0; j < N; j++ )
  87. m[i][j] += v.m[i][j];
  88. return *this;
  89. }
  90. template<int M, int N>
  91. inline NMatrixMN NMatrixMN::operator-() const
  92. {
  93. NMatrixMN ret;
  94. for( int i=0; i < M*N; i++ )
  95. ((float*)ret.m)[i] = -((float*)m)[i];
  96. return ret;
  97. }
  98. template<int M, int N>
  99. inline NMatrixMN NMatrixMN::operator-( NMatrixMN const &v ) const
  100. {
  101. NMatrixMN ret;
  102. for( int i=0; i < M; i++ )
  103. for( int j=0; j < N; j++ )
  104. ret.m[i][j] = m[i][j] - v.m[i][j];
  105. return ret;
  106. }
  107. template<int M, int N>
  108. inline NVector<M> NMatrixMN::operator*( NVectorN const &v ) const
  109. {
  110. NVectorN ret;
  111. for( int i=0; i < M; i++ )
  112. {
  113. ret.v[i] = 0;
  114. for( int j=0; j < N; j++ )
  115. ret.v[i] += m[i][j] * v.v[j];
  116. }
  117. return ret;
  118. }
  119. template<int M, int N>
  120. inline NMatrix<M,M> NMatrixMN::operator*( NMatrix<N,M> const &b ) const
  121. {
  122. NMatrix<M,M> ret;
  123. for( int myRow=0; myRow < M; myRow++ )
  124. {
  125. for( int otherCol=0; otherCol < M; otherCol++ )
  126. {
  127. ret[myRow][otherCol] = 0;
  128. for( int i=0; i < N; i++ )
  129. ret[myRow][otherCol] += a.m[myRow][i] * b.m[i][otherCol];
  130. }
  131. }
  132. return ret;
  133. }
  134. template<int M, int N>
  135. inline NMatrixMN NMatrixMN::operator*( float val ) const
  136. {
  137. NMatrixMN ret;
  138. for( int i=0; i < N*M; i++ )
  139. ((float*)ret.m)[i] = ((float*)m)[i] * val;
  140. return ret;
  141. }
  142. template<int M, int N>
  143. bool NMatrixMN::InverseGeneral( NMatrixMN &mInverse ) const
  144. {
  145. int iRow, i, j, iTemp, iTest;
  146. float mul, fTest, fLargest;
  147. float mat[N][2*N];
  148. int rowMap[N], iLargest;
  149. float *pOut, *pRow, *pScaleRow;
  150. // Can only invert square matrices.
  151. if( M != N )
  152. {
  153. assert( !"Tried to invert a non-square matrix" );
  154. return false;
  155. }
  156. // How it's done.
  157. // AX = I
  158. // A = this
  159. // X = the matrix we're looking for
  160. // I = identity
  161. // Setup AI
  162. for(i=0; i < N; i++)
  163. {
  164. const float *pIn = m[i];
  165. pOut = mat[i];
  166. for(j=0; j < N; j++)
  167. {
  168. pOut[j] = pIn[j];
  169. }
  170. for(j=N; j < 2*N; j++)
  171. pOut[j] = 0;
  172. pOut[i+N] = 1.0f;
  173. rowMap[i] = i;
  174. }
  175. // Use row operations to get to reduced row-echelon form using these rules:
  176. // 1. Multiply or divide a row by a nonzero number.
  177. // 2. Add a multiple of one row to another.
  178. // 3. Interchange two rows.
  179. for(iRow=0; iRow < N; iRow++)
  180. {
  181. // Find the row with the largest element in this column.
  182. fLargest = 0.001f;
  183. iLargest = -1;
  184. for(iTest=iRow; iTest < N; iTest++)
  185. {
  186. fTest = (float)fabs(mat[rowMap[iTest]][iRow]);
  187. if(fTest > fLargest)
  188. {
  189. iLargest = iTest;
  190. fLargest = fTest;
  191. }
  192. }
  193. // They're all too small.. sorry.
  194. if(iLargest == -1)
  195. {
  196. return false;
  197. }
  198. // Swap the rows.
  199. iTemp = rowMap[iLargest];
  200. rowMap[iLargest] = rowMap[iRow];
  201. rowMap[iRow] = iTemp;
  202. pRow = mat[rowMap[iRow]];
  203. // Divide this row by the element.
  204. mul = 1.0f / pRow[iRow];
  205. for(j=0; j < 2*N; j++)
  206. pRow[j] *= mul;
  207. pRow[iRow] = 1.0f; // Preserve accuracy...
  208. // Eliminate this element from the other rows using operation 2.
  209. for(i=0; i < N; i++)
  210. {
  211. if(i == iRow)
  212. continue;
  213. pScaleRow = mat[rowMap[i]];
  214. // Multiply this row by -(iRow*the element).
  215. mul = -pScaleRow[iRow];
  216. for(j=0; j < 2*N; j++)
  217. {
  218. pScaleRow[j] += pRow[j] * mul;
  219. }
  220. pScaleRow[iRow] = 0.0f; // Preserve accuracy...
  221. }
  222. }
  223. // The inverse is on the right side of AX now (the identity is on the left).
  224. for(i=0; i < N; i++)
  225. {
  226. const float *pIn = mat[rowMap[i]] + N;
  227. pOut = mInverse.m[i];
  228. for(j=0; j < N; j++)
  229. {
  230. pOut[j] = pIn[j];
  231. }
  232. }
  233. return true;
  234. }
  235. template<int M, int N>
  236. inline NMatrix<N,M> NMatrixMN::Transpose() const
  237. {
  238. NMatrix<N,M> ret;
  239. for( int i=0; i < M; i++ )
  240. for( int j=0; j < N; j++ )
  241. ret.m[j][i] = m[i][j];
  242. return ret;
  243. }
  244. #endif // NMATRIX_H