MatX.h 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #ifndef __MATH_MATX_H__
  21. #define __MATH_MATX_H__
  22. /*
  23. ===============================================================================
  24. idMatX - arbitrary sized dense real matrix
  25. The matrix lives on 16 byte aligned and 16 byte padded memory.
  26. NOTE: due to the temporary memory pool idMatX cannot be used by multiple threads.
  27. ===============================================================================
  28. */
  29. #define MATX_MAX_TEMP 1024
  30. #define MATX_QUAD( x ) ( ( ( ( x ) + 3 ) & ~3 ) * sizeof( float ) )
  31. #define MATX_CLEAREND() int s = numRows * numColumns; while( s < ( ( s + 3 ) & ~3 ) ) { mat[s++] = 0.0f; }
  32. #define MATX_ALLOCA( n ) ( (float *) _alloca16( MATX_QUAD( n ) ) )
  33. #define MATX_ALLOCA_CACHE_LINES( n ) ( (float *) _alloca128( ( ( n ) * sizeof( float ) + CACHE_LINE_SIZE - 1 ) & ~ ( CACHE_LINE_SIZE - 1 ) ) )
  34. #define MATX_SIMD
  35. class idMatX {
  36. public:
  37. ID_INLINE idMatX();
  38. ID_INLINE idMatX( const idMatX & other );
  39. ID_INLINE explicit idMatX( int rows, int columns );
  40. ID_INLINE explicit idMatX( int rows, int columns, float *src );
  41. ID_INLINE ~idMatX();
  42. ID_INLINE void Set( int rows, int columns, const float *src );
  43. ID_INLINE void Set( const idMat3 &m1, const idMat3 &m2 );
  44. ID_INLINE void Set( const idMat3 &m1, const idMat3 &m2, const idMat3 &m3, const idMat3 &m4 );
  45. ID_INLINE const float * operator[]( int index ) const;
  46. ID_INLINE float * operator[]( int index );
  47. ID_INLINE idMatX & operator=( const idMatX &a );
  48. ID_INLINE idMatX operator*( const float a ) const;
  49. ID_INLINE idVecX operator*( const idVecX &vec ) const;
  50. ID_INLINE idMatX operator*( const idMatX &a ) const;
  51. ID_INLINE idMatX operator+( const idMatX &a ) const;
  52. ID_INLINE idMatX operator-( const idMatX &a ) const;
  53. ID_INLINE idMatX & operator*=( const float a );
  54. ID_INLINE idMatX & operator*=( const idMatX &a );
  55. ID_INLINE idMatX & operator+=( const idMatX &a );
  56. ID_INLINE idMatX & operator-=( const idMatX &a );
  57. friend ID_INLINE idMatX operator*( const float a, const idMatX &m );
  58. friend ID_INLINE idVecX operator*( const idVecX &vec, const idMatX &m );
  59. friend ID_INLINE idVecX &operator*=( idVecX &vec, const idMatX &m );
  60. ID_INLINE bool Compare( const idMatX &a ) const; // exact compare, no epsilon
  61. ID_INLINE bool Compare( const idMatX &a, const float epsilon ) const; // compare with epsilon
  62. ID_INLINE bool operator==( const idMatX &a ) const; // exact compare, no epsilon
  63. ID_INLINE bool operator!=( const idMatX &a ) const; // exact compare, no epsilon
  64. ID_INLINE void SetSize( int rows, int columns ); // set the number of rows/columns
  65. void ChangeSize( int rows, int columns, bool makeZero = false ); // change the size keeping data intact where possible
  66. ID_INLINE void ChangeNumRows( int rows ) { ChangeSize( rows, numColumns ); } // set the number of rows/columns
  67. int GetNumRows() const { return numRows; } // get the number of rows
  68. int GetNumColumns() const { return numColumns; } // get the number of columns
  69. ID_INLINE void SetData( int rows, int columns, float *data ); // set float array pointer
  70. ID_INLINE void SetDataCacheLines( int rows, int columns, float *data, bool clear );// set float array pointer
  71. ID_INLINE void Zero(); // clear matrix
  72. ID_INLINE void Zero( int rows, int columns ); // set size and clear matrix
  73. ID_INLINE void Identity(); // clear to identity matrix
  74. ID_INLINE void Identity( int rows, int columns ); // set size and clear to identity matrix
  75. ID_INLINE void Diag( const idVecX &v ); // create diagonal matrix from vector
  76. ID_INLINE void Random( int seed, float l = 0.0f, float u = 1.0f ); // fill matrix with random values
  77. ID_INLINE void Random( int rows, int columns, int seed, float l = 0.0f, float u = 1.0f );
  78. ID_INLINE void Negate(); // (*this) = - (*this)
  79. ID_INLINE void Clamp( float min, float max ); // clamp all values
  80. ID_INLINE idMatX & SwapRows( int r1, int r2 ); // swap rows
  81. ID_INLINE idMatX & SwapColumns( int r1, int r2 ); // swap columns
  82. ID_INLINE idMatX & SwapRowsColumns( int r1, int r2 ); // swap rows and columns
  83. idMatX & RemoveRow( int r ); // remove a row
  84. idMatX & RemoveColumn( int r ); // remove a column
  85. idMatX & RemoveRowColumn( int r ); // remove a row and column
  86. ID_INLINE void ClearUpperTriangle(); // clear the upper triangle
  87. ID_INLINE void ClearLowerTriangle(); // clear the lower triangle
  88. void CopyLowerToUpperTriangle(); // copy the lower triangle to the upper triangle
  89. ID_INLINE void SquareSubMatrix( const idMatX &m, int size ); // get square sub-matrix from 0,0 to size,size
  90. ID_INLINE float MaxDifference( const idMatX &m ) const; // return maximum element difference between this and m
  91. ID_INLINE bool IsSquare() const { return ( numRows == numColumns ); }
  92. ID_INLINE bool IsZero( const float epsilon = MATRIX_EPSILON ) const;
  93. ID_INLINE bool IsIdentity( const float epsilon = MATRIX_EPSILON ) const;
  94. ID_INLINE bool IsDiagonal( const float epsilon = MATRIX_EPSILON ) const;
  95. ID_INLINE bool IsTriDiagonal( const float epsilon = MATRIX_EPSILON ) const;
  96. ID_INLINE bool IsSymmetric( const float epsilon = MATRIX_EPSILON ) const;
  97. bool IsOrthogonal( const float epsilon = MATRIX_EPSILON ) const;
  98. bool IsOrthonormal( const float epsilon = MATRIX_EPSILON ) const;
  99. bool IsPMatrix( const float epsilon = MATRIX_EPSILON ) const;
  100. bool IsZMatrix( const float epsilon = MATRIX_EPSILON ) const;
  101. bool IsPositiveDefinite( const float epsilon = MATRIX_EPSILON ) const;
  102. bool IsSymmetricPositiveDefinite( const float epsilon = MATRIX_EPSILON ) const;
  103. bool IsPositiveSemiDefinite( const float epsilon = MATRIX_EPSILON ) const;
  104. bool IsSymmetricPositiveSemiDefinite( const float epsilon = MATRIX_EPSILON ) const;
  105. ID_INLINE float Trace() const; // returns product of diagonal elements
  106. ID_INLINE float Determinant() const; // returns determinant of matrix
  107. ID_INLINE idMatX Transpose() const; // returns transpose
  108. ID_INLINE idMatX & TransposeSelf(); // transposes the matrix itself
  109. ID_INLINE void Transpose( idMatX & dst ) const; // stores transpose in 'dst'
  110. ID_INLINE idMatX Inverse() const; // returns the inverse ( m * m.Inverse() = identity )
  111. ID_INLINE bool InverseSelf(); // returns false if determinant is zero
  112. ID_INLINE idMatX InverseFast() const; // returns the inverse ( m * m.Inverse() = identity )
  113. ID_INLINE bool InverseFastSelf(); // returns false if determinant is zero
  114. ID_INLINE void Inverse( idMatX & dst ) const; // stores the inverse in 'dst' ( m * m.Inverse() = identity )
  115. bool LowerTriangularInverse(); // in-place inversion, returns false if determinant is zero
  116. bool UpperTriangularInverse(); // in-place inversion, returns false if determinant is zero
  117. ID_INLINE void Subtract( const idMatX & a ); // (*this) -= a;
  118. ID_INLINE idVecX Multiply( const idVecX &vec ) const; // (*this) * vec
  119. ID_INLINE idVecX TransposeMultiply( const idVecX &vec ) const; // this->Transpose() * vec
  120. ID_INLINE idMatX Multiply( const idMatX &a ) const; // (*this) * a
  121. ID_INLINE idMatX TransposeMultiply( const idMatX &a ) const; // this->Transpose() * a
  122. ID_INLINE void Multiply( idVecX &dst, const idVecX &vec ) const; // dst = (*this) * vec
  123. ID_INLINE void MultiplyAdd( idVecX &dst, const idVecX &vec ) const; // dst += (*this) * vec
  124. ID_INLINE void MultiplySub( idVecX &dst, const idVecX &vec ) const; // dst -= (*this) * vec
  125. ID_INLINE void TransposeMultiply( idVecX &dst, const idVecX &vec ) const; // dst = this->Transpose() * vec
  126. ID_INLINE void TransposeMultiplyAdd( idVecX &dst, const idVecX &vec ) const; // dst += this->Transpose() * vec
  127. ID_INLINE void TransposeMultiplySub( idVecX &dst, const idVecX &vec ) const; // dst -= this->Transpose() * vec
  128. ID_INLINE void Multiply( idMatX &dst, const idMatX &a ) const; // dst = (*this) * a
  129. ID_INLINE void TransposeMultiply( idMatX &dst, const idMatX &a ) const; // dst = this->Transpose() * a
  130. ID_INLINE int GetDimension() const; // returns total number of values in matrix
  131. ID_INLINE const idVec6 & SubVec6( int row ) const; // interpret beginning of row as a const idVec6
  132. ID_INLINE idVec6 & SubVec6( int row ); // interpret beginning of row as an idVec6
  133. ID_INLINE const idVecX SubVecX( int row ) const; // interpret complete row as a const idVecX
  134. ID_INLINE idVecX SubVecX( int row ); // interpret complete row as an idVecX
  135. ID_INLINE const float * ToFloatPtr() const; // pointer to const matrix float array
  136. ID_INLINE float * ToFloatPtr(); // pointer to matrix float array
  137. const char * ToString( int precision = 2 ) const;
  138. void Update_RankOne( const idVecX &v, const idVecX &w, float alpha );
  139. void Update_RankOneSymmetric( const idVecX &v, float alpha );
  140. void Update_RowColumn( const idVecX &v, const idVecX &w, int r );
  141. void Update_RowColumnSymmetric( const idVecX &v, int r );
  142. void Update_Increment( const idVecX &v, const idVecX &w );
  143. void Update_IncrementSymmetric( const idVecX &v );
  144. void Update_Decrement( int r );
  145. bool Inverse_GaussJordan(); // invert in-place with Gauss-Jordan elimination
  146. bool Inverse_UpdateRankOne( const idVecX &v, const idVecX &w, float alpha );
  147. bool Inverse_UpdateRowColumn( const idVecX &v, const idVecX &w, int r );
  148. bool Inverse_UpdateIncrement( const idVecX &v, const idVecX &w );
  149. bool Inverse_UpdateDecrement( const idVecX &v, const idVecX &w, int r );
  150. void Inverse_Solve( idVecX &x, const idVecX &b ) const;
  151. bool LU_Factor( int *index, float *det = NULL ); // factor in-place: L * U
  152. bool LU_UpdateRankOne( const idVecX &v, const idVecX &w, float alpha, int *index );
  153. bool LU_UpdateRowColumn( const idVecX &v, const idVecX &w, int r, int *index );
  154. bool LU_UpdateIncrement( const idVecX &v, const idVecX &w, int *index );
  155. bool LU_UpdateDecrement( const idVecX &v, const idVecX &w, const idVecX &u, int r, int *index );
  156. void LU_Solve( idVecX &x, const idVecX &b, const int *index ) const;
  157. void LU_Inverse( idMatX &inv, const int *index ) const;
  158. void LU_UnpackFactors( idMatX &L, idMatX &U ) const;
  159. void LU_MultiplyFactors( idMatX &m, const int *index ) const;
  160. bool QR_Factor( idVecX &c, idVecX &d ); // factor in-place: Q * R
  161. bool QR_UpdateRankOne( idMatX &R, const idVecX &v, const idVecX &w, float alpha );
  162. bool QR_UpdateRowColumn( idMatX &R, const idVecX &v, const idVecX &w, int r );
  163. bool QR_UpdateIncrement( idMatX &R, const idVecX &v, const idVecX &w );
  164. bool QR_UpdateDecrement( idMatX &R, const idVecX &v, const idVecX &w, int r );
  165. void QR_Solve( idVecX &x, const idVecX &b, const idVecX &c, const idVecX &d ) const;
  166. void QR_Solve( idVecX &x, const idVecX &b, const idMatX &R ) const;
  167. void QR_Inverse( idMatX &inv, const idVecX &c, const idVecX &d ) const;
  168. void QR_UnpackFactors( idMatX &Q, idMatX &R, const idVecX &c, const idVecX &d ) const;
  169. void QR_MultiplyFactors( idMatX &m, const idVecX &c, const idVecX &d ) const;
  170. bool SVD_Factor( idVecX &w, idMatX &V ); // factor in-place: U * Diag(w) * V.Transpose()
  171. void SVD_Solve( idVecX &x, const idVecX &b, const idVecX &w, const idMatX &V ) const;
  172. void SVD_Inverse( idMatX &inv, const idVecX &w, const idMatX &V ) const;
  173. void SVD_MultiplyFactors( idMatX &m, const idVecX &w, const idMatX &V ) const;
  174. bool Cholesky_Factor(); // factor in-place: L * L.Transpose()
  175. bool Cholesky_UpdateRankOne( const idVecX &v, float alpha, int offset = 0 );
  176. bool Cholesky_UpdateRowColumn( const idVecX &v, int r );
  177. bool Cholesky_UpdateIncrement( const idVecX &v );
  178. bool Cholesky_UpdateDecrement( const idVecX &v, int r );
  179. void Cholesky_Solve( idVecX &x, const idVecX &b ) const;
  180. void Cholesky_Inverse( idMatX &inv ) const;
  181. void Cholesky_MultiplyFactors( idMatX &m ) const;
  182. bool LDLT_Factor(); // factor in-place: L * D * L.Transpose()
  183. bool LDLT_UpdateRankOne( const idVecX &v, float alpha, int offset = 0 );
  184. bool LDLT_UpdateRowColumn( const idVecX &v, int r );
  185. bool LDLT_UpdateIncrement( const idVecX &v );
  186. bool LDLT_UpdateDecrement( const idVecX &v, int r );
  187. void LDLT_Solve( idVecX &x, const idVecX &b ) const;
  188. void LDLT_Inverse( idMatX &inv ) const;
  189. void LDLT_UnpackFactors( idMatX &L, idMatX &D ) const;
  190. void LDLT_MultiplyFactors( idMatX &m ) const;
  191. void TriDiagonal_ClearTriangles();
  192. bool TriDiagonal_Solve( idVecX &x, const idVecX &b ) const;
  193. void TriDiagonal_Inverse( idMatX &inv ) const;
  194. bool Eigen_SolveSymmetricTriDiagonal( idVecX &eigenValues );
  195. bool Eigen_SolveSymmetric( idVecX &eigenValues );
  196. bool Eigen_Solve( idVecX &realEigenValues, idVecX &imaginaryEigenValues );
  197. void Eigen_SortIncreasing( idVecX &eigenValues );
  198. void Eigen_SortDecreasing( idVecX &eigenValues );
  199. static void Test();
  200. private:
  201. int numRows; // number of rows
  202. int numColumns; // number of columns
  203. int alloced; // floats allocated, if -1 then mat points to data set with SetData
  204. float * mat; // memory the matrix is stored
  205. static float temp[MATX_MAX_TEMP+4]; // used to store intermediate results
  206. static float * tempPtr; // pointer to 16 byte aligned temporary memory
  207. static int tempIndex; // index into memory pool, wraps around
  208. private:
  209. void SetTempSize( int rows, int columns );
  210. float DeterminantGeneric() const;
  211. bool InverseSelfGeneric();
  212. void QR_Rotate( idMatX &R, int i, float a, float b );
  213. float Pythag( float a, float b ) const;
  214. void SVD_BiDiag( idVecX &w, idVecX &rv1, float &anorm );
  215. void SVD_InitialWV( idVecX &w, idMatX &V, idVecX &rv1 );
  216. void HouseholderReduction( idVecX &diag, idVecX &subd );
  217. bool QL( idVecX &diag, idVecX &subd );
  218. void HessenbergReduction( idMatX &H );
  219. void ComplexDivision( float xr, float xi, float yr, float yi, float &cdivr, float &cdivi );
  220. bool HessenbergToRealSchur( idMatX &H, idVecX &realEigenValues, idVecX &imaginaryEigenValues );
  221. };
  222. /*
  223. ========================
  224. idMatX::idMatX
  225. ========================
  226. */
  227. ID_INLINE idMatX::idMatX() {
  228. numRows = numColumns = alloced = 0;
  229. mat = NULL;
  230. }
  231. /*
  232. ========================
  233. idMatX::~idMatX
  234. ========================
  235. */
  236. ID_INLINE idMatX::~idMatX() {
  237. // if not temp memory
  238. if ( mat != NULL && ( mat < idMatX::tempPtr || mat > idMatX::tempPtr + MATX_MAX_TEMP ) && alloced != -1 ) {
  239. Mem_Free16( mat );
  240. }
  241. }
  242. /*
  243. ========================
  244. idMatX::idMatX
  245. ========================
  246. */
  247. ID_INLINE idMatX::idMatX( int rows, int columns ) {
  248. numRows = numColumns = alloced = 0;
  249. mat = NULL;
  250. SetSize( rows, columns );
  251. }
  252. /*
  253. ========================
  254. idMatX::idMatX
  255. ========================
  256. */
  257. ID_INLINE idMatX::idMatX( const idMatX & other ) {
  258. numRows = numColumns = alloced = 0;
  259. mat = NULL;
  260. Set( other.GetNumRows(), other.GetNumColumns(), other.ToFloatPtr() );
  261. }
  262. /*
  263. ========================
  264. idMatX::idMatX
  265. ========================
  266. */
  267. ID_INLINE idMatX::idMatX( int rows, int columns, float *src ) {
  268. numRows = numColumns = alloced = 0;
  269. mat = NULL;
  270. SetData( rows, columns, src );
  271. }
  272. /*
  273. ========================
  274. idMatX::Set
  275. ========================
  276. */
  277. ID_INLINE void idMatX::Set( int rows, int columns, const float *src ) {
  278. SetSize( rows, columns );
  279. memcpy( this->mat, src, rows * columns * sizeof( float ) );
  280. }
  281. /*
  282. ========================
  283. idMatX::Set
  284. ========================
  285. */
  286. ID_INLINE void idMatX::Set( const idMat3 &m1, const idMat3 &m2 ) {
  287. SetSize( 3, 6 );
  288. for ( int i = 0; i < 3; i++ ) {
  289. for ( int j = 0; j < 3; j++ ) {
  290. mat[(i+0) * numColumns + (j+0)] = m1[i][j];
  291. mat[(i+0) * numColumns + (j+3)] = m2[i][j];
  292. }
  293. }
  294. }
  295. /*
  296. ========================
  297. idMatX::Set
  298. ========================
  299. */
  300. ID_INLINE void idMatX::Set( const idMat3 &m1, const idMat3 &m2, const idMat3 &m3, const idMat3 &m4 ) {
  301. SetSize( 6, 6 );
  302. for ( int i = 0; i < 3; i++ ) {
  303. for ( int j = 0; j < 3; j++ ) {
  304. mat[(i+0) * numColumns + (j+0)] = m1[i][j];
  305. mat[(i+0) * numColumns + (j+3)] = m2[i][j];
  306. mat[(i+3) * numColumns + (j+0)] = m3[i][j];
  307. mat[(i+3) * numColumns + (j+3)] = m4[i][j];
  308. }
  309. }
  310. }
  311. /*
  312. ========================
  313. idMatX::operator[]
  314. ========================
  315. */
  316. ID_INLINE const float *idMatX::operator[]( int index ) const {
  317. assert( ( index >= 0 ) && ( index < numRows ) );
  318. return mat + index * numColumns;
  319. }
  320. /*
  321. ========================
  322. idMatX::operator[]
  323. ========================
  324. */
  325. ID_INLINE float *idMatX::operator[]( int index ) {
  326. assert( ( index >= 0 ) && ( index < numRows ) );
  327. return mat + index * numColumns;
  328. }
  329. /*
  330. ========================
  331. idMatX::operator=
  332. ========================
  333. */
  334. ID_INLINE idMatX &idMatX::operator=( const idMatX &a ) {
  335. SetSize( a.numRows, a.numColumns );
  336. int s = a.numRows * a.numColumns;
  337. #if defined(ID_WIN_X86_SSE_INTRIN) && defined(MATX_SIMD)
  338. for ( int i = 0; i < s; i += 4 ) {
  339. _mm_store_ps( mat + i, _mm_load_ps( a.mat + i ) );
  340. }
  341. #else
  342. memcpy( mat, a.mat, s * sizeof( float ) );
  343. #endif
  344. idMatX::tempIndex = 0;
  345. return *this;
  346. }
  347. /*
  348. ========================
  349. idMatX::operator*
  350. ========================
  351. */
  352. ID_INLINE idMatX idMatX::operator*( const float a ) const {
  353. idMatX m;
  354. m.SetTempSize( numRows, numColumns );
  355. int s = numRows * numColumns;
  356. #if defined(ID_WIN_X86_SSE_INTRIN) && defined(MATX_SIMD)
  357. __m128 va = _mm_load1_ps( & a );
  358. for ( int i = 0; i < s; i += 4 ) {
  359. _mm_store_ps( m.mat + i, _mm_mul_ps( _mm_load_ps( mat + i ), va ) );
  360. }
  361. #else
  362. for ( int i = 0; i < s; i++ ) {
  363. m.mat[i] = mat[i] * a;
  364. }
  365. #endif
  366. return m;
  367. }
  368. /*
  369. ========================
  370. idMatX::operator*
  371. ========================
  372. */
  373. ID_INLINE idVecX idMatX::operator*( const idVecX &vec ) const {
  374. assert( numColumns == vec.GetSize() );
  375. idVecX dst;
  376. dst.SetTempSize( numRows );
  377. Multiply( dst, vec );
  378. return dst;
  379. }
  380. /*
  381. ========================
  382. idMatX::operator*
  383. ========================
  384. */
  385. ID_INLINE idMatX idMatX::operator*( const idMatX &a ) const {
  386. assert( numColumns == a.numRows );
  387. idMatX dst;
  388. dst.SetTempSize( numRows, a.numColumns );
  389. Multiply( dst, a );
  390. return dst;
  391. }
  392. /*
  393. ========================
  394. idMatX::operator+
  395. ========================
  396. */
  397. ID_INLINE idMatX idMatX::operator+( const idMatX &a ) const {
  398. idMatX m;
  399. assert( numRows == a.numRows && numColumns == a.numColumns );
  400. m.SetTempSize( numRows, numColumns );
  401. int s = numRows * numColumns;
  402. #if defined(ID_WIN_X86_SSE_INTRIN) && defined(MATX_SIMD)
  403. for ( int i = 0; i < s; i += 4 ) {
  404. _mm_store_ps( m.mat + i, _mm_add_ps( _mm_load_ps( mat + i ), _mm_load_ps( a.mat + i ) ) );
  405. }
  406. #else
  407. for ( int i = 0; i < s; i++ ) {
  408. m.mat[i] = mat[i] + a.mat[i];
  409. }
  410. #endif
  411. return m;
  412. }
  413. /*
  414. ========================
  415. idMatX::operator-
  416. ========================
  417. */
  418. ID_INLINE idMatX idMatX::operator-( const idMatX &a ) const {
  419. idMatX m;
  420. assert( numRows == a.numRows && numColumns == a.numColumns );
  421. m.SetTempSize( numRows, numColumns );
  422. int s = numRows * numColumns;
  423. #if defined(ID_WIN_X86_SSE_INTRIN) && defined(MATX_SIMD)
  424. for ( int i = 0; i < s; i += 4 ) {
  425. _mm_store_ps( m.mat + i, _mm_sub_ps( _mm_load_ps( mat + i ), _mm_load_ps( a.mat + i ) ) );
  426. }
  427. #else
  428. for ( int i = 0; i < s; i++ ) {
  429. m.mat[i] = mat[i] - a.mat[i];
  430. }
  431. #endif
  432. return m;
  433. }
  434. /*
  435. ========================
  436. idMatX::operator*=
  437. ========================
  438. */
  439. ID_INLINE idMatX &idMatX::operator*=( const float a ) {
  440. int s = numRows * numColumns;
  441. #if defined(ID_WIN_X86_SSE_INTRIN) && defined(MATX_SIMD)
  442. __m128 va = _mm_load1_ps( & a );
  443. for ( int i = 0; i < s; i += 4 ) {
  444. _mm_store_ps( mat + i, _mm_mul_ps( _mm_load_ps( mat + i ), va ) );
  445. }
  446. #else
  447. for ( int i = 0; i < s; i++ ) {
  448. mat[i] *= a;
  449. }
  450. #endif
  451. idMatX::tempIndex = 0;
  452. return *this;
  453. }
  454. /*
  455. ========================
  456. idMatX::operator*=
  457. ========================
  458. */
  459. ID_INLINE idMatX &idMatX::operator*=( const idMatX &a ) {
  460. *this = *this * a;
  461. idMatX::tempIndex = 0;
  462. return *this;
  463. }
  464. /*
  465. ========================
  466. idMatX::operator+=
  467. ========================
  468. */
  469. ID_INLINE idMatX &idMatX::operator+=( const idMatX &a ) {
  470. assert( numRows == a.numRows && numColumns == a.numColumns );
  471. int s = numRows * numColumns;
  472. #if defined(ID_WIN_X86_SSE_INTRIN) && defined(MATX_SIMD)
  473. for ( int i = 0; i < s; i += 4 ) {
  474. _mm_store_ps( mat + i, _mm_add_ps( _mm_load_ps( mat + i ), _mm_load_ps( a.mat + i ) ) );
  475. }
  476. #else
  477. for ( int i = 0; i < s; i++ ) {
  478. mat[i] += a.mat[i];
  479. }
  480. #endif
  481. idMatX::tempIndex = 0;
  482. return *this;
  483. }
  484. /*
  485. ========================
  486. idMatX::operator-=
  487. ========================
  488. */
  489. ID_INLINE idMatX &idMatX::operator-=( const idMatX &a ) {
  490. assert( numRows == a.numRows && numColumns == a.numColumns );
  491. int s = numRows * numColumns;
  492. #if defined(ID_WIN_X86_SSE_INTRIN) && defined(MATX_SIMD)
  493. for ( int i = 0; i < s; i += 4 ) {
  494. _mm_store_ps( mat + i, _mm_sub_ps( _mm_load_ps( mat + i ), _mm_load_ps( a.mat + i ) ) );
  495. }
  496. #else
  497. for ( int i = 0; i < s; i++ ) {
  498. mat[i] -= a.mat[i];
  499. }
  500. #endif
  501. idMatX::tempIndex = 0;
  502. return *this;
  503. }
  504. /*
  505. ========================
  506. operator*
  507. ========================
  508. */
  509. ID_INLINE idMatX operator*( const float a, idMatX const &m ) {
  510. return m * a;
  511. }
  512. /*
  513. ========================
  514. operator*
  515. ========================
  516. */
  517. ID_INLINE idVecX operator*( const idVecX &vec, const idMatX &m ) {
  518. return m * vec;
  519. }
  520. /*
  521. ========================
  522. operator*=
  523. ========================
  524. */
  525. ID_INLINE idVecX &operator*=( idVecX &vec, const idMatX &m ) {
  526. vec = m * vec;
  527. return vec;
  528. }
  529. /*
  530. ========================
  531. idMatX::Compare
  532. ========================
  533. */
  534. ID_INLINE bool idMatX::Compare( const idMatX &a ) const {
  535. assert( numRows == a.numRows && numColumns == a.numColumns );
  536. int s = numRows * numColumns;
  537. for ( int i = 0; i < s; i++ ) {
  538. if ( mat[i] != a.mat[i] ) {
  539. return false;
  540. }
  541. }
  542. return true;
  543. }
  544. /*
  545. ========================
  546. idMatX::Compare
  547. ========================
  548. */
  549. ID_INLINE bool idMatX::Compare( const idMatX &a, const float epsilon ) const {
  550. assert( numRows == a.numRows && numColumns == a.numColumns );
  551. int s = numRows * numColumns;
  552. for ( int i = 0; i < s; i++ ) {
  553. if ( idMath::Fabs( mat[i] - a.mat[i] ) > epsilon ) {
  554. return false;
  555. }
  556. }
  557. return true;
  558. }
  559. /*
  560. ========================
  561. idMatX::operator==
  562. ========================
  563. */
  564. ID_INLINE bool idMatX::operator==( const idMatX &a ) const {
  565. return Compare( a );
  566. }
  567. /*
  568. ========================
  569. idMatX::operator!=
  570. ========================
  571. */
  572. ID_INLINE bool idMatX::operator!=( const idMatX &a ) const {
  573. return !Compare( a );
  574. }
  575. /*
  576. ========================
  577. idMatX::SetSize
  578. ========================
  579. */
  580. ID_INLINE void idMatX::SetSize( int rows, int columns ) {
  581. if ( rows != numRows || columns != numColumns || mat == NULL ) {
  582. assert( mat < idMatX::tempPtr || mat > idMatX::tempPtr + MATX_MAX_TEMP );
  583. int alloc = ( rows * columns + 3 ) & ~3;
  584. if ( alloc > alloced && alloced != -1 ) {
  585. if ( mat != NULL ) {
  586. Mem_Free16( mat );
  587. }
  588. mat = (float *) Mem_Alloc16( alloc * sizeof( float ), TAG_MATH );
  589. alloced = alloc;
  590. }
  591. numRows = rows;
  592. numColumns = columns;
  593. MATX_CLEAREND();
  594. }
  595. }
  596. /*
  597. ========================
  598. idMatX::SetTempSize
  599. ========================
  600. */
  601. ID_INLINE void idMatX::SetTempSize( int rows, int columns ) {
  602. int newSize;
  603. newSize = ( rows * columns + 3 ) & ~3;
  604. assert( newSize < MATX_MAX_TEMP );
  605. if ( idMatX::tempIndex + newSize > MATX_MAX_TEMP ) {
  606. idMatX::tempIndex = 0;
  607. }
  608. mat = idMatX::tempPtr + idMatX::tempIndex;
  609. idMatX::tempIndex += newSize;
  610. alloced = newSize;
  611. numRows = rows;
  612. numColumns = columns;
  613. MATX_CLEAREND();
  614. }
  615. /*
  616. ========================
  617. idMatX::SetData
  618. ========================
  619. */
  620. ID_INLINE void idMatX::SetData( int rows, int columns, float *data ) {
  621. assert( mat < idMatX::tempPtr || mat > idMatX::tempPtr + MATX_MAX_TEMP );
  622. if ( mat != NULL && alloced != -1 ) {
  623. Mem_Free16( mat );
  624. }
  625. assert( ( ( (UINT_PTR) data ) & 15 ) == 0 ); // data must be 16 byte aligned
  626. mat = data;
  627. alloced = -1;
  628. numRows = rows;
  629. numColumns = columns;
  630. MATX_CLEAREND();
  631. }
  632. /*
  633. ========================
  634. idMatX::SetDataCacheLines
  635. ========================
  636. */
  637. ID_INLINE void idMatX::SetDataCacheLines( int rows, int columns, float *data, bool clear ) {
  638. if ( mat != NULL && alloced != -1 ) {
  639. Mem_Free( mat );
  640. }
  641. assert( ( ( (UINT_PTR) data ) & 127 ) == 0 ); // data must be 128 byte aligned
  642. mat = data;
  643. alloced = -1;
  644. numRows = rows;
  645. numColumns = columns;
  646. if ( clear ) {
  647. int size = numRows * numColumns * sizeof( float );
  648. for ( int i = 0; i < size; i += CACHE_LINE_SIZE ) {
  649. ZeroCacheLine( mat, i );
  650. }
  651. } else {
  652. MATX_CLEAREND();
  653. }
  654. }
  655. /*
  656. ========================
  657. idMatX::Zero
  658. ========================
  659. */
  660. ID_INLINE void idMatX::Zero() {
  661. int s = numRows * numColumns;
  662. #if defined(ID_WIN_X86_SSE_INTRIN) && defined(MATX_SIMD)
  663. for ( int i = 0; i < s; i += 4 ) {
  664. _mm_store_ps( mat + i, _mm_setzero_ps() );
  665. }
  666. #else
  667. s;
  668. memset( mat, 0, numRows * numColumns * sizeof( float ) );
  669. #endif
  670. }
  671. /*
  672. ========================
  673. idMatX::Zero
  674. ========================
  675. */
  676. ID_INLINE void idMatX::Zero( int rows, int columns ) {
  677. SetSize( rows, columns );
  678. Zero();
  679. }
  680. /*
  681. ========================
  682. idMatX::Identity
  683. ========================
  684. */
  685. ID_INLINE void idMatX::Identity() {
  686. assert( numRows == numColumns );
  687. Zero();
  688. for ( int i = 0; i < numRows; i++ ) {
  689. mat[i * numColumns + i] = 1.0f;
  690. }
  691. }
  692. /*
  693. ========================
  694. idMatX::Identity
  695. ========================
  696. */
  697. ID_INLINE void idMatX::Identity( int rows, int columns ) {
  698. assert( rows == columns );
  699. SetSize( rows, columns );
  700. idMatX::Identity();
  701. }
  702. /*
  703. ========================
  704. idMatX::Diag
  705. ========================
  706. */
  707. ID_INLINE void idMatX::Diag( const idVecX &v ) {
  708. Zero( v.GetSize(), v.GetSize() );
  709. for ( int i = 0; i < v.GetSize(); i++ ) {
  710. mat[i * numColumns + i] = v[i];
  711. }
  712. }
  713. /*
  714. ========================
  715. idMatX::Random
  716. ========================
  717. */
  718. ID_INLINE void idMatX::Random( int seed, float l, float u ) {
  719. idRandom rnd(seed);
  720. float c = u - l;
  721. int s = numRows * numColumns;
  722. for ( int i = 0; i < s; i++ ) {
  723. mat[i] = l + rnd.RandomFloat() * c;
  724. }
  725. }
  726. /*
  727. ========================
  728. idMatX::Random
  729. ========================
  730. */
  731. ID_INLINE void idMatX::Random( int rows, int columns, int seed, float l, float u ) {
  732. idRandom rnd(seed);
  733. SetSize( rows, columns );
  734. float c = u - l;
  735. int s = numRows * numColumns;
  736. for ( int i = 0; i < s; i++ ) {
  737. mat[i] = l + rnd.RandomFloat() * c;
  738. }
  739. }
  740. /*
  741. ========================
  742. idMatX::Negate
  743. ========================
  744. */
  745. ID_INLINE void idMatX::Negate() {
  746. int s = numRows * numColumns;
  747. #if defined(ID_WIN_X86_SSE_INTRIN) && defined(MATX_SIMD)
  748. ALIGN16( const unsigned int signBit[4] ) = { IEEE_FLT_SIGN_MASK, IEEE_FLT_SIGN_MASK, IEEE_FLT_SIGN_MASK, IEEE_FLT_SIGN_MASK };
  749. for ( int i = 0; i < s; i += 4 ) {
  750. _mm_store_ps( mat + i, _mm_xor_ps( _mm_load_ps( mat + i ), (__m128 &) signBit[0] ) );
  751. }
  752. #else
  753. for ( int i = 0; i < s; i++ ) {
  754. mat[i] = -mat[i];
  755. }
  756. #endif
  757. }
  758. /*
  759. ========================
  760. idMatX::Clamp
  761. ========================
  762. */
  763. ID_INLINE void idMatX::Clamp( float min, float max ) {
  764. int s = numRows * numColumns;
  765. for ( int i = 0; i < s; i++ ) {
  766. if ( mat[i] < min ) {
  767. mat[i] = min;
  768. } else if ( mat[i] > max ) {
  769. mat[i] = max;
  770. }
  771. }
  772. }
  773. /*
  774. ========================
  775. idMatX::SwapRows
  776. ========================
  777. */
  778. ID_INLINE idMatX &idMatX::SwapRows( int r1, int r2 ) {
  779. float * ptr1 = mat + r1 * numColumns;
  780. float * ptr2 = mat + r2 * numColumns;
  781. for ( int i = 0; i < numColumns; i++ ) {
  782. SwapValues( ptr1[i], ptr2[i] );
  783. }
  784. return *this;
  785. }
  786. /*
  787. ========================
  788. idMatX::SwapColumns
  789. ========================
  790. */
  791. ID_INLINE idMatX &idMatX::SwapColumns( int r1, int r2 ) {
  792. float * ptr = mat;
  793. for ( int i = 0; i < numRows; i++, ptr += numColumns ) {
  794. SwapValues( ptr[r1], ptr[r2] );
  795. }
  796. return *this;
  797. }
  798. /*
  799. ========================
  800. idMatX::SwapRowsColumns
  801. ========================
  802. */
  803. ID_INLINE idMatX &idMatX::SwapRowsColumns( int r1, int r2 ) {
  804. SwapRows( r1, r2 );
  805. SwapColumns( r1, r2 );
  806. return *this;
  807. }
  808. /*
  809. ========================
  810. idMatX::ClearUpperTriangle
  811. ========================
  812. */
  813. ID_INLINE void idMatX::ClearUpperTriangle() {
  814. assert( numRows == numColumns );
  815. for ( int i = numRows-2; i >= 0; i-- ) {
  816. memset( mat + i * numColumns + i + 1, 0, (numColumns - 1 - i) * sizeof(float) );
  817. }
  818. }
  819. /*
  820. ========================
  821. idMatX::ClearLowerTriangle
  822. ========================
  823. */
  824. ID_INLINE void idMatX::ClearLowerTriangle() {
  825. assert( numRows == numColumns );
  826. for ( int i = 1; i < numRows; i++ ) {
  827. memset( mat + i * numColumns, 0, i * sizeof(float) );
  828. }
  829. }
  830. /*
  831. ========================
  832. idMatX::SquareSubMatrix
  833. ========================
  834. */
  835. ID_INLINE void idMatX::SquareSubMatrix( const idMatX &m, int size ) {
  836. assert( size <= m.numRows && size <= m.numColumns );
  837. SetSize( size, size );
  838. for ( int i = 0; i < size; i++ ) {
  839. memcpy( mat + i * numColumns, m.mat + i * m.numColumns, size * sizeof( float ) );
  840. }
  841. }
  842. /*
  843. ========================
  844. idMatX::MaxDifference
  845. ========================
  846. */
  847. ID_INLINE float idMatX::MaxDifference( const idMatX &m ) const {
  848. assert( numRows == m.numRows && numColumns == m.numColumns );
  849. float maxDiff = -1.0f;
  850. for ( int i = 0; i < numRows; i++ ) {
  851. for ( int j = 0; j < numColumns; j++ ) {
  852. float diff = idMath::Fabs( mat[ i * numColumns + j ] - m[i][j] );
  853. if ( maxDiff < 0.0f || diff > maxDiff ) {
  854. maxDiff = diff;
  855. }
  856. }
  857. }
  858. return maxDiff;
  859. }
  860. /*
  861. ========================
  862. idMatX::IsZero
  863. ========================
  864. */
  865. ID_INLINE bool idMatX::IsZero( const float epsilon ) const {
  866. // returns true if (*this) == Zero
  867. for ( int i = 0; i < numRows; i++ ) {
  868. for ( int j = 0; j < numColumns; j++ ) {
  869. if ( idMath::Fabs( mat[i * numColumns + j] ) > epsilon ) {
  870. return false;
  871. }
  872. }
  873. }
  874. return true;
  875. }
  876. /*
  877. ========================
  878. idMatX::IsIdentity
  879. ========================
  880. */
  881. ID_INLINE bool idMatX::IsIdentity( const float epsilon ) const {
  882. // returns true if (*this) == Identity
  883. assert( numRows == numColumns );
  884. for ( int i = 0; i < numRows; i++ ) {
  885. for ( int j = 0; j < numColumns; j++ ) {
  886. if ( idMath::Fabs( mat[i * numColumns + j] - (float)( i == j ) ) > epsilon ) {
  887. return false;
  888. }
  889. }
  890. }
  891. return true;
  892. }
  893. /*
  894. ========================
  895. idMatX::IsDiagonal
  896. ========================
  897. */
  898. ID_INLINE bool idMatX::IsDiagonal( const float epsilon ) const {
  899. // returns true if all elements are zero except for the elements on the diagonal
  900. assert( numRows == numColumns );
  901. for ( int i = 0; i < numRows; i++ ) {
  902. for ( int j = 0; j < numColumns; j++ ) {
  903. if ( i != j && idMath::Fabs( mat[i * numColumns + j] ) > epsilon ) {
  904. return false;
  905. }
  906. }
  907. }
  908. return true;
  909. }
  910. /*
  911. ========================
  912. idMatX::IsTriDiagonal
  913. ========================
  914. */
  915. ID_INLINE bool idMatX::IsTriDiagonal( const float epsilon ) const {
  916. // returns true if all elements are zero except for the elements on the diagonal plus or minus one column
  917. if ( numRows != numColumns ) {
  918. return false;
  919. }
  920. for ( int i = 0; i < numRows-2; i++ ) {
  921. for ( int j = i+2; j < numColumns; j++ ) {
  922. if ( idMath::Fabs( (*this)[i][j] ) > epsilon ) {
  923. return false;
  924. }
  925. if ( idMath::Fabs( (*this)[j][i] ) > epsilon ) {
  926. return false;
  927. }
  928. }
  929. }
  930. return true;
  931. }
  932. /*
  933. ========================
  934. idMatX::IsSymmetric
  935. ========================
  936. */
  937. ID_INLINE bool idMatX::IsSymmetric( const float epsilon ) const {
  938. // (*this)[i][j] == (*this)[j][i]
  939. if ( numRows != numColumns ) {
  940. return false;
  941. }
  942. for ( int i = 0; i < numRows; i++ ) {
  943. for ( int j = 0; j < numColumns; j++ ) {
  944. if ( idMath::Fabs( mat[ i * numColumns + j ] - mat[ j * numColumns + i ] ) > epsilon ) {
  945. return false;
  946. }
  947. }
  948. }
  949. return true;
  950. }
  951. /*
  952. ========================
  953. idMatX::Trace
  954. ========================
  955. */
  956. ID_INLINE float idMatX::Trace() const {
  957. float trace = 0.0f;
  958. assert( numRows == numColumns );
  959. // sum of elements on the diagonal
  960. for ( int i = 0; i < numRows; i++ ) {
  961. trace += mat[i * numRows + i];
  962. }
  963. return trace;
  964. }
  965. /*
  966. ========================
  967. idMatX::Determinant
  968. ========================
  969. */
  970. ID_INLINE float idMatX::Determinant() const {
  971. assert( numRows == numColumns );
  972. switch( numRows ) {
  973. case 1: return mat[0];
  974. case 2: return reinterpret_cast<const idMat2 *>( mat )->Determinant();
  975. case 3: return reinterpret_cast<const idMat3 *>( mat )->Determinant();
  976. case 4: return reinterpret_cast<const idMat4 *>( mat )->Determinant();
  977. case 5: return reinterpret_cast<const idMat5 *>( mat )->Determinant();
  978. case 6: return reinterpret_cast<const idMat6 *>( mat )->Determinant();
  979. default: return DeterminantGeneric();
  980. }
  981. }
  982. /*
  983. ========================
  984. idMatX::Transpose
  985. ========================
  986. */
  987. ID_INLINE idMatX idMatX::Transpose() const {
  988. idMatX transpose;
  989. transpose.SetTempSize( numColumns, numRows );
  990. for ( int i = 0; i < numRows; i++ ) {
  991. for ( int j = 0; j < numColumns; j++ ) {
  992. transpose.mat[j * transpose.numColumns + i] = mat[i * numColumns + j];
  993. }
  994. }
  995. return transpose;
  996. }
  997. /*
  998. ========================
  999. idMatX::TransposeSelf
  1000. ========================
  1001. */
  1002. ID_INLINE idMatX &idMatX::TransposeSelf() {
  1003. *this = Transpose();
  1004. return *this;
  1005. }
  1006. /*
  1007. ========================
  1008. idMatX::Transpose
  1009. ========================
  1010. */
  1011. ID_INLINE void idMatX::Transpose( idMatX & dst ) const {
  1012. dst = Transpose();
  1013. }
  1014. /*
  1015. ========================
  1016. idMatX::Inverse
  1017. ========================
  1018. */
  1019. ID_INLINE idMatX idMatX::Inverse() const {
  1020. idMatX invMat;
  1021. invMat.SetTempSize( numRows, numColumns );
  1022. memcpy( invMat.mat, mat, numRows * numColumns * sizeof( float ) );
  1023. verify( invMat.InverseSelf() );
  1024. return invMat;
  1025. }
  1026. /*
  1027. ========================
  1028. idMatX::InverseSelf
  1029. ========================
  1030. */
  1031. ID_INLINE bool idMatX::InverseSelf() {
  1032. assert( numRows == numColumns );
  1033. switch( numRows ) {
  1034. case 1:
  1035. if ( idMath::Fabs( mat[0] ) < MATRIX_INVERSE_EPSILON ) {
  1036. return false;
  1037. }
  1038. mat[0] = 1.0f / mat[0];
  1039. return true;
  1040. case 2:
  1041. return reinterpret_cast<idMat2 *>(mat)->InverseSelf();
  1042. case 3:
  1043. return reinterpret_cast<idMat3 *>(mat)->InverseSelf();
  1044. case 4:
  1045. return reinterpret_cast<idMat4 *>(mat)->InverseSelf();
  1046. case 5:
  1047. return reinterpret_cast<idMat5 *>(mat)->InverseSelf();
  1048. case 6:
  1049. return reinterpret_cast<idMat6 *>(mat)->InverseSelf();
  1050. default:
  1051. return InverseSelfGeneric();
  1052. }
  1053. }
  1054. /*
  1055. ========================
  1056. idMatX::InverseFast
  1057. ========================
  1058. */
  1059. ID_INLINE idMatX idMatX::InverseFast() const {
  1060. idMatX invMat;
  1061. invMat.SetTempSize( numRows, numColumns );
  1062. memcpy( invMat.mat, mat, numRows * numColumns * sizeof( float ) );
  1063. verify( invMat.InverseFastSelf() );
  1064. return invMat;
  1065. }
  1066. /*
  1067. ========================
  1068. idMatX::InverseFastSelf
  1069. ========================
  1070. */
  1071. ID_INLINE bool idMatX::InverseFastSelf() {
  1072. assert( numRows == numColumns );
  1073. switch( numRows ) {
  1074. case 1:
  1075. if ( idMath::Fabs( mat[0] ) < MATRIX_INVERSE_EPSILON ) {
  1076. return false;
  1077. }
  1078. mat[0] = 1.0f / mat[0];
  1079. return true;
  1080. case 2:
  1081. return reinterpret_cast<idMat2 *>(mat)->InverseFastSelf();
  1082. case 3:
  1083. return reinterpret_cast<idMat3 *>(mat)->InverseFastSelf();
  1084. case 4:
  1085. return reinterpret_cast<idMat4 *>(mat)->InverseFastSelf();
  1086. case 5:
  1087. return reinterpret_cast<idMat5 *>(mat)->InverseFastSelf();
  1088. case 6:
  1089. return reinterpret_cast<idMat6 *>(mat)->InverseFastSelf();
  1090. default:
  1091. return InverseSelfGeneric();
  1092. }
  1093. }
  1094. /*
  1095. ========================
  1096. idMatX::Inverse
  1097. ========================
  1098. */
  1099. ID_INLINE void idMatX::Inverse( idMatX & dst ) const {
  1100. dst = InverseFast();
  1101. }
  1102. /*
  1103. ========================
  1104. idMatX::Subtract
  1105. ========================
  1106. */
  1107. ID_INLINE void idMatX::Subtract( const idMatX & a ) {
  1108. (*this) -= a;
  1109. }
  1110. /*
  1111. ========================
  1112. idMatX::Multiply
  1113. ========================
  1114. */
  1115. ID_INLINE idVecX idMatX::Multiply( const idVecX &vec ) const {
  1116. assert( numColumns == vec.GetSize() );
  1117. idVecX dst;
  1118. dst.SetTempSize( numRows );
  1119. Multiply( dst, vec );
  1120. return dst;
  1121. }
  1122. /*
  1123. ========================
  1124. idMatX::Multiply
  1125. ========================
  1126. */
  1127. ID_INLINE idMatX idMatX::Multiply( const idMatX &a ) const {
  1128. assert( numColumns == a.numRows );
  1129. idMatX dst;
  1130. dst.SetTempSize( numRows, a.numColumns );
  1131. Multiply( dst, a );
  1132. return dst;
  1133. }
  1134. /*
  1135. ========================
  1136. idMatX::TransposeMultiply
  1137. ========================
  1138. */
  1139. ID_INLINE idVecX idMatX::TransposeMultiply( const idVecX &vec ) const {
  1140. assert( numRows == vec.GetSize() );
  1141. idVecX dst;
  1142. dst.SetTempSize( numColumns );
  1143. TransposeMultiply( dst, vec );
  1144. return dst;
  1145. }
  1146. /*
  1147. ========================
  1148. idMatX::TransposeMultiply
  1149. ========================
  1150. */
  1151. ID_INLINE idMatX idMatX::TransposeMultiply( const idMatX &a ) const {
  1152. assert( numRows == a.numRows );
  1153. idMatX dst;
  1154. dst.SetTempSize( numColumns, a.numColumns );
  1155. TransposeMultiply( dst, a );
  1156. return dst;
  1157. }
  1158. /*
  1159. ========================
  1160. idMatX::Multiply
  1161. ========================
  1162. */
  1163. ID_INLINE void idMatX::Multiply( idVecX &dst, const idVecX &vec ) const {
  1164. dst.SetSize( numRows );
  1165. const float * mPtr = mat;
  1166. const float * vPtr = vec.ToFloatPtr();
  1167. float * dstPtr = dst.ToFloatPtr();
  1168. float * temp = (float *)_alloca16( numRows * sizeof( float ) );
  1169. for ( int i = 0; i < numRows; i++ ) {
  1170. float sum = mPtr[0] * vPtr[0];
  1171. for ( int j = 1; j < numColumns; j++ ) {
  1172. sum += mPtr[j] * vPtr[j];
  1173. }
  1174. temp[i] = sum;
  1175. mPtr += numColumns;
  1176. }
  1177. for ( int i = 0; i < numRows; i++ ) {
  1178. dstPtr[i] = temp[i];
  1179. }
  1180. }
  1181. /*
  1182. ========================
  1183. idMatX::MultiplyAdd
  1184. ========================
  1185. */
  1186. ID_INLINE void idMatX::MultiplyAdd( idVecX &dst, const idVecX &vec ) const {
  1187. assert( dst.GetSize() == numRows );
  1188. const float * mPtr = mat;
  1189. const float * vPtr = vec.ToFloatPtr();
  1190. float * dstPtr = dst.ToFloatPtr();
  1191. float * temp = (float *)_alloca16( numRows * sizeof( float ) );
  1192. for ( int i = 0; i < numRows; i++ ) {
  1193. float sum = mPtr[0] * vPtr[0];
  1194. for ( int j = 1; j < numColumns; j++ ) {
  1195. sum += mPtr[j] * vPtr[j];
  1196. }
  1197. temp[i] = dstPtr[i] + sum;
  1198. mPtr += numColumns;
  1199. }
  1200. for ( int i = 0; i < numRows; i++ ) {
  1201. dstPtr[i] = temp[i];
  1202. }
  1203. }
  1204. /*
  1205. ========================
  1206. idMatX::MultiplySub
  1207. ========================
  1208. */
  1209. ID_INLINE void idMatX::MultiplySub( idVecX &dst, const idVecX &vec ) const {
  1210. assert( dst.GetSize() == numRows );
  1211. const float * mPtr = mat;
  1212. const float * vPtr = vec.ToFloatPtr();
  1213. float * dstPtr = dst.ToFloatPtr();
  1214. float * temp = (float *)_alloca16( numRows * sizeof( float ) );
  1215. for ( int i = 0; i < numRows; i++ ) {
  1216. float sum = mPtr[0] * vPtr[0];
  1217. for ( int j = 1; j < numColumns; j++ ) {
  1218. sum += mPtr[j] * vPtr[j];
  1219. }
  1220. temp[i] = dstPtr[i] - sum;
  1221. mPtr += numColumns;
  1222. }
  1223. for ( int i = 0; i < numRows; i++ ) {
  1224. dstPtr[i] = temp[i];
  1225. }
  1226. }
  1227. /*
  1228. ========================
  1229. idMatX::TransposeMultiply
  1230. ========================
  1231. */
  1232. ID_INLINE void idMatX::TransposeMultiply( idVecX &dst, const idVecX &vec ) const {
  1233. dst.SetSize( numColumns );
  1234. const float * vPtr = vec.ToFloatPtr();
  1235. float * dstPtr = dst.ToFloatPtr();
  1236. float * temp = (float *)_alloca16( numColumns * sizeof( float ) );
  1237. for ( int i = 0; i < numColumns; i++ ) {
  1238. const float * mPtr = mat + i;
  1239. float sum = mPtr[0] * vPtr[0];
  1240. for ( int j = 1; j < numRows; j++ ) {
  1241. mPtr += numColumns;
  1242. sum += mPtr[0] * vPtr[j];
  1243. }
  1244. temp[i] = sum;
  1245. }
  1246. for ( int i = 0; i < numColumns; i++ ) {
  1247. dstPtr[i] = temp[i];
  1248. }
  1249. }
  1250. /*
  1251. ========================
  1252. idMatX::TransposeMultiplyAdd
  1253. ========================
  1254. */
  1255. ID_INLINE void idMatX::TransposeMultiplyAdd( idVecX &dst, const idVecX &vec ) const {
  1256. assert( dst.GetSize() == numColumns );
  1257. const float * vPtr = vec.ToFloatPtr();
  1258. float * dstPtr = dst.ToFloatPtr();
  1259. float * temp = (float *)_alloca16( numColumns * sizeof( float ) );
  1260. for ( int i = 0; i < numColumns; i++ ) {
  1261. const float * mPtr = mat + i;
  1262. float sum = mPtr[0] * vPtr[0];
  1263. for ( int j = 1; j < numRows; j++ ) {
  1264. mPtr += numColumns;
  1265. sum += mPtr[0] * vPtr[j];
  1266. }
  1267. temp[i] = dstPtr[i] + sum;
  1268. }
  1269. for ( int i = 0; i < numColumns; i++ ) {
  1270. dstPtr[i] = temp[i];
  1271. }
  1272. }
  1273. /*
  1274. ========================
  1275. idMatX::TransposeMultiplySub
  1276. ========================
  1277. */
  1278. ID_INLINE void idMatX::TransposeMultiplySub( idVecX &dst, const idVecX &vec ) const {
  1279. assert( dst.GetSize() == numColumns );
  1280. const float * vPtr = vec.ToFloatPtr();
  1281. float * dstPtr = dst.ToFloatPtr();
  1282. float * temp = (float *)_alloca16( numColumns * sizeof( float ) );
  1283. for ( int i = 0; i < numColumns; i++ ) {
  1284. const float * mPtr = mat + i;
  1285. float sum = mPtr[0] * vPtr[0];
  1286. for ( int j = 1; j < numRows; j++ ) {
  1287. mPtr += numColumns;
  1288. sum += mPtr[0] * vPtr[j];
  1289. }
  1290. temp[i] = dstPtr[i] - sum;
  1291. }
  1292. for ( int i = 0; i < numColumns; i++ ) {
  1293. dstPtr[i] = temp[i];
  1294. }
  1295. }
  1296. /*
  1297. ========================
  1298. idMatX::Multiply
  1299. ========================
  1300. */
  1301. ID_INLINE void idMatX::Multiply( idMatX &dst, const idMatX &a ) const {
  1302. assert( numColumns == a.numRows );
  1303. assert( &dst != &a && &dst != this );
  1304. dst.SetSize( numRows, a.numColumns );
  1305. float * dstPtr = dst.ToFloatPtr();
  1306. const float * m1Ptr = ToFloatPtr();
  1307. int k = numRows;
  1308. int l = a.GetNumColumns();
  1309. for ( int i = 0; i < k; i++ ) {
  1310. for ( int j = 0; j < l; j++ ) {
  1311. const float * m2Ptr = a.ToFloatPtr() + j;
  1312. float sum = m1Ptr[0] * m2Ptr[0];
  1313. for ( int n = 1; n < numColumns; n++ ) {
  1314. m2Ptr += l;
  1315. sum += m1Ptr[n] * m2Ptr[0];
  1316. }
  1317. *dstPtr++ = sum;
  1318. }
  1319. m1Ptr += numColumns;
  1320. }
  1321. }
  1322. /*
  1323. ========================
  1324. idMatX::TransposeMultiply
  1325. ========================
  1326. */
  1327. ID_INLINE void idMatX::TransposeMultiply( idMatX &dst, const idMatX &a ) const {
  1328. assert( numRows == a.numRows );
  1329. assert( &dst != &a && &dst != this );
  1330. dst.SetSize( numColumns, a.numColumns );
  1331. float * dstPtr = dst.ToFloatPtr();
  1332. int k = numColumns;
  1333. int l = a.numColumns;
  1334. for ( int i = 0; i < k; i++ ) {
  1335. for ( int j = 0; j < l; j++ ) {
  1336. const float * m1Ptr = ToFloatPtr() + i;
  1337. const float * m2Ptr = a.ToFloatPtr() + j;
  1338. float sum = m1Ptr[0] * m2Ptr[0];
  1339. for ( int n = 1; n < numRows; n++ ) {
  1340. m1Ptr += numColumns;
  1341. m2Ptr += a.numColumns;
  1342. sum += m1Ptr[0] * m2Ptr[0];
  1343. }
  1344. *dstPtr++ = sum;
  1345. }
  1346. }
  1347. }
  1348. /*
  1349. ========================
  1350. idMatX::GetDimension
  1351. ========================
  1352. */
  1353. ID_INLINE int idMatX::GetDimension() const {
  1354. return numRows * numColumns;
  1355. }
  1356. /*
  1357. ========================
  1358. idMatX::SubVec6
  1359. ========================
  1360. */
  1361. ID_INLINE const idVec6 &idMatX::SubVec6( int row ) const {
  1362. assert( numColumns >= 6 && row >= 0 && row < numRows );
  1363. return *reinterpret_cast<const idVec6 *>(mat + row * numColumns);
  1364. }
  1365. /*
  1366. ========================
  1367. idMatX::SubVec6
  1368. ========================
  1369. */
  1370. ID_INLINE idVec6 &idMatX::SubVec6( int row ) {
  1371. assert( numColumns >= 6 && row >= 0 && row < numRows );
  1372. return *reinterpret_cast<idVec6 *>(mat + row * numColumns);
  1373. }
  1374. /*
  1375. ========================
  1376. idMatX::SubVecX
  1377. ========================
  1378. */
  1379. ID_INLINE const idVecX idMatX::SubVecX( int row ) const {
  1380. idVecX v;
  1381. assert( row >= 0 && row < numRows );
  1382. v.SetData( numColumns, mat + row * numColumns );
  1383. return v;
  1384. }
  1385. /*
  1386. ========================
  1387. idMatX::SubVecX
  1388. ========================
  1389. */
  1390. ID_INLINE idVecX idMatX::SubVecX( int row ) {
  1391. idVecX v;
  1392. assert( row >= 0 && row < numRows );
  1393. v.SetData( numColumns, mat + row * numColumns );
  1394. return v;
  1395. }
  1396. /*
  1397. ========================
  1398. idMatX::ToFloatPtr
  1399. ========================
  1400. */
  1401. ID_INLINE const float *idMatX::ToFloatPtr() const {
  1402. return mat;
  1403. }
  1404. /*
  1405. ========================
  1406. idMatX::ToFloatPtr
  1407. ========================
  1408. */
  1409. ID_INLINE float *idMatX::ToFloatPtr() {
  1410. return mat;
  1411. }
  1412. #endif // !__MATH_MATRIXX_H__