matrix4.h 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905
  1. // Copyright (C) 2002-2012 Nikolaus Gebhardt
  2. // This file is part of the "Irrlicht Engine".
  3. // For conditions of distribution and use, see copyright notice in irrlicht.h
  4. #pragma once
  5. #include <cstring> // memset, memcpy
  6. #include "irrMath.h"
  7. #include "vector3d.h"
  8. #include "vector2d.h"
  9. #include "plane3d.h"
  10. #include "aabbox3d.h"
  11. #include "rect.h"
  12. #include <cassert>
  13. namespace irr
  14. {
  15. namespace core
  16. {
  17. //! 4x4 matrix. Mostly used as transformation matrix for 3d calculations.
  18. /** Conventions: Matrices are considered to be in row-major order.
  19. * Multiplication of a matrix A with a row vector v is the premultiplication vA.
  20. * Translations are thus in the 4th row.
  21. * The matrix product AB yields a matrix C such that vC = (vB)A:
  22. * B is applied first, then A.
  23. */
  24. template <class T>
  25. class CMatrix4
  26. {
  27. public:
  28. //! Constructor Flags
  29. enum eConstructor
  30. {
  31. EM4CONST_NOTHING = 0,
  32. EM4CONST_COPY,
  33. EM4CONST_IDENTITY,
  34. EM4CONST_TRANSPOSED,
  35. EM4CONST_INVERSE,
  36. EM4CONST_INVERSE_TRANSPOSED
  37. };
  38. //! Default constructor
  39. /** \param constructor Choose the initialization style */
  40. CMatrix4(eConstructor constructor = EM4CONST_IDENTITY);
  41. //! Constructor with value initialization
  42. constexpr CMatrix4(const T &r0c0, const T &r0c1, const T &r0c2, const T &r0c3,
  43. const T &r1c0, const T &r1c1, const T &r1c2, const T &r1c3,
  44. const T &r2c0, const T &r2c1, const T &r2c2, const T &r2c3,
  45. const T &r3c0, const T &r3c1, const T &r3c2, const T &r3c3)
  46. {
  47. M[0] = r0c0;
  48. M[1] = r0c1;
  49. M[2] = r0c2;
  50. M[3] = r0c3;
  51. M[4] = r1c0;
  52. M[5] = r1c1;
  53. M[6] = r1c2;
  54. M[7] = r1c3;
  55. M[8] = r2c0;
  56. M[9] = r2c1;
  57. M[10] = r2c2;
  58. M[11] = r2c3;
  59. M[12] = r3c0;
  60. M[13] = r3c1;
  61. M[14] = r3c2;
  62. M[15] = r3c3;
  63. }
  64. //! Copy constructor
  65. /** \param other Other matrix to copy from
  66. \param constructor Choose the initialization style */
  67. CMatrix4(const CMatrix4<T> &other, eConstructor constructor = EM4CONST_COPY);
  68. //! Simple operator for directly accessing every element of the matrix.
  69. T &operator()(const s32 row, const s32 col)
  70. {
  71. return M[row * 4 + col];
  72. }
  73. //! Simple operator for directly accessing every element of the matrix.
  74. const T &operator()(const s32 row, const s32 col) const { return M[row * 4 + col]; }
  75. //! Simple operator for linearly accessing every element of the matrix.
  76. T &operator[](u32 index)
  77. {
  78. return M[index];
  79. }
  80. //! Simple operator for linearly accessing every element of the matrix.
  81. const T &operator[](u32 index) const { return M[index]; }
  82. //! Sets this matrix equal to the other matrix.
  83. CMatrix4<T> &operator=(const CMatrix4<T> &other) = default;
  84. //! Sets all elements of this matrix to the value.
  85. inline CMatrix4<T> &operator=(const T &scalar);
  86. //! Returns pointer to internal array
  87. const T *pointer() const { return M; }
  88. T *pointer()
  89. {
  90. return M;
  91. }
  92. //! Returns true if other matrix is equal to this matrix.
  93. constexpr bool operator==(const CMatrix4<T> &other) const
  94. {
  95. for (s32 i = 0; i < 16; ++i)
  96. if (M[i] != other.M[i])
  97. return false;
  98. return true;
  99. }
  100. //! Returns true if other matrix is not equal to this matrix.
  101. constexpr bool operator!=(const CMatrix4<T> &other) const
  102. {
  103. return !(*this == other);
  104. }
  105. //! Add another matrix.
  106. CMatrix4<T> operator+(const CMatrix4<T> &other) const;
  107. //! Add another matrix.
  108. CMatrix4<T> &operator+=(const CMatrix4<T> &other);
  109. //! Subtract another matrix.
  110. CMatrix4<T> operator-(const CMatrix4<T> &other) const;
  111. //! Subtract another matrix.
  112. CMatrix4<T> &operator-=(const CMatrix4<T> &other);
  113. //! set this matrix to the product of two matrices
  114. /** Calculate b*a */
  115. inline CMatrix4<T> &setbyproduct(const CMatrix4<T> &other_a, const CMatrix4<T> &other_b);
  116. //! Set this matrix to the product of two matrices
  117. /** Calculate b*a, no optimization used,
  118. use it if you know you never have an identity matrix */
  119. CMatrix4<T> &setbyproduct_nocheck(const CMatrix4<T> &other_a, const CMatrix4<T> &other_b);
  120. //! Multiply by another matrix.
  121. /** Calculate other*this */
  122. CMatrix4<T> operator*(const CMatrix4<T> &other) const;
  123. //! Multiply by another matrix.
  124. /** Like calling: (*this) = (*this) * other
  125. */
  126. CMatrix4<T> &operator*=(const CMatrix4<T> &other);
  127. //! Multiply by scalar.
  128. CMatrix4<T> operator*(const T &scalar) const;
  129. //! Multiply by scalar.
  130. CMatrix4<T> &operator*=(const T &scalar);
  131. //! Set matrix to identity.
  132. inline CMatrix4<T> &makeIdentity();
  133. //! Returns true if the matrix is the identity matrix
  134. inline bool isIdentity() const;
  135. //! Set the translation of the current matrix. Will erase any previous values.
  136. CMatrix4<T> &setTranslation(const vector3d<T> &translation);
  137. //! Gets the current translation
  138. vector3d<T> getTranslation() const;
  139. //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
  140. //! NOTE: Rotation order is ZYX. This means that vectors are
  141. //! first rotated around the X, then the Y, and finally the Z axis.
  142. //! NOTE: The rotation is done as per the right-hand rule.
  143. //! See test_irr_matrix4.cpp if you're still unsure about the conventions used here.
  144. inline CMatrix4<T> &setRotationRadians(const vector3d<T> &rotation);
  145. //! Same as `setRotationRadians`, but uses degrees.
  146. CMatrix4<T> &setRotationDegrees(const vector3d<T> &rotation);
  147. //! Get the rotation, as set by setRotation() when you already know the scale used to create the matrix
  148. /**
  149. NOTE: No scale value can be 0 or the result is undefined.
  150. NOTE: It does not necessarily return the *same* Euler angles as those set by setRotationDegrees(),
  151. but the rotation will be equivalent, i.e. will have the same result when used to rotate a vector or node.
  152. NOTE: It will (usually) give wrong results when further transformations have been added in the matrix (like shear).
  153. WARNING: There have been troubles with this function over the years and we may still have missed some corner cases.
  154. It's generally safer to keep the rotation and scale you used to create the matrix around and work with those.
  155. */
  156. vector3d<T> getRotationRadians(const vector3d<T> &scale) const;
  157. //! Returns the rotation, as set by setRotation().
  158. /** NOTE: You will have the same end-rotation as used in setRotation, but it might not use the same axis values.
  159. NOTE: This only works correctly for TRS matrix products where S is a positive, component-wise scaling (see setScale).
  160. NOTE: It does not necessarily return the *same* Euler angles as those set by setRotationDegrees(),
  161. but the rotation will be equivalent, i.e. will have the same result when used to rotate a vector or node.
  162. */
  163. vector3d<T> getRotationRadians() const;
  164. //! Same as getRotationRadians, but returns degrees.
  165. vector3d<T> getRotationDegrees() const;
  166. //! Make a rotation matrix from angle and axis, assuming left handed rotation.
  167. /** The 4th row and column are unmodified. */
  168. inline CMatrix4<T> &setRotationAxisRadians(const T &angle, const vector3d<T> &axis);
  169. //! Set Scale
  170. CMatrix4<T> &setScale(const vector3d<T> &scale);
  171. //! Set Scale
  172. CMatrix4<T> &setScale(const T scale) { return setScale(vector3d<T>(scale, scale, scale)); }
  173. //! Get Scale
  174. vector3d<T> getScale() const;
  175. //! Translate a vector by the inverse of the translation part of this matrix.
  176. void inverseTranslateVect(vector3df &vect) const;
  177. //! Scale a vector, then rotate by the inverse of the rotation part of this matrix.
  178. [[nodiscard]] vector3d<T> scaleThenInvRotVect(const vector3d<T> &vect) const;
  179. //! Rotate and scale a vector. Applies both rotation & scale part of the matrix.
  180. [[nodiscard]] vector3d<T> rotateAndScaleVect(const vector3d<T> &vect) const;
  181. //! Transforms the vector by this matrix
  182. /** This operation is performed as if the vector was 4d with the 4th component = 1 */
  183. [[nodiscard]] vector3d<T> transformVect(const vector3d<T> &v) const;
  184. //! Transforms the vector by this matrix
  185. /** This operation is performed as if the vector was 4d with the 4th component = 1 */
  186. void transformVect(vector3d<T> &vect) const {
  187. const vector3d<T> &v = vect;
  188. vect = transformVect(v);
  189. }
  190. //! Transforms input vector by this matrix and stores result in output vector
  191. /** This operation is performed as if the vector was 4d with the 4th component = 1 */
  192. void transformVect(vector3d<T> &out, const vector3d<T> &in) const {
  193. out = transformVect(in);
  194. }
  195. //! An alternate transform vector method, writing into an array of 4 floats
  196. /** This operation is performed as if the vector was 4d with the 4th component =1.
  197. NOTE: out[3] will be written to (4th vector component)*/
  198. void transformVect(T *out, const vector3df &in) const;
  199. //! An alternate transform vector method, reading from and writing to an array of 3 floats
  200. /** This operation is performed as if the vector was 4d with the 4th component =1
  201. NOTE: out[3] will be written to (4th vector component)*/
  202. void transformVec3(T *out, const T *in) const;
  203. //! An alternate transform vector method, reading from and writing to an array of 4 floats
  204. void transformVec4(T *out, const T *in) const;
  205. //! Translate a vector by the translation part of this matrix.
  206. /** This operation is performed as if the vector was 4d with the 4th component =1 */
  207. void translateVect(vector3df &vect) const;
  208. //! Transforms a plane by this matrix
  209. void transformPlane(plane3d<f32> &plane) const;
  210. //! Transforms a plane by this matrix
  211. void transformPlane(const plane3d<f32> &in, plane3d<f32> &out) const;
  212. //! Transforms a axis aligned bounding box
  213. void transformBoxEx(aabbox3d<f32> &box) const;
  214. //! Multiplies this matrix by a 1x4 matrix
  215. void multiplyWith1x4Matrix(T *matrix) const;
  216. //! Calculates inverse of matrix. Slow.
  217. /** \return Returns false if there is no inverse matrix.*/
  218. bool makeInverse();
  219. //! Inverts a primitive matrix which only contains a translation and a rotation
  220. /** \param out: where result matrix is written to. */
  221. bool getInversePrimitive(CMatrix4<T> &out) const;
  222. //! Gets the inverse matrix of this one
  223. /** \param out: where result matrix is written to.
  224. \return Returns false if there is no inverse matrix. */
  225. bool getInverse(CMatrix4<T> &out) const;
  226. //! Builds a right-handed perspective projection matrix based on a field of view
  227. //\param zClipFromZero: Clipping of z can be projected from 0 to w when true (D3D style) and from -w to w when false (OGL style).
  228. CMatrix4<T> &buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero = true);
  229. //! Builds a left-handed perspective projection matrix based on a field of view
  230. CMatrix4<T> &buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero = true);
  231. //! Builds a left-handed perspective projection matrix based on a field of view, with far plane at infinity
  232. CMatrix4<T> &buildProjectionMatrixPerspectiveFovInfinityLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon = 0);
  233. //! Builds a right-handed perspective projection matrix.
  234. CMatrix4<T> &buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero = true);
  235. //! Builds a left-handed perspective projection matrix.
  236. CMatrix4<T> &buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero = true);
  237. //! Builds a left-handed orthogonal projection matrix.
  238. //\param zClipFromZero: Clipping of z can be projected from 0 to 1 when true (D3D style) and from -1 to 1 when false (OGL style).
  239. CMatrix4<T> &buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero = true);
  240. //! Builds a right-handed orthogonal projection matrix.
  241. CMatrix4<T> &buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero = true);
  242. //! Builds a left-handed look-at matrix.
  243. CMatrix4<T> &buildCameraLookAtMatrixLH(
  244. const vector3df &position,
  245. const vector3df &target,
  246. const vector3df &upVector);
  247. //! Builds a right-handed look-at matrix.
  248. CMatrix4<T> &buildCameraLookAtMatrixRH(
  249. const vector3df &position,
  250. const vector3df &target,
  251. const vector3df &upVector);
  252. //! Builds a matrix that flattens geometry into a plane.
  253. /** \param light: light source
  254. \param plane: plane into which the geometry if flattened into
  255. \param point: value between 0 and 1, describing the light source.
  256. If this is 1, it is a point light, if it is 0, it is a directional light. */
  257. CMatrix4<T> &buildShadowMatrix(const vector3df &light, plane3df plane, f32 point = 1.0f);
  258. //! Builds a matrix which transforms a normalized Device Coordinate to Device Coordinates.
  259. /** Used to scale <-1,-1><1,1> to viewport, for example from <-1,-1> <1,1> to the viewport <0,0><0,640> */
  260. CMatrix4<T> &buildNDCToDCMatrix(const rect<s32> &area, f32 zScale);
  261. //! Creates a new matrix as interpolated matrix from two other ones.
  262. /** \param b: other matrix to interpolate with
  263. \param time: Must be a value between 0 and 1. */
  264. CMatrix4<T> interpolate(const CMatrix4<T> &b, f32 time) const;
  265. //! Gets transposed matrix
  266. CMatrix4<T> getTransposed() const;
  267. //! Gets transposed matrix
  268. inline void getTransposed(CMatrix4<T> &dest) const;
  269. //! Builds a matrix that rotates from one vector to another
  270. /** \param from: vector to rotate from
  271. \param to: vector to rotate to
  272. */
  273. CMatrix4<T> &buildRotateFromTo(const vector3df &from, const vector3df &to);
  274. //! Builds a combined matrix which translates to a center before rotation and translates from origin afterwards
  275. /** \param center Position to rotate around
  276. \param translate Translation applied after the rotation
  277. */
  278. void setRotationCenter(const vector3df &center, const vector3df &translate);
  279. //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis
  280. /** \param camPos: viewer position in world coo
  281. \param center: object position in world-coo and rotation pivot
  282. \param translation: object final translation from center
  283. \param axis: axis to rotate about
  284. \param from: source vector to rotate from
  285. */
  286. void buildAxisAlignedBillboard(const vector3df &camPos,
  287. const vector3df &center,
  288. const vector3df &translation,
  289. const vector3df &axis,
  290. const vector3df &from);
  291. /*
  292. construct 2D Texture transformations
  293. rotate about center, scale, and transform.
  294. */
  295. //! Set to a texture transformation matrix with the given parameters.
  296. CMatrix4<T> &buildTextureTransform(f32 rotateRad,
  297. const vector2df &rotatecenter,
  298. const vector2df &translate,
  299. const vector2df &scale);
  300. //! Set texture transformation rotation
  301. /** Rotate about z axis, recenter at (0.5,0.5).
  302. Doesn't clear other elements than those affected
  303. \param radAngle Angle in radians
  304. \return Altered matrix */
  305. CMatrix4<T> &setTextureRotationCenter(f32 radAngle);
  306. //! Set texture transformation translation
  307. /** Doesn't clear other elements than those affected.
  308. \param x Offset on x axis
  309. \param y Offset on y axis
  310. \return Altered matrix */
  311. CMatrix4<T> &setTextureTranslate(f32 x, f32 y);
  312. //! Get texture transformation translation
  313. /** \param x returns offset on x axis
  314. \param y returns offset on y axis */
  315. void getTextureTranslate(f32 &x, f32 &y) const;
  316. //! Set texture transformation translation, using a transposed representation
  317. /** Doesn't clear other elements than those affected.
  318. \param x Offset on x axis
  319. \param y Offset on y axis
  320. \return Altered matrix */
  321. CMatrix4<T> &setTextureTranslateTransposed(f32 x, f32 y);
  322. //! Set texture transformation scale
  323. /** Doesn't clear other elements than those affected.
  324. \param sx Scale factor on x axis
  325. \param sy Scale factor on y axis
  326. \return Altered matrix. */
  327. CMatrix4<T> &setTextureScale(f32 sx, f32 sy);
  328. //! Get texture transformation scale
  329. /** \param sx Returns x axis scale factor
  330. \param sy Returns y axis scale factor */
  331. void getTextureScale(f32 &sx, f32 &sy) const;
  332. //! Set texture transformation scale, and recenter at (0.5,0.5)
  333. /** Doesn't clear other elements than those affected.
  334. \param sx Scale factor on x axis
  335. \param sy Scale factor on y axis
  336. \return Altered matrix. */
  337. CMatrix4<T> &setTextureScaleCenter(f32 sx, f32 sy);
  338. //! Sets all matrix data members at once
  339. CMatrix4<T> &setM(const T *data);
  340. //! Compare two matrices using the equal method
  341. bool equals(const CMatrix4<T> &other, const T tolerance = (T)ROUNDING_ERROR_f64) const;
  342. private:
  343. template <bool degrees>
  344. vector3d<T> getRotation(const vector3d<T> &scale) const;
  345. //! Matrix data, stored in row-major order
  346. T M[16];
  347. };
  348. // Default constructor
  349. template <class T>
  350. inline CMatrix4<T>::CMatrix4(eConstructor constructor)
  351. {
  352. switch (constructor) {
  353. case EM4CONST_NOTHING:
  354. case EM4CONST_COPY:
  355. break;
  356. case EM4CONST_IDENTITY:
  357. case EM4CONST_INVERSE:
  358. default:
  359. makeIdentity();
  360. break;
  361. }
  362. }
  363. // Copy constructor
  364. template <class T>
  365. inline CMatrix4<T>::CMatrix4(const CMatrix4<T> &other, eConstructor constructor)
  366. {
  367. switch (constructor) {
  368. case EM4CONST_IDENTITY:
  369. makeIdentity();
  370. break;
  371. case EM4CONST_NOTHING:
  372. break;
  373. case EM4CONST_COPY:
  374. *this = other;
  375. break;
  376. case EM4CONST_TRANSPOSED:
  377. other.getTransposed(*this);
  378. break;
  379. case EM4CONST_INVERSE:
  380. if (!other.getInverse(*this))
  381. memset(M, 0, 16 * sizeof(T));
  382. break;
  383. case EM4CONST_INVERSE_TRANSPOSED:
  384. if (!other.getInverse(*this))
  385. memset(M, 0, 16 * sizeof(T));
  386. else
  387. *this = getTransposed();
  388. break;
  389. }
  390. }
  391. //! Add another matrix.
  392. template <class T>
  393. inline CMatrix4<T> CMatrix4<T>::operator+(const CMatrix4<T> &other) const
  394. {
  395. CMatrix4<T> temp(EM4CONST_NOTHING);
  396. temp[0] = M[0] + other[0];
  397. temp[1] = M[1] + other[1];
  398. temp[2] = M[2] + other[2];
  399. temp[3] = M[3] + other[3];
  400. temp[4] = M[4] + other[4];
  401. temp[5] = M[5] + other[5];
  402. temp[6] = M[6] + other[6];
  403. temp[7] = M[7] + other[7];
  404. temp[8] = M[8] + other[8];
  405. temp[9] = M[9] + other[9];
  406. temp[10] = M[10] + other[10];
  407. temp[11] = M[11] + other[11];
  408. temp[12] = M[12] + other[12];
  409. temp[13] = M[13] + other[13];
  410. temp[14] = M[14] + other[14];
  411. temp[15] = M[15] + other[15];
  412. return temp;
  413. }
  414. //! Add another matrix.
  415. template <class T>
  416. inline CMatrix4<T> &CMatrix4<T>::operator+=(const CMatrix4<T> &other)
  417. {
  418. M[0] += other[0];
  419. M[1] += other[1];
  420. M[2] += other[2];
  421. M[3] += other[3];
  422. M[4] += other[4];
  423. M[5] += other[5];
  424. M[6] += other[6];
  425. M[7] += other[7];
  426. M[8] += other[8];
  427. M[9] += other[9];
  428. M[10] += other[10];
  429. M[11] += other[11];
  430. M[12] += other[12];
  431. M[13] += other[13];
  432. M[14] += other[14];
  433. M[15] += other[15];
  434. return *this;
  435. }
  436. //! Subtract another matrix.
  437. template <class T>
  438. inline CMatrix4<T> CMatrix4<T>::operator-(const CMatrix4<T> &other) const
  439. {
  440. CMatrix4<T> temp(EM4CONST_NOTHING);
  441. temp[0] = M[0] - other[0];
  442. temp[1] = M[1] - other[1];
  443. temp[2] = M[2] - other[2];
  444. temp[3] = M[3] - other[3];
  445. temp[4] = M[4] - other[4];
  446. temp[5] = M[5] - other[5];
  447. temp[6] = M[6] - other[6];
  448. temp[7] = M[7] - other[7];
  449. temp[8] = M[8] - other[8];
  450. temp[9] = M[9] - other[9];
  451. temp[10] = M[10] - other[10];
  452. temp[11] = M[11] - other[11];
  453. temp[12] = M[12] - other[12];
  454. temp[13] = M[13] - other[13];
  455. temp[14] = M[14] - other[14];
  456. temp[15] = M[15] - other[15];
  457. return temp;
  458. }
  459. //! Subtract another matrix.
  460. template <class T>
  461. inline CMatrix4<T> &CMatrix4<T>::operator-=(const CMatrix4<T> &other)
  462. {
  463. M[0] -= other[0];
  464. M[1] -= other[1];
  465. M[2] -= other[2];
  466. M[3] -= other[3];
  467. M[4] -= other[4];
  468. M[5] -= other[5];
  469. M[6] -= other[6];
  470. M[7] -= other[7];
  471. M[8] -= other[8];
  472. M[9] -= other[9];
  473. M[10] -= other[10];
  474. M[11] -= other[11];
  475. M[12] -= other[12];
  476. M[13] -= other[13];
  477. M[14] -= other[14];
  478. M[15] -= other[15];
  479. return *this;
  480. }
  481. //! Multiply by scalar.
  482. template <class T>
  483. inline CMatrix4<T> CMatrix4<T>::operator*(const T &scalar) const
  484. {
  485. CMatrix4<T> temp(EM4CONST_NOTHING);
  486. temp[0] = M[0] * scalar;
  487. temp[1] = M[1] * scalar;
  488. temp[2] = M[2] * scalar;
  489. temp[3] = M[3] * scalar;
  490. temp[4] = M[4] * scalar;
  491. temp[5] = M[5] * scalar;
  492. temp[6] = M[6] * scalar;
  493. temp[7] = M[7] * scalar;
  494. temp[8] = M[8] * scalar;
  495. temp[9] = M[9] * scalar;
  496. temp[10] = M[10] * scalar;
  497. temp[11] = M[11] * scalar;
  498. temp[12] = M[12] * scalar;
  499. temp[13] = M[13] * scalar;
  500. temp[14] = M[14] * scalar;
  501. temp[15] = M[15] * scalar;
  502. return temp;
  503. }
  504. //! Multiply by scalar.
  505. template <class T>
  506. inline CMatrix4<T> &CMatrix4<T>::operator*=(const T &scalar)
  507. {
  508. M[0] *= scalar;
  509. M[1] *= scalar;
  510. M[2] *= scalar;
  511. M[3] *= scalar;
  512. M[4] *= scalar;
  513. M[5] *= scalar;
  514. M[6] *= scalar;
  515. M[7] *= scalar;
  516. M[8] *= scalar;
  517. M[9] *= scalar;
  518. M[10] *= scalar;
  519. M[11] *= scalar;
  520. M[12] *= scalar;
  521. M[13] *= scalar;
  522. M[14] *= scalar;
  523. M[15] *= scalar;
  524. return *this;
  525. }
  526. //! Multiply by another matrix.
  527. template <class T>
  528. inline CMatrix4<T> &CMatrix4<T>::operator*=(const CMatrix4<T> &other)
  529. {
  530. CMatrix4<T> temp(*this);
  531. return setbyproduct_nocheck(temp, other);
  532. }
  533. //! multiply by another matrix
  534. // set this matrix to the product of two other matrices
  535. // goal is to reduce stack use and copy
  536. template <class T>
  537. inline CMatrix4<T> &CMatrix4<T>::setbyproduct_nocheck(const CMatrix4<T> &other_a, const CMatrix4<T> &other_b)
  538. {
  539. const T *m1 = other_a.M;
  540. const T *m2 = other_b.M;
  541. M[0] = m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3];
  542. M[1] = m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3];
  543. M[2] = m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3];
  544. M[3] = m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3];
  545. M[4] = m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7];
  546. M[5] = m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7];
  547. M[6] = m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7];
  548. M[7] = m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7];
  549. M[8] = m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11];
  550. M[9] = m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11];
  551. M[10] = m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11];
  552. M[11] = m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11];
  553. M[12] = m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15];
  554. M[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15];
  555. M[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15];
  556. M[15] = m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15];
  557. return *this;
  558. }
  559. //! multiply by another matrix
  560. // set this matrix to the product of two other matrices
  561. // goal is to reduce stack use and copy
  562. template <class T>
  563. inline CMatrix4<T> &CMatrix4<T>::setbyproduct(const CMatrix4<T> &other_a, const CMatrix4<T> &other_b)
  564. {
  565. return setbyproduct_nocheck(other_a, other_b);
  566. }
  567. //! multiply by another matrix
  568. template <class T>
  569. inline CMatrix4<T> CMatrix4<T>::operator*(const CMatrix4<T> &m2) const
  570. {
  571. CMatrix4<T> m3(EM4CONST_NOTHING);
  572. const T *m1 = M;
  573. m3[0] = m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3];
  574. m3[1] = m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3];
  575. m3[2] = m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3];
  576. m3[3] = m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3];
  577. m3[4] = m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7];
  578. m3[5] = m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7];
  579. m3[6] = m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7];
  580. m3[7] = m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7];
  581. m3[8] = m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11];
  582. m3[9] = m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11];
  583. m3[10] = m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11];
  584. m3[11] = m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11];
  585. m3[12] = m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15];
  586. m3[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15];
  587. m3[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15];
  588. m3[15] = m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15];
  589. return m3;
  590. }
  591. template <class T>
  592. inline vector3d<T> CMatrix4<T>::getTranslation() const
  593. {
  594. return vector3d<T>(M[12], M[13], M[14]);
  595. }
  596. template <class T>
  597. inline CMatrix4<T> &CMatrix4<T>::setTranslation(const vector3d<T> &translation)
  598. {
  599. M[12] = translation.X;
  600. M[13] = translation.Y;
  601. M[14] = translation.Z;
  602. return *this;
  603. }
  604. template <class T>
  605. inline CMatrix4<T> &CMatrix4<T>::setScale(const vector3d<T> &scale)
  606. {
  607. M[0] = scale.X;
  608. M[5] = scale.Y;
  609. M[10] = scale.Z;
  610. return *this;
  611. }
  612. //! Returns the absolute values of the scales of the 3x3 submatrix.
  613. /**
  614. Note: You only get back original values if the matrix only set the scale.
  615. Otherwise the result is a scale you can use to normalize the matrix axes,
  616. but it's usually no longer what you did set with setScale.
  617. */
  618. template <class T>
  619. inline vector3d<T> CMatrix4<T>::getScale() const
  620. {
  621. auto row_vector_length = [this](int col) {
  622. int i = 4 * col;
  623. return sqrtf(M[i] * M[i] + M[i+1] * M[i+1] + M[i+2] * M[i+2]);
  624. };
  625. return {
  626. row_vector_length(0),
  627. row_vector_length(1),
  628. row_vector_length(2),
  629. };
  630. }
  631. template <class T>
  632. inline CMatrix4<T> &CMatrix4<T>::setRotationDegrees(const vector3d<T> &rotation)
  633. {
  634. return setRotationRadians(rotation * DEGTORAD);
  635. }
  636. template <class T>
  637. inline CMatrix4<T> &CMatrix4<T>::setRotationRadians(const vector3d<T> &rotation)
  638. {
  639. const f64 cPitch = cos(rotation.X);
  640. const f64 sPitch = sin(rotation.X);
  641. const f64 cYaw = cos(rotation.Y);
  642. const f64 sYaw = sin(rotation.Y);
  643. const f64 cRoll = cos(rotation.Z);
  644. const f64 sRoll = sin(rotation.Z);
  645. M[0] = (T)(cYaw * cRoll);
  646. M[1] = (T)(cYaw * sRoll);
  647. M[2] = (T)(-sYaw);
  648. const f64 sPitch_sYaw = sPitch * sYaw;
  649. const f64 cPitch_sYaw = cPitch * sYaw;
  650. M[4] = (T)(sPitch_sYaw * cRoll - cPitch * sRoll);
  651. M[5] = (T)(sPitch_sYaw * sRoll + cPitch * cRoll);
  652. M[6] = (T)(sPitch * cYaw);
  653. M[8] = (T)(cPitch_sYaw * cRoll + sPitch * sRoll);
  654. M[9] = (T)(cPitch_sYaw * sRoll - sPitch * cRoll);
  655. M[10] = (T)(cPitch * cYaw);
  656. return *this;
  657. }
  658. template <class T>
  659. template <bool degrees>
  660. inline vector3d<T> CMatrix4<T>::getRotation(const vector3d<T> &scale_) const
  661. {
  662. // Based on code by Chev
  663. const CMatrix4<T> &mat = *this;
  664. const vector3d<f64> scale(iszero(scale_.X) ? FLT_MAX : scale_.X, iszero(scale_.Y) ? FLT_MAX : scale_.Y, iszero(scale_.Z) ? FLT_MAX : scale_.Z);
  665. const vector3d<f64> invScale(reciprocal(scale.X), reciprocal(scale.Y), reciprocal(scale.Z));
  666. f64 a = clamp(mat[2] * invScale.X, -1.0, 1.0);
  667. f64 Y = -asin(a);
  668. f64 rotx, roty, X, Z;
  669. if (!core::equals(std::abs(a), 1.0)) {
  670. // abs(a) = abs(sin(Y)) = 1 <=> cos(Y) = 0
  671. rotx = mat[10] * invScale.Z;
  672. roty = mat[6] * invScale.Y;
  673. X = atan2(roty, rotx);
  674. rotx = mat[0] * invScale.X;
  675. roty = mat[1] * invScale.X;
  676. Z = atan2(roty, rotx);
  677. } else {
  678. X = 0.0;
  679. rotx = mat[5];
  680. roty = -mat[4];
  681. Z = atan2(roty, rotx);
  682. }
  683. if (degrees) {
  684. X *= core::RADTODEG64;
  685. Y *= core::RADTODEG64;
  686. Z *= core::RADTODEG64;
  687. }
  688. return vector3d<T>((T)X, (T)Y, (T)Z);
  689. }
  690. template <class T>
  691. inline vector3d<T> CMatrix4<T>::getRotationRadians(const vector3d<T> &scale) const
  692. {
  693. return getRotation<false>(scale);
  694. }
  695. template <class T>
  696. inline vector3d<T> CMatrix4<T>::getRotationRadians() const
  697. {
  698. return getRotationRadians(getScale());
  699. }
  700. template <class T>
  701. inline vector3d<T> CMatrix4<T>::getRotationDegrees() const
  702. {
  703. return getRotation<true>(getScale());
  704. }
  705. //! Sets matrix to rotation matrix defined by axis and angle, assuming LH rotation
  706. template <class T>
  707. inline CMatrix4<T> &CMatrix4<T>::setRotationAxisRadians(const T &angle, const vector3d<T> &axis)
  708. {
  709. const f64 c = cos(angle);
  710. const f64 s = sin(angle);
  711. const f64 t = 1.0 - c;
  712. const f64 tx = t * axis.X;
  713. const f64 ty = t * axis.Y;
  714. const f64 tz = t * axis.Z;
  715. const f64 sx = s * axis.X;
  716. const f64 sy = s * axis.Y;
  717. const f64 sz = s * axis.Z;
  718. M[0] = (T)(tx * axis.X + c);
  719. M[1] = (T)(tx * axis.Y + sz);
  720. M[2] = (T)(tx * axis.Z - sy);
  721. M[4] = (T)(ty * axis.X - sz);
  722. M[5] = (T)(ty * axis.Y + c);
  723. M[6] = (T)(ty * axis.Z + sx);
  724. M[8] = (T)(tz * axis.X + sy);
  725. M[9] = (T)(tz * axis.Y - sx);
  726. M[10] = (T)(tz * axis.Z + c);
  727. return *this;
  728. }
  729. template <class T>
  730. inline CMatrix4<T> &CMatrix4<T>::makeIdentity()
  731. {
  732. memset(M, 0, 16 * sizeof(T));
  733. M[0] = M[5] = M[10] = M[15] = (T)1;
  734. return *this;
  735. }
  736. /*
  737. check identity with epsilon
  738. solve floating range problems..
  739. */
  740. template <class T>
  741. inline bool CMatrix4<T>::isIdentity() const
  742. {
  743. if (!core::equals(M[12], (T)0) || !core::equals(M[13], (T)0) || !core::equals(M[14], (T)0) || !core::equals(M[15], (T)1))
  744. return false;
  745. if (!core::equals(M[0], (T)1) || !core::equals(M[1], (T)0) || !core::equals(M[2], (T)0) || !core::equals(M[3], (T)0))
  746. return false;
  747. if (!core::equals(M[4], (T)0) || !core::equals(M[5], (T)1) || !core::equals(M[6], (T)0) || !core::equals(M[7], (T)0))
  748. return false;
  749. if (!core::equals(M[8], (T)0) || !core::equals(M[9], (T)0) || !core::equals(M[10], (T)1) || !core::equals(M[11], (T)0))
  750. return false;
  751. /*
  752. if (!core::equals( M[ 0], (T)1 ) ||
  753. !core::equals( M[ 5], (T)1 ) ||
  754. !core::equals( M[10], (T)1 ) ||
  755. !core::equals( M[15], (T)1 ))
  756. return false;
  757. for (s32 i=0; i<4; ++i)
  758. for (s32 j=0; j<4; ++j)
  759. if ((j != i) && (!iszero((*this)(i,j))))
  760. return false;
  761. */
  762. return true;
  763. }
  764. template <class T>
  765. inline vector3d<T> CMatrix4<T>::rotateAndScaleVect(const vector3d<T> &v) const
  766. {
  767. return {
  768. v.X * M[0] + v.Y * M[4] + v.Z * M[8],
  769. v.X * M[1] + v.Y * M[5] + v.Z * M[9],
  770. v.X * M[2] + v.Y * M[6] + v.Z * M[10]
  771. };
  772. }
  773. template <class T>
  774. inline vector3d<T> CMatrix4<T>::scaleThenInvRotVect(const vector3d<T> &v) const
  775. {
  776. return {
  777. v.X * M[0] + v.Y * M[1] + v.Z * M[2],
  778. v.X * M[4] + v.Y * M[5] + v.Z * M[6],
  779. v.X * M[8] + v.Y * M[9] + v.Z * M[10]
  780. };
  781. }
  782. template <class T>
  783. inline vector3d<T> CMatrix4<T>::transformVect(const vector3d<T> &v) const
  784. {
  785. return {
  786. v.X * M[0] + v.Y * M[4] + v.Z * M[8] + M[12],
  787. v.X * M[1] + v.Y * M[5] + v.Z * M[9] + M[13],
  788. v.X * M[2] + v.Y * M[6] + v.Z * M[10] + M[14],
  789. };
  790. }
  791. template <class T>
  792. inline void CMatrix4<T>::transformVect(T *out, const vector3df &in) const
  793. {
  794. out[0] = in.X * M[0] + in.Y * M[4] + in.Z * M[8] + M[12];
  795. out[1] = in.X * M[1] + in.Y * M[5] + in.Z * M[9] + M[13];
  796. out[2] = in.X * M[2] + in.Y * M[6] + in.Z * M[10] + M[14];
  797. out[3] = in.X * M[3] + in.Y * M[7] + in.Z * M[11] + M[15];
  798. }
  799. template <class T>
  800. inline void CMatrix4<T>::transformVec3(T *out, const T *in) const
  801. {
  802. out[0] = in[0] * M[0] + in[1] * M[4] + in[2] * M[8] + M[12];
  803. out[1] = in[0] * M[1] + in[1] * M[5] + in[2] * M[9] + M[13];
  804. out[2] = in[0] * M[2] + in[1] * M[6] + in[2] * M[10] + M[14];
  805. }
  806. template <class T>
  807. inline void CMatrix4<T>::transformVec4(T *out, const T *in) const
  808. {
  809. out[0] = in[0] * M[0] + in[1] * M[4] + in[2] * M[8] + in[3] * M[12];
  810. out[1] = in[0] * M[1] + in[1] * M[5] + in[2] * M[9] + in[3] * M[13];
  811. out[2] = in[0] * M[2] + in[1] * M[6] + in[2] * M[10] + in[3] * M[14];
  812. out[3] = in[0] * M[3] + in[1] * M[7] + in[2] * M[11] + in[3] * M[15];
  813. }
  814. //! Transforms a plane by this matrix
  815. template <class T>
  816. inline void CMatrix4<T>::transformPlane(plane3d<f32> &plane) const
  817. {
  818. vector3df member;
  819. // Transform the plane member point, i.e. rotate, translate and scale it.
  820. transformVect(member, plane.getMemberPoint());
  821. // Transform the normal by the transposed inverse of the matrix
  822. CMatrix4<T> transposedInverse(*this, EM4CONST_INVERSE_TRANSPOSED);
  823. vector3df normal = transposedInverse.rotateAndScaleVect(plane.Normal);
  824. plane.setPlane(member, normal.normalize());
  825. }
  826. //! Transforms a plane by this matrix
  827. template <class T>
  828. inline void CMatrix4<T>::transformPlane(const plane3d<f32> &in, plane3d<f32> &out) const
  829. {
  830. out = in;
  831. transformPlane(out);
  832. }
  833. //! Transforms a axis aligned bounding box more accurately than transformBox()
  834. template <class T>
  835. inline void CMatrix4<T>::transformBoxEx(aabbox3d<f32> &box) const
  836. {
  837. const f32 Amin[3] = {box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z};
  838. const f32 Amax[3] = {box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z};
  839. f32 Bmin[3];
  840. f32 Bmax[3];
  841. Bmin[0] = Bmax[0] = M[12];
  842. Bmin[1] = Bmax[1] = M[13];
  843. Bmin[2] = Bmax[2] = M[14];
  844. const CMatrix4<T> &m = *this;
  845. for (u32 i = 0; i < 3; ++i) {
  846. for (u32 j = 0; j < 3; ++j) {
  847. const f32 a = m(j, i) * Amin[j];
  848. const f32 b = m(j, i) * Amax[j];
  849. if (a < b) {
  850. Bmin[i] += a;
  851. Bmax[i] += b;
  852. } else {
  853. Bmin[i] += b;
  854. Bmax[i] += a;
  855. }
  856. }
  857. }
  858. box.MinEdge.X = Bmin[0];
  859. box.MinEdge.Y = Bmin[1];
  860. box.MinEdge.Z = Bmin[2];
  861. box.MaxEdge.X = Bmax[0];
  862. box.MaxEdge.Y = Bmax[1];
  863. box.MaxEdge.Z = Bmax[2];
  864. }
  865. //! Multiplies this matrix by a 1x4 matrix
  866. template <class T>
  867. inline void CMatrix4<T>::multiplyWith1x4Matrix(T *matrix) const
  868. {
  869. /*
  870. 0 1 2 3
  871. 4 5 6 7
  872. 8 9 10 11
  873. 12 13 14 15
  874. */
  875. T mat[4];
  876. mat[0] = matrix[0];
  877. mat[1] = matrix[1];
  878. mat[2] = matrix[2];
  879. mat[3] = matrix[3];
  880. matrix[0] = M[0] * mat[0] + M[4] * mat[1] + M[8] * mat[2] + M[12] * mat[3];
  881. matrix[1] = M[1] * mat[0] + M[5] * mat[1] + M[9] * mat[2] + M[13] * mat[3];
  882. matrix[2] = M[2] * mat[0] + M[6] * mat[1] + M[10] * mat[2] + M[14] * mat[3];
  883. matrix[3] = M[3] * mat[0] + M[7] * mat[1] + M[11] * mat[2] + M[15] * mat[3];
  884. }
  885. template <class T>
  886. inline void CMatrix4<T>::inverseTranslateVect(vector3df &vect) const
  887. {
  888. vect.X = vect.X - M[12];
  889. vect.Y = vect.Y - M[13];
  890. vect.Z = vect.Z - M[14];
  891. }
  892. template <class T>
  893. inline void CMatrix4<T>::translateVect(vector3df &vect) const
  894. {
  895. vect.X = vect.X + M[12];
  896. vect.Y = vect.Y + M[13];
  897. vect.Z = vect.Z + M[14];
  898. }
  899. template <class T>
  900. inline bool CMatrix4<T>::getInverse(CMatrix4<T> &out) const
  901. {
  902. /// Calculates the inverse of this Matrix
  903. /// The inverse is calculated using Cramers rule.
  904. /// If no inverse exists then 'false' is returned.
  905. const CMatrix4<T> &m = *this;
  906. f32 d = (m[0] * m[5] - m[1] * m[4]) * (m[10] * m[15] - m[11] * m[14]) -
  907. (m[0] * m[6] - m[2] * m[4]) * (m[9] * m[15] - m[11] * m[13]) +
  908. (m[0] * m[7] - m[3] * m[4]) * (m[9] * m[14] - m[10] * m[13]) +
  909. (m[1] * m[6] - m[2] * m[5]) * (m[8] * m[15] - m[11] * m[12]) -
  910. (m[1] * m[7] - m[3] * m[5]) * (m[8] * m[14] - m[10] * m[12]) +
  911. (m[2] * m[7] - m[3] * m[6]) * (m[8] * m[13] - m[9] * m[12]);
  912. if (iszero(d, FLT_MIN))
  913. return false;
  914. d = reciprocal(d);
  915. out[0] = d * (m[5] * (m[10] * m[15] - m[11] * m[14]) +
  916. m[6] * (m[11] * m[13] - m[9] * m[15]) +
  917. m[7] * (m[9] * m[14] - m[10] * m[13]));
  918. out[1] = d * (m[9] * (m[2] * m[15] - m[3] * m[14]) +
  919. m[10] * (m[3] * m[13] - m[1] * m[15]) +
  920. m[11] * (m[1] * m[14] - m[2] * m[13]));
  921. out[2] = d * (m[13] * (m[2] * m[7] - m[3] * m[6]) +
  922. m[14] * (m[3] * m[5] - m[1] * m[7]) +
  923. m[15] * (m[1] * m[6] - m[2] * m[5]));
  924. out[3] = d * (m[1] * (m[7] * m[10] - m[6] * m[11]) +
  925. m[2] * (m[5] * m[11] - m[7] * m[9]) +
  926. m[3] * (m[6] * m[9] - m[5] * m[10]));
  927. out[4] = d * (m[6] * (m[8] * m[15] - m[11] * m[12]) +
  928. m[7] * (m[10] * m[12] - m[8] * m[14]) +
  929. m[4] * (m[11] * m[14] - m[10] * m[15]));
  930. out[5] = d * (m[10] * (m[0] * m[15] - m[3] * m[12]) +
  931. m[11] * (m[2] * m[12] - m[0] * m[14]) +
  932. m[8] * (m[3] * m[14] - m[2] * m[15]));
  933. out[6] = d * (m[14] * (m[0] * m[7] - m[3] * m[4]) +
  934. m[15] * (m[2] * m[4] - m[0] * m[6]) +
  935. m[12] * (m[3] * m[6] - m[2] * m[7]));
  936. out[7] = d * (m[2] * (m[7] * m[8] - m[4] * m[11]) +
  937. m[3] * (m[4] * m[10] - m[6] * m[8]) +
  938. m[0] * (m[6] * m[11] - m[7] * m[10]));
  939. out[8] = d * (m[7] * (m[8] * m[13] - m[9] * m[12]) +
  940. m[4] * (m[9] * m[15] - m[11] * m[13]) +
  941. m[5] * (m[11] * m[12] - m[8] * m[15]));
  942. out[9] = d * (m[11] * (m[0] * m[13] - m[1] * m[12]) +
  943. m[8] * (m[1] * m[15] - m[3] * m[13]) +
  944. m[9] * (m[3] * m[12] - m[0] * m[15]));
  945. out[10] = d * (m[15] * (m[0] * m[5] - m[1] * m[4]) +
  946. m[12] * (m[1] * m[7] - m[3] * m[5]) +
  947. m[13] * (m[3] * m[4] - m[0] * m[7]));
  948. out[11] = d * (m[3] * (m[5] * m[8] - m[4] * m[9]) +
  949. m[0] * (m[7] * m[9] - m[5] * m[11]) +
  950. m[1] * (m[4] * m[11] - m[7] * m[8]));
  951. out[12] = d * (m[4] * (m[10] * m[13] - m[9] * m[14]) +
  952. m[5] * (m[8] * m[14] - m[10] * m[12]) +
  953. m[6] * (m[9] * m[12] - m[8] * m[13]));
  954. out[13] = d * (m[8] * (m[2] * m[13] - m[1] * m[14]) +
  955. m[9] * (m[0] * m[14] - m[2] * m[12]) +
  956. m[10] * (m[1] * m[12] - m[0] * m[13]));
  957. out[14] = d * (m[12] * (m[2] * m[5] - m[1] * m[6]) +
  958. m[13] * (m[0] * m[6] - m[2] * m[4]) +
  959. m[14] * (m[1] * m[4] - m[0] * m[5]));
  960. out[15] = d * (m[0] * (m[5] * m[10] - m[6] * m[9]) +
  961. m[1] * (m[6] * m[8] - m[4] * m[10]) +
  962. m[2] * (m[4] * m[9] - m[5] * m[8]));
  963. return true;
  964. }
  965. //! Inverts a primitive matrix which only contains a translation and a rotation
  966. //! \param out: where result matrix is written to.
  967. template <class T>
  968. inline bool CMatrix4<T>::getInversePrimitive(CMatrix4<T> &out) const
  969. {
  970. out.M[0] = M[0];
  971. out.M[1] = M[4];
  972. out.M[2] = M[8];
  973. out.M[3] = 0;
  974. out.M[4] = M[1];
  975. out.M[5] = M[5];
  976. out.M[6] = M[9];
  977. out.M[7] = 0;
  978. out.M[8] = M[2];
  979. out.M[9] = M[6];
  980. out.M[10] = M[10];
  981. out.M[11] = 0;
  982. out.M[12] = (T) - (M[12] * M[0] + M[13] * M[1] + M[14] * M[2]);
  983. out.M[13] = (T) - (M[12] * M[4] + M[13] * M[5] + M[14] * M[6]);
  984. out.M[14] = (T) - (M[12] * M[8] + M[13] * M[9] + M[14] * M[10]);
  985. out.M[15] = 1;
  986. return true;
  987. }
  988. /*!
  989. */
  990. template <class T>
  991. inline bool CMatrix4<T>::makeInverse()
  992. {
  993. CMatrix4<T> temp(EM4CONST_NOTHING);
  994. if (getInverse(temp)) {
  995. *this = temp;
  996. return true;
  997. }
  998. return false;
  999. }
  1000. template <class T>
  1001. inline CMatrix4<T> &CMatrix4<T>::operator=(const T &scalar)
  1002. {
  1003. for (s32 i = 0; i < 16; ++i)
  1004. M[i] = scalar;
  1005. return *this;
  1006. }
  1007. // Builds a right-handed perspective projection matrix based on a field of view
  1008. template <class T>
  1009. inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixPerspectiveFovRH(
  1010. f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero)
  1011. {
  1012. const f64 h = reciprocal(tan(fieldOfViewRadians * 0.5));
  1013. assert(aspectRatio != 0.f); // divide by zero
  1014. const T w = static_cast<T>(h / aspectRatio);
  1015. assert(zNear != zFar); // divide by zero
  1016. M[0] = w;
  1017. M[1] = 0;
  1018. M[2] = 0;
  1019. M[3] = 0;
  1020. M[4] = 0;
  1021. M[5] = (T)h;
  1022. M[6] = 0;
  1023. M[7] = 0;
  1024. M[8] = 0;
  1025. M[9] = 0;
  1026. // M[10]
  1027. M[11] = -1;
  1028. M[12] = 0;
  1029. M[13] = 0;
  1030. // M[14]
  1031. M[15] = 0;
  1032. if (zClipFromZero) { // DirectX version
  1033. M[10] = (T)(zFar / (zNear - zFar));
  1034. M[14] = (T)(zNear * zFar / (zNear - zFar));
  1035. } else // OpenGL version
  1036. {
  1037. M[10] = (T)((zFar + zNear) / (zNear - zFar));
  1038. M[14] = (T)(2.0f * zNear * zFar / (zNear - zFar));
  1039. }
  1040. return *this;
  1041. }
  1042. // Builds a left-handed perspective projection matrix based on a field of view
  1043. template <class T>
  1044. inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixPerspectiveFovLH(
  1045. f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero)
  1046. {
  1047. const f64 h = reciprocal(tan(fieldOfViewRadians * 0.5));
  1048. assert(aspectRatio != 0.f); // divide by zero
  1049. const T w = static_cast<T>(h / aspectRatio);
  1050. assert(zNear != zFar); // divide by zero
  1051. M[0] = w;
  1052. M[1] = 0;
  1053. M[2] = 0;
  1054. M[3] = 0;
  1055. M[4] = 0;
  1056. M[5] = (T)h;
  1057. M[6] = 0;
  1058. M[7] = 0;
  1059. M[8] = 0;
  1060. M[9] = 0;
  1061. // M[10]
  1062. M[11] = 1;
  1063. M[12] = 0;
  1064. M[13] = 0;
  1065. // M[14]
  1066. M[15] = 0;
  1067. if (zClipFromZero) { // DirectX version
  1068. M[10] = (T)(zFar / (zFar - zNear));
  1069. M[14] = (T)(-zNear * zFar / (zFar - zNear));
  1070. } else // OpenGL version
  1071. {
  1072. M[10] = (T)((zFar + zNear) / (zFar - zNear));
  1073. M[14] = (T)(2.0f * zNear * zFar / (zNear - zFar));
  1074. }
  1075. return *this;
  1076. }
  1077. // Builds a left-handed perspective projection matrix based on a field of view, with far plane culling at infinity
  1078. template <class T>
  1079. inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixPerspectiveFovInfinityLH(
  1080. f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon)
  1081. {
  1082. const f64 h = reciprocal(tan(fieldOfViewRadians * 0.5));
  1083. assert(aspectRatio != 0.f); // divide by zero
  1084. const T w = static_cast<T>(h / aspectRatio);
  1085. M[0] = w;
  1086. M[1] = 0;
  1087. M[2] = 0;
  1088. M[3] = 0;
  1089. M[4] = 0;
  1090. M[5] = (T)h;
  1091. M[6] = 0;
  1092. M[7] = 0;
  1093. M[8] = 0;
  1094. M[9] = 0;
  1095. M[10] = (T)(1.f - epsilon);
  1096. M[11] = 1;
  1097. M[12] = 0;
  1098. M[13] = 0;
  1099. M[14] = (T)(zNear * (epsilon - 1.f));
  1100. M[15] = 0;
  1101. return *this;
  1102. }
  1103. // Builds a left-handed orthogonal projection matrix.
  1104. template <class T>
  1105. inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixOrthoLH(
  1106. f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
  1107. {
  1108. assert(widthOfViewVolume != 0.f); // divide by zero
  1109. assert(heightOfViewVolume != 0.f); // divide by zero
  1110. assert(zNear != zFar); // divide by zero
  1111. M[0] = (T)(2 / widthOfViewVolume);
  1112. M[1] = 0;
  1113. M[2] = 0;
  1114. M[3] = 0;
  1115. M[4] = 0;
  1116. M[5] = (T)(2 / heightOfViewVolume);
  1117. M[6] = 0;
  1118. M[7] = 0;
  1119. M[8] = 0;
  1120. M[9] = 0;
  1121. // M[10]
  1122. M[11] = 0;
  1123. M[12] = 0;
  1124. M[13] = 0;
  1125. // M[14]
  1126. M[15] = 1;
  1127. if (zClipFromZero) {
  1128. M[10] = (T)(1 / (zFar - zNear));
  1129. M[14] = (T)(zNear / (zNear - zFar));
  1130. } else {
  1131. M[10] = (T)(2 / (zFar - zNear));
  1132. M[14] = (T) - (zFar + zNear) / (zFar - zNear);
  1133. }
  1134. return *this;
  1135. }
  1136. // Builds a right-handed orthogonal projection matrix.
  1137. template <class T>
  1138. inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixOrthoRH(
  1139. f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
  1140. {
  1141. assert(widthOfViewVolume != 0.f); // divide by zero
  1142. assert(heightOfViewVolume != 0.f); // divide by zero
  1143. assert(zNear != zFar); // divide by zero
  1144. M[0] = (T)(2 / widthOfViewVolume);
  1145. M[1] = 0;
  1146. M[2] = 0;
  1147. M[3] = 0;
  1148. M[4] = 0;
  1149. M[5] = (T)(2 / heightOfViewVolume);
  1150. M[6] = 0;
  1151. M[7] = 0;
  1152. M[8] = 0;
  1153. M[9] = 0;
  1154. // M[10]
  1155. M[11] = 0;
  1156. M[12] = 0;
  1157. M[13] = 0;
  1158. // M[14]
  1159. M[15] = 1;
  1160. if (zClipFromZero) {
  1161. M[10] = (T)(1 / (zNear - zFar));
  1162. M[14] = (T)(zNear / (zNear - zFar));
  1163. } else {
  1164. M[10] = (T)(2 / (zNear - zFar));
  1165. M[14] = (T) - (zFar + zNear) / (zFar - zNear);
  1166. }
  1167. return *this;
  1168. }
  1169. // Builds a right-handed perspective projection matrix.
  1170. template <class T>
  1171. inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixPerspectiveRH(
  1172. f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
  1173. {
  1174. assert(widthOfViewVolume != 0.f); // divide by zero
  1175. assert(heightOfViewVolume != 0.f); // divide by zero
  1176. assert(zNear != zFar); // divide by zero
  1177. M[0] = (T)(2 * zNear / widthOfViewVolume);
  1178. M[1] = 0;
  1179. M[2] = 0;
  1180. M[3] = 0;
  1181. M[4] = 0;
  1182. M[5] = (T)(2 * zNear / heightOfViewVolume);
  1183. M[6] = 0;
  1184. M[7] = 0;
  1185. M[8] = 0;
  1186. M[9] = 0;
  1187. // M[10]
  1188. M[11] = -1;
  1189. M[12] = 0;
  1190. M[13] = 0;
  1191. // M[14]
  1192. M[15] = 0;
  1193. if (zClipFromZero) { // DirectX version
  1194. M[10] = (T)(zFar / (zNear - zFar));
  1195. M[14] = (T)(zNear * zFar / (zNear - zFar));
  1196. } else // OpenGL version
  1197. {
  1198. M[10] = (T)((zFar + zNear) / (zNear - zFar));
  1199. M[14] = (T)(2.0f * zNear * zFar / (zNear - zFar));
  1200. }
  1201. return *this;
  1202. }
  1203. // Builds a left-handed perspective projection matrix.
  1204. template <class T>
  1205. inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixPerspectiveLH(
  1206. f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
  1207. {
  1208. assert(widthOfViewVolume != 0.f); // divide by zero
  1209. assert(heightOfViewVolume != 0.f); // divide by zero
  1210. assert(zNear != zFar); // divide by zero
  1211. M[0] = (T)(2 * zNear / widthOfViewVolume);
  1212. M[1] = 0;
  1213. M[2] = 0;
  1214. M[3] = 0;
  1215. M[4] = 0;
  1216. M[5] = (T)(2 * zNear / heightOfViewVolume);
  1217. M[6] = 0;
  1218. M[7] = 0;
  1219. M[8] = 0;
  1220. M[9] = 0;
  1221. // M[10]
  1222. M[11] = 1;
  1223. M[12] = 0;
  1224. M[13] = 0;
  1225. // M[14] = (T)(zNear*zFar/(zNear-zFar));
  1226. M[15] = 0;
  1227. if (zClipFromZero) { // DirectX version
  1228. M[10] = (T)(zFar / (zFar - zNear));
  1229. M[14] = (T)(zNear * zFar / (zNear - zFar));
  1230. } else // OpenGL version
  1231. {
  1232. M[10] = (T)((zFar + zNear) / (zFar - zNear));
  1233. M[14] = (T)(2.0f * zNear * zFar / (zNear - zFar));
  1234. }
  1235. return *this;
  1236. }
  1237. // Builds a matrix that flattens geometry into a plane.
  1238. template <class T>
  1239. inline CMatrix4<T> &CMatrix4<T>::buildShadowMatrix(const vector3df &light, plane3df plane, f32 point)
  1240. {
  1241. plane.Normal.normalize();
  1242. const f32 d = plane.Normal.dotProduct(light);
  1243. M[0] = (T)(-plane.Normal.X * light.X + d);
  1244. M[1] = (T)(-plane.Normal.X * light.Y);
  1245. M[2] = (T)(-plane.Normal.X * light.Z);
  1246. M[3] = (T)(-plane.Normal.X * point);
  1247. M[4] = (T)(-plane.Normal.Y * light.X);
  1248. M[5] = (T)(-plane.Normal.Y * light.Y + d);
  1249. M[6] = (T)(-plane.Normal.Y * light.Z);
  1250. M[7] = (T)(-plane.Normal.Y * point);
  1251. M[8] = (T)(-plane.Normal.Z * light.X);
  1252. M[9] = (T)(-plane.Normal.Z * light.Y);
  1253. M[10] = (T)(-plane.Normal.Z * light.Z + d);
  1254. M[11] = (T)(-plane.Normal.Z * point);
  1255. M[12] = (T)(-plane.D * light.X);
  1256. M[13] = (T)(-plane.D * light.Y);
  1257. M[14] = (T)(-plane.D * light.Z);
  1258. M[15] = (T)(-plane.D * point + d);
  1259. return *this;
  1260. }
  1261. // Builds a left-handed look-at matrix.
  1262. template <class T>
  1263. inline CMatrix4<T> &CMatrix4<T>::buildCameraLookAtMatrixLH(
  1264. const vector3df &position,
  1265. const vector3df &target,
  1266. const vector3df &upVector)
  1267. {
  1268. vector3df zaxis = target - position;
  1269. zaxis.normalize();
  1270. vector3df xaxis = upVector.crossProduct(zaxis);
  1271. xaxis.normalize();
  1272. vector3df yaxis = zaxis.crossProduct(xaxis);
  1273. M[0] = (T)xaxis.X;
  1274. M[1] = (T)yaxis.X;
  1275. M[2] = (T)zaxis.X;
  1276. M[3] = 0;
  1277. M[4] = (T)xaxis.Y;
  1278. M[5] = (T)yaxis.Y;
  1279. M[6] = (T)zaxis.Y;
  1280. M[7] = 0;
  1281. M[8] = (T)xaxis.Z;
  1282. M[9] = (T)yaxis.Z;
  1283. M[10] = (T)zaxis.Z;
  1284. M[11] = 0;
  1285. M[12] = (T)-xaxis.dotProduct(position);
  1286. M[13] = (T)-yaxis.dotProduct(position);
  1287. M[14] = (T)-zaxis.dotProduct(position);
  1288. M[15] = 1;
  1289. return *this;
  1290. }
  1291. // Builds a right-handed look-at matrix.
  1292. template <class T>
  1293. inline CMatrix4<T> &CMatrix4<T>::buildCameraLookAtMatrixRH(
  1294. const vector3df &position,
  1295. const vector3df &target,
  1296. const vector3df &upVector)
  1297. {
  1298. vector3df zaxis = position - target;
  1299. zaxis.normalize();
  1300. vector3df xaxis = upVector.crossProduct(zaxis);
  1301. xaxis.normalize();
  1302. vector3df yaxis = zaxis.crossProduct(xaxis);
  1303. M[0] = (T)xaxis.X;
  1304. M[1] = (T)yaxis.X;
  1305. M[2] = (T)zaxis.X;
  1306. M[3] = 0;
  1307. M[4] = (T)xaxis.Y;
  1308. M[5] = (T)yaxis.Y;
  1309. M[6] = (T)zaxis.Y;
  1310. M[7] = 0;
  1311. M[8] = (T)xaxis.Z;
  1312. M[9] = (T)yaxis.Z;
  1313. M[10] = (T)zaxis.Z;
  1314. M[11] = 0;
  1315. M[12] = (T)-xaxis.dotProduct(position);
  1316. M[13] = (T)-yaxis.dotProduct(position);
  1317. M[14] = (T)-zaxis.dotProduct(position);
  1318. M[15] = 1;
  1319. return *this;
  1320. }
  1321. // creates a new matrix as interpolated matrix from this and the passed one.
  1322. template <class T>
  1323. inline CMatrix4<T> CMatrix4<T>::interpolate(const CMatrix4<T> &b, f32 time) const
  1324. {
  1325. CMatrix4<T> mat(EM4CONST_NOTHING);
  1326. for (u32 i = 0; i < 16; i += 4) {
  1327. mat.M[i + 0] = (T)(M[i + 0] + (b.M[i + 0] - M[i + 0]) * time);
  1328. mat.M[i + 1] = (T)(M[i + 1] + (b.M[i + 1] - M[i + 1]) * time);
  1329. mat.M[i + 2] = (T)(M[i + 2] + (b.M[i + 2] - M[i + 2]) * time);
  1330. mat.M[i + 3] = (T)(M[i + 3] + (b.M[i + 3] - M[i + 3]) * time);
  1331. }
  1332. return mat;
  1333. }
  1334. // returns transposed matrix
  1335. template <class T>
  1336. inline CMatrix4<T> CMatrix4<T>::getTransposed() const
  1337. {
  1338. CMatrix4<T> t(EM4CONST_NOTHING);
  1339. getTransposed(t);
  1340. return t;
  1341. }
  1342. // returns transposed matrix
  1343. template <class T>
  1344. inline void CMatrix4<T>::getTransposed(CMatrix4<T> &o) const
  1345. {
  1346. o[0] = M[0];
  1347. o[1] = M[4];
  1348. o[2] = M[8];
  1349. o[3] = M[12];
  1350. o[4] = M[1];
  1351. o[5] = M[5];
  1352. o[6] = M[9];
  1353. o[7] = M[13];
  1354. o[8] = M[2];
  1355. o[9] = M[6];
  1356. o[10] = M[10];
  1357. o[11] = M[14];
  1358. o[12] = M[3];
  1359. o[13] = M[7];
  1360. o[14] = M[11];
  1361. o[15] = M[15];
  1362. }
  1363. // used to scale <-1,-1><1,1> to viewport
  1364. template <class T>
  1365. inline CMatrix4<T> &CMatrix4<T>::buildNDCToDCMatrix(const rect<s32> &viewport, f32 zScale)
  1366. {
  1367. const f32 scaleX = (viewport.getWidth() - 0.75f) * 0.5f;
  1368. const f32 scaleY = -(viewport.getHeight() - 0.75f) * 0.5f;
  1369. const f32 dx = -0.5f + ((viewport.UpperLeftCorner.X + viewport.LowerRightCorner.X) * 0.5f);
  1370. const f32 dy = -0.5f + ((viewport.UpperLeftCorner.Y + viewport.LowerRightCorner.Y) * 0.5f);
  1371. makeIdentity();
  1372. M[12] = (T)dx;
  1373. M[13] = (T)dy;
  1374. return setScale(vector3d<T>((T)scaleX, (T)scaleY, (T)zScale));
  1375. }
  1376. //! Builds a matrix that rotates from one vector to another
  1377. /** \param from: vector to rotate from
  1378. \param to: vector to rotate to
  1379. http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/index.htm
  1380. */
  1381. template <class T>
  1382. inline CMatrix4<T> &CMatrix4<T>::buildRotateFromTo(const vector3df &from, const vector3df &to)
  1383. {
  1384. // unit vectors
  1385. vector3df f(from);
  1386. vector3df t(to);
  1387. f.normalize();
  1388. t.normalize();
  1389. // axis multiplication by sin
  1390. vector3df vs(t.crossProduct(f));
  1391. // axis of rotation
  1392. vector3df v(vs);
  1393. v.normalize();
  1394. // cosine angle
  1395. T ca = f.dotProduct(t);
  1396. vector3df vt(v * (1 - ca));
  1397. M[0] = vt.X * v.X + ca;
  1398. M[5] = vt.Y * v.Y + ca;
  1399. M[10] = vt.Z * v.Z + ca;
  1400. vt.X *= v.Y;
  1401. vt.Z *= v.X;
  1402. vt.Y *= v.Z;
  1403. M[1] = vt.X - vs.Z;
  1404. M[2] = vt.Z + vs.Y;
  1405. M[3] = 0;
  1406. M[4] = vt.X + vs.Z;
  1407. M[6] = vt.Y - vs.X;
  1408. M[7] = 0;
  1409. M[8] = vt.Z - vs.Y;
  1410. M[9] = vt.Y + vs.X;
  1411. M[11] = 0;
  1412. M[12] = 0;
  1413. M[13] = 0;
  1414. M[14] = 0;
  1415. M[15] = 1;
  1416. return *this;
  1417. }
  1418. //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis
  1419. /** \param camPos: viewer position in world coord
  1420. \param center: object position in world-coord, rotation pivot
  1421. \param translation: object final translation from center
  1422. \param axis: axis to rotate about
  1423. \param from: source vector to rotate from
  1424. */
  1425. template <class T>
  1426. inline void CMatrix4<T>::buildAxisAlignedBillboard(
  1427. const vector3df &camPos,
  1428. const vector3df &center,
  1429. const vector3df &translation,
  1430. const vector3df &axis,
  1431. const vector3df &from)
  1432. {
  1433. // axis of rotation
  1434. vector3df up = axis;
  1435. up.normalize();
  1436. const vector3df forward = (camPos - center).normalize();
  1437. const vector3df right = up.crossProduct(forward).normalize();
  1438. // correct look vector
  1439. const vector3df look = right.crossProduct(up);
  1440. // rotate from to
  1441. // axis multiplication by sin
  1442. const vector3df vs = look.crossProduct(from);
  1443. // cosine angle
  1444. const f32 ca = from.dotProduct(look);
  1445. vector3df vt(up * (1.f - ca));
  1446. M[0] = static_cast<T>(vt.X * up.X + ca);
  1447. M[5] = static_cast<T>(vt.Y * up.Y + ca);
  1448. M[10] = static_cast<T>(vt.Z * up.Z + ca);
  1449. vt.X *= up.Y;
  1450. vt.Z *= up.X;
  1451. vt.Y *= up.Z;
  1452. M[1] = static_cast<T>(vt.X - vs.Z);
  1453. M[2] = static_cast<T>(vt.Z + vs.Y);
  1454. M[3] = 0;
  1455. M[4] = static_cast<T>(vt.X + vs.Z);
  1456. M[6] = static_cast<T>(vt.Y - vs.X);
  1457. M[7] = 0;
  1458. M[8] = static_cast<T>(vt.Z - vs.Y);
  1459. M[9] = static_cast<T>(vt.Y + vs.X);
  1460. M[11] = 0;
  1461. setRotationCenter(center, translation);
  1462. }
  1463. //! Builds a combined matrix which translate to a center before rotation and translate afterward
  1464. template <class T>
  1465. inline void CMatrix4<T>::setRotationCenter(const vector3df &center, const vector3df &translation)
  1466. {
  1467. M[12] = -M[0] * center.X - M[4] * center.Y - M[8] * center.Z + (center.X - translation.X);
  1468. M[13] = -M[1] * center.X - M[5] * center.Y - M[9] * center.Z + (center.Y - translation.Y);
  1469. M[14] = -M[2] * center.X - M[6] * center.Y - M[10] * center.Z + (center.Z - translation.Z);
  1470. M[15] = (T)1.0;
  1471. }
  1472. /*!
  1473. Generate texture coordinates as linear functions so that:
  1474. u = Ux*x + Uy*y + Uz*z + Uw
  1475. v = Vx*x + Vy*y + Vz*z + Vw
  1476. The matrix M for this case is:
  1477. Ux Vx 0 0
  1478. Uy Vy 0 0
  1479. Uz Vz 0 0
  1480. Uw Vw 0 0
  1481. */
  1482. template <class T>
  1483. inline CMatrix4<T> &CMatrix4<T>::buildTextureTransform(f32 rotateRad,
  1484. const vector2df &rotatecenter,
  1485. const vector2df &translate,
  1486. const vector2df &scale)
  1487. {
  1488. const f32 c = cosf(rotateRad);
  1489. const f32 s = sinf(rotateRad);
  1490. M[0] = (T)(c * scale.X);
  1491. M[1] = (T)(s * scale.Y);
  1492. M[2] = 0;
  1493. M[3] = 0;
  1494. M[4] = (T)(-s * scale.X);
  1495. M[5] = (T)(c * scale.Y);
  1496. M[6] = 0;
  1497. M[7] = 0;
  1498. M[8] = (T)(c * scale.X * rotatecenter.X + -s * rotatecenter.Y + translate.X);
  1499. M[9] = (T)(s * scale.Y * rotatecenter.X + c * rotatecenter.Y + translate.Y);
  1500. M[10] = 1;
  1501. M[11] = 0;
  1502. M[12] = 0;
  1503. M[13] = 0;
  1504. M[14] = 0;
  1505. M[15] = 1;
  1506. return *this;
  1507. }
  1508. // rotate about z axis, center ( 0.5, 0.5 )
  1509. template <class T>
  1510. inline CMatrix4<T> &CMatrix4<T>::setTextureRotationCenter(f32 rotateRad)
  1511. {
  1512. const f32 c = cosf(rotateRad);
  1513. const f32 s = sinf(rotateRad);
  1514. M[0] = (T)c;
  1515. M[1] = (T)s;
  1516. M[4] = (T)-s;
  1517. M[5] = (T)c;
  1518. M[8] = (T)(0.5f * (s - c) + 0.5f);
  1519. M[9] = (T)(-0.5f * (s + c) + 0.5f);
  1520. return *this;
  1521. }
  1522. template <class T>
  1523. inline CMatrix4<T> &CMatrix4<T>::setTextureTranslate(f32 x, f32 y)
  1524. {
  1525. M[8] = (T)x;
  1526. M[9] = (T)y;
  1527. return *this;
  1528. }
  1529. template <class T>
  1530. inline void CMatrix4<T>::getTextureTranslate(f32 &x, f32 &y) const
  1531. {
  1532. x = (f32)M[8];
  1533. y = (f32)M[9];
  1534. }
  1535. template <class T>
  1536. inline CMatrix4<T> &CMatrix4<T>::setTextureTranslateTransposed(f32 x, f32 y)
  1537. {
  1538. M[2] = (T)x;
  1539. M[6] = (T)y;
  1540. return *this;
  1541. }
  1542. template <class T>
  1543. inline CMatrix4<T> &CMatrix4<T>::setTextureScale(f32 sx, f32 sy)
  1544. {
  1545. M[0] = (T)sx;
  1546. M[5] = (T)sy;
  1547. return *this;
  1548. }
  1549. template <class T>
  1550. inline void CMatrix4<T>::getTextureScale(f32 &sx, f32 &sy) const
  1551. {
  1552. sx = (f32)M[0];
  1553. sy = (f32)M[5];
  1554. }
  1555. template <class T>
  1556. inline CMatrix4<T> &CMatrix4<T>::setTextureScaleCenter(f32 sx, f32 sy)
  1557. {
  1558. M[0] = (T)sx;
  1559. M[5] = (T)sy;
  1560. M[8] = (T)(0.5f - 0.5f * sx);
  1561. M[9] = (T)(0.5f - 0.5f * sy);
  1562. return *this;
  1563. }
  1564. // sets all matrix data members at once
  1565. template <class T>
  1566. inline CMatrix4<T> &CMatrix4<T>::setM(const T *data)
  1567. {
  1568. memcpy(M, data, 16 * sizeof(T));
  1569. return *this;
  1570. }
  1571. //! Compare two matrices using the equal method
  1572. template <class T>
  1573. inline bool CMatrix4<T>::equals(const CMatrix4<T> &other, const T tolerance) const
  1574. {
  1575. for (s32 i = 0; i < 16; ++i)
  1576. if (!core::equals(M[i], other.M[i], tolerance))
  1577. return false;
  1578. return true;
  1579. }
  1580. // Multiply by scalar.
  1581. template <class T>
  1582. inline CMatrix4<T> operator*(const T scalar, const CMatrix4<T> &mat)
  1583. {
  1584. return mat * scalar;
  1585. }
  1586. //! Typedef for f32 matrix
  1587. typedef CMatrix4<f32> matrix4;
  1588. //! global const identity matrix
  1589. extern const matrix4 IdentityMatrix;
  1590. } // end namespace core
  1591. } // end namespace irr