matrix4.h 63 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282
  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 "IrrCompileConfig.h" // for IRRLICHT_API
  13. // enable this to keep track of changes to the matrix
  14. // and make simpler identity check for seldom changing matrices
  15. // otherwise identity check will always compare the elements
  16. // #define USE_MATRIX_TEST
  17. namespace irr
  18. {
  19. namespace core
  20. {
  21. //! 4x4 matrix. Mostly used as transformation matrix for 3d calculations.
  22. /** The matrix is a D3D style matrix, row major with translations in the 4th row. */
  23. template <class T>
  24. class CMatrix4
  25. {
  26. public:
  27. //! Constructor Flags
  28. enum eConstructor
  29. {
  30. EM4CONST_NOTHING = 0,
  31. EM4CONST_COPY,
  32. EM4CONST_IDENTITY,
  33. EM4CONST_TRANSPOSED,
  34. EM4CONST_INVERSE,
  35. EM4CONST_INVERSE_TRANSPOSED
  36. };
  37. //! Default constructor
  38. /** \param constructor Choose the initialization style */
  39. CMatrix4(eConstructor constructor = EM4CONST_IDENTITY);
  40. //! Constructor with value initialization
  41. constexpr CMatrix4(const T &r0c0, const T &r0c1, const T &r0c2, const T &r0c3,
  42. const T &r1c0, const T &r1c1, const T &r1c2, const T &r1c3,
  43. const T &r2c0, const T &r2c1, const T &r2c2, const T &r2c3,
  44. const T &r3c0, const T &r3c1, const T &r3c2, const T &r3c3)
  45. {
  46. M[0] = r0c0;
  47. M[1] = r0c1;
  48. M[2] = r0c2;
  49. M[3] = r0c3;
  50. M[4] = r1c0;
  51. M[5] = r1c1;
  52. M[6] = r1c2;
  53. M[7] = r1c3;
  54. M[8] = r2c0;
  55. M[9] = r2c1;
  56. M[10] = r2c2;
  57. M[11] = r2c3;
  58. M[12] = r3c0;
  59. M[13] = r3c1;
  60. M[14] = r3c2;
  61. M[15] = r3c3;
  62. }
  63. //! Copy constructor
  64. /** \param other Other matrix to copy from
  65. \param constructor Choose the initialization style */
  66. CMatrix4(const CMatrix4<T> &other, eConstructor constructor = EM4CONST_COPY);
  67. //! Simple operator for directly accessing every element of the matrix.
  68. T &operator()(const s32 row, const s32 col)
  69. {
  70. #if defined(USE_MATRIX_TEST)
  71. definitelyIdentityMatrix = false;
  72. #endif
  73. return M[row * 4 + col];
  74. }
  75. //! Simple operator for directly accessing every element of the matrix.
  76. const T &operator()(const s32 row, const s32 col) const { return M[row * 4 + col]; }
  77. //! Simple operator for linearly accessing every element of the matrix.
  78. T &operator[](u32 index)
  79. {
  80. #if defined(USE_MATRIX_TEST)
  81. definitelyIdentityMatrix = false;
  82. #endif
  83. return M[index];
  84. }
  85. //! Simple operator for linearly accessing every element of the matrix.
  86. const T &operator[](u32 index) const { return M[index]; }
  87. //! Sets this matrix equal to the other matrix.
  88. CMatrix4<T> &operator=(const CMatrix4<T> &other) = default;
  89. //! Sets all elements of this matrix to the value.
  90. inline CMatrix4<T> &operator=(const T &scalar);
  91. //! Returns pointer to internal array
  92. const T *pointer() const { return M; }
  93. T *pointer()
  94. {
  95. #if defined(USE_MATRIX_TEST)
  96. definitelyIdentityMatrix = false;
  97. #endif
  98. return M;
  99. }
  100. //! Returns true if other matrix is equal to this matrix.
  101. constexpr bool operator==(const CMatrix4<T> &other) const
  102. {
  103. #if defined(USE_MATRIX_TEST)
  104. if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
  105. return true;
  106. #endif
  107. for (s32 i = 0; i < 16; ++i)
  108. if (M[i] != other.M[i])
  109. return false;
  110. return true;
  111. }
  112. //! Returns true if other matrix is not equal to this matrix.
  113. constexpr bool operator!=(const CMatrix4<T> &other) const
  114. {
  115. return !(*this == other);
  116. }
  117. //! Add another matrix.
  118. CMatrix4<T> operator+(const CMatrix4<T> &other) const;
  119. //! Add another matrix.
  120. CMatrix4<T> &operator+=(const CMatrix4<T> &other);
  121. //! Subtract another matrix.
  122. CMatrix4<T> operator-(const CMatrix4<T> &other) const;
  123. //! Subtract another matrix.
  124. CMatrix4<T> &operator-=(const CMatrix4<T> &other);
  125. //! set this matrix to the product of two matrices
  126. /** Calculate b*a */
  127. inline CMatrix4<T> &setbyproduct(const CMatrix4<T> &other_a, const CMatrix4<T> &other_b);
  128. //! Set this matrix to the product of two matrices
  129. /** Calculate b*a, no optimization used,
  130. use it if you know you never have an identity matrix */
  131. CMatrix4<T> &setbyproduct_nocheck(const CMatrix4<T> &other_a, const CMatrix4<T> &other_b);
  132. //! Multiply by another matrix.
  133. /** Calculate other*this */
  134. CMatrix4<T> operator*(const CMatrix4<T> &other) const;
  135. //! Multiply by another matrix.
  136. /** Like calling: (*this) = (*this) * other
  137. */
  138. CMatrix4<T> &operator*=(const CMatrix4<T> &other);
  139. //! Multiply by scalar.
  140. CMatrix4<T> operator*(const T &scalar) const;
  141. //! Multiply by scalar.
  142. CMatrix4<T> &operator*=(const T &scalar);
  143. //! Set matrix to identity.
  144. inline CMatrix4<T> &makeIdentity();
  145. //! Returns true if the matrix is the identity matrix
  146. inline bool isIdentity() const;
  147. //! Returns true if the matrix is orthogonal
  148. inline bool isOrthogonal() const;
  149. //! Returns true if the matrix is the identity matrix
  150. bool isIdentity_integer_base() const;
  151. //! Set the translation of the current matrix. Will erase any previous values.
  152. CMatrix4<T> &setTranslation(const vector3d<T> &translation);
  153. //! Gets the current translation
  154. vector3d<T> getTranslation() const;
  155. //! Set the inverse translation of the current matrix. Will erase any previous values.
  156. CMatrix4<T> &setInverseTranslation(const vector3d<T> &translation);
  157. //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
  158. inline CMatrix4<T> &setRotationRadians(const vector3d<T> &rotation);
  159. //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
  160. CMatrix4<T> &setRotationDegrees(const vector3d<T> &rotation);
  161. //! Get the rotation, as set by setRotation() when you already know the scale used to create the matrix
  162. /** NOTE: The scale needs to be the correct one used to create this matrix.
  163. You can _not_ use the result of getScale(), but have to save your scale
  164. variable in another place (like ISceneNode does).
  165. NOTE: No scale value can be 0 or the result is undefined.
  166. NOTE: It does not necessarily return the *same* Euler angles as those set by setRotationDegrees(),
  167. but the rotation will be equivalent, i.e. will have the same result when used to rotate a vector or node.
  168. NOTE: It will (usually) give wrong results when further transformations have been added in the matrix (like shear).
  169. WARNING: There have been troubles with this function over the years and we may still have missed some corner cases.
  170. It's generally safer to keep the rotation and scale you used to create the matrix around and work with those.
  171. */
  172. core::vector3d<T> getRotationDegrees(const vector3d<T> &scale) const;
  173. //! Returns the rotation, as set by setRotation().
  174. /** NOTE: You will have the same end-rotation as used in setRotation, but it might not use the same axis values.
  175. NOTE: This only works correct if no other matrix operations have been done on the inner 3x3 matrix besides
  176. setting rotation (so no scale/shear). Thought it (probably) works as long as scale doesn't flip handedness.
  177. NOTE: It does not necessarily return the *same* Euler angles as those set by setRotationDegrees(),
  178. but the rotation will be equivalent, i.e. will have the same result when used to rotate a vector or node.
  179. */
  180. core::vector3d<T> getRotationDegrees() const;
  181. //! Make an inverted rotation matrix from Euler angles.
  182. /** The 4th row and column are unmodified. */
  183. inline CMatrix4<T> &setInverseRotationRadians(const vector3d<T> &rotation);
  184. //! Make an inverted rotation matrix from Euler angles.
  185. /** The 4th row and column are unmodified. */
  186. inline CMatrix4<T> &setInverseRotationDegrees(const vector3d<T> &rotation);
  187. //! Make a rotation matrix from angle and axis, assuming left handed rotation.
  188. /** The 4th row and column are unmodified. */
  189. inline CMatrix4<T> &setRotationAxisRadians(const T &angle, const vector3d<T> &axis);
  190. //! Set Scale
  191. CMatrix4<T> &setScale(const vector3d<T> &scale);
  192. //! Set Scale
  193. CMatrix4<T> &setScale(const T scale) { return setScale(core::vector3d<T>(scale, scale, scale)); }
  194. //! Get Scale
  195. core::vector3d<T> getScale() const;
  196. //! Translate a vector by the inverse of the translation part of this matrix.
  197. void inverseTranslateVect(vector3df &vect) const;
  198. //! Rotate a vector by the inverse of the rotation part of this matrix.
  199. void inverseRotateVect(vector3df &vect) const;
  200. //! Rotate a vector by the rotation part of this matrix.
  201. void rotateVect(vector3df &vect) const;
  202. //! An alternate transform vector method, writing into a second vector
  203. void rotateVect(core::vector3df &out, const core::vector3df &in) const;
  204. //! An alternate transform vector method, writing into an array of 3 floats
  205. void rotateVect(T *out, const core::vector3df &in) const;
  206. //! Transforms the vector by this matrix
  207. /** This operation is performed as if the vector was 4d with the 4th component =1 */
  208. void transformVect(vector3df &vect) const;
  209. //! Transforms input vector by this matrix and stores result in output vector
  210. /** This operation is performed as if the vector was 4d with the 4th component =1 */
  211. void transformVect(vector3df &out, const vector3df &in) const;
  212. //! An alternate transform vector method, writing into an array of 4 floats
  213. /** This operation is performed as if the vector was 4d with the 4th component =1.
  214. NOTE: out[3] will be written to (4th vector component)*/
  215. void transformVect(T *out, const core::vector3df &in) const;
  216. //! An alternate transform vector method, reading from and writing to an array of 3 floats
  217. /** This operation is performed as if the vector was 4d with the 4th component =1
  218. NOTE: out[3] will be written to (4th vector component)*/
  219. void transformVec3(T *out, const T *in) const;
  220. //! An alternate transform vector method, reading from and writing to an array of 4 floats
  221. void transformVec4(T *out, const T *in) const;
  222. //! Translate a vector by the translation part of this matrix.
  223. /** This operation is performed as if the vector was 4d with the 4th component =1 */
  224. void translateVect(vector3df &vect) const;
  225. //! Transforms a plane by this matrix
  226. void transformPlane(core::plane3d<f32> &plane) const;
  227. //! Transforms a plane by this matrix
  228. void transformPlane(const core::plane3d<f32> &in, core::plane3d<f32> &out) const;
  229. //! Transforms a axis aligned bounding box
  230. void transformBoxEx(core::aabbox3d<f32> &box) const;
  231. //! Multiplies this matrix by a 1x4 matrix
  232. void multiplyWith1x4Matrix(T *matrix) const;
  233. //! Calculates inverse of matrix. Slow.
  234. /** \return Returns false if there is no inverse matrix.*/
  235. bool makeInverse();
  236. //! Inverts a primitive matrix which only contains a translation and a rotation
  237. /** \param out: where result matrix is written to. */
  238. bool getInversePrimitive(CMatrix4<T> &out) const;
  239. //! Gets the inverse matrix of this one
  240. /** \param out: where result matrix is written to.
  241. \return Returns false if there is no inverse matrix. */
  242. bool getInverse(CMatrix4<T> &out) const;
  243. //! Builds a right-handed perspective projection matrix based on a field of view
  244. //\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).
  245. CMatrix4<T> &buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero = true);
  246. //! Builds a left-handed perspective projection matrix based on a field of view
  247. CMatrix4<T> &buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero = true);
  248. //! Builds a left-handed perspective projection matrix based on a field of view, with far plane at infinity
  249. CMatrix4<T> &buildProjectionMatrixPerspectiveFovInfinityLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon = 0);
  250. //! Builds a right-handed perspective projection matrix.
  251. CMatrix4<T> &buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero = true);
  252. //! Builds a left-handed perspective projection matrix.
  253. CMatrix4<T> &buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero = true);
  254. //! Builds a left-handed orthogonal projection matrix.
  255. //\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).
  256. CMatrix4<T> &buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero = true);
  257. //! Builds a right-handed orthogonal projection matrix.
  258. CMatrix4<T> &buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero = true);
  259. //! Builds a left-handed look-at matrix.
  260. CMatrix4<T> &buildCameraLookAtMatrixLH(
  261. const vector3df &position,
  262. const vector3df &target,
  263. const vector3df &upVector);
  264. //! Builds a right-handed look-at matrix.
  265. CMatrix4<T> &buildCameraLookAtMatrixRH(
  266. const vector3df &position,
  267. const vector3df &target,
  268. const vector3df &upVector);
  269. //! Builds a matrix that flattens geometry into a plane.
  270. /** \param light: light source
  271. \param plane: plane into which the geometry if flattened into
  272. \param point: value between 0 and 1, describing the light source.
  273. If this is 1, it is a point light, if it is 0, it is a directional light. */
  274. CMatrix4<T> &buildShadowMatrix(const core::vector3df &light, core::plane3df plane, f32 point = 1.0f);
  275. //! Builds a matrix which transforms a normalized Device Coordinate to Device Coordinates.
  276. /** Used to scale <-1,-1><1,1> to viewport, for example from <-1,-1> <1,1> to the viewport <0,0><0,640> */
  277. CMatrix4<T> &buildNDCToDCMatrix(const core::rect<s32> &area, f32 zScale);
  278. //! Creates a new matrix as interpolated matrix from two other ones.
  279. /** \param b: other matrix to interpolate with
  280. \param time: Must be a value between 0 and 1. */
  281. CMatrix4<T> interpolate(const core::CMatrix4<T> &b, f32 time) const;
  282. //! Gets transposed matrix
  283. CMatrix4<T> getTransposed() const;
  284. //! Gets transposed matrix
  285. inline void getTransposed(CMatrix4<T> &dest) const;
  286. //! Builds a matrix that rotates from one vector to another
  287. /** \param from: vector to rotate from
  288. \param to: vector to rotate to
  289. */
  290. CMatrix4<T> &buildRotateFromTo(const core::vector3df &from, const core::vector3df &to);
  291. //! Builds a combined matrix which translates to a center before rotation and translates from origin afterwards
  292. /** \param center Position to rotate around
  293. \param translate Translation applied after the rotation
  294. */
  295. void setRotationCenter(const core::vector3df &center, const core::vector3df &translate);
  296. //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis
  297. /** \param camPos: viewer position in world coo
  298. \param center: object position in world-coo and rotation pivot
  299. \param translation: object final translation from center
  300. \param axis: axis to rotate about
  301. \param from: source vector to rotate from
  302. */
  303. void buildAxisAlignedBillboard(const core::vector3df &camPos,
  304. const core::vector3df &center,
  305. const core::vector3df &translation,
  306. const core::vector3df &axis,
  307. const core::vector3df &from);
  308. /*
  309. construct 2D Texture transformations
  310. rotate about center, scale, and transform.
  311. */
  312. //! Set to a texture transformation matrix with the given parameters.
  313. CMatrix4<T> &buildTextureTransform(f32 rotateRad,
  314. const core::vector2df &rotatecenter,
  315. const core::vector2df &translate,
  316. const core::vector2df &scale);
  317. //! Set texture transformation rotation
  318. /** Rotate about z axis, recenter at (0.5,0.5).
  319. Doesn't clear other elements than those affected
  320. \param radAngle Angle in radians
  321. \return Altered matrix */
  322. CMatrix4<T> &setTextureRotationCenter(f32 radAngle);
  323. //! Set texture transformation translation
  324. /** Doesn't clear other elements than those affected.
  325. \param x Offset on x axis
  326. \param y Offset on y axis
  327. \return Altered matrix */
  328. CMatrix4<T> &setTextureTranslate(f32 x, f32 y);
  329. //! Get texture transformation translation
  330. /** \param x returns offset on x axis
  331. \param y returns offset on y axis */
  332. void getTextureTranslate(f32 &x, f32 &y) const;
  333. //! Set texture transformation translation, using a transposed representation
  334. /** Doesn't clear other elements than those affected.
  335. \param x Offset on x axis
  336. \param y Offset on y axis
  337. \return Altered matrix */
  338. CMatrix4<T> &setTextureTranslateTransposed(f32 x, f32 y);
  339. //! Set texture transformation scale
  340. /** Doesn't clear other elements than those affected.
  341. \param sx Scale factor on x axis
  342. \param sy Scale factor on y axis
  343. \return Altered matrix. */
  344. CMatrix4<T> &setTextureScale(f32 sx, f32 sy);
  345. //! Get texture transformation scale
  346. /** \param sx Returns x axis scale factor
  347. \param sy Returns y axis scale factor */
  348. void getTextureScale(f32 &sx, f32 &sy) const;
  349. //! Set texture transformation scale, and recenter at (0.5,0.5)
  350. /** Doesn't clear other elements than those affected.
  351. \param sx Scale factor on x axis
  352. \param sy Scale factor on y axis
  353. \return Altered matrix. */
  354. CMatrix4<T> &setTextureScaleCenter(f32 sx, f32 sy);
  355. //! Sets all matrix data members at once
  356. CMatrix4<T> &setM(const T *data);
  357. //! Sets if the matrix is definitely identity matrix
  358. void setDefinitelyIdentityMatrix(bool isDefinitelyIdentityMatrix);
  359. //! Gets if the matrix is definitely identity matrix
  360. bool getDefinitelyIdentityMatrix() const;
  361. //! Compare two matrices using the equal method
  362. bool equals(const core::CMatrix4<T> &other, const T tolerance = (T)ROUNDING_ERROR_f64) const;
  363. private:
  364. //! Matrix data, stored in row-major order
  365. T M[16];
  366. #if defined(USE_MATRIX_TEST)
  367. //! Flag is this matrix is identity matrix
  368. mutable u32 definitelyIdentityMatrix;
  369. #endif
  370. };
  371. // Default constructor
  372. template <class T>
  373. inline CMatrix4<T>::CMatrix4(eConstructor constructor)
  374. #if defined(USE_MATRIX_TEST)
  375. :
  376. definitelyIdentityMatrix(BIT_UNTESTED)
  377. #endif
  378. {
  379. switch (constructor) {
  380. case EM4CONST_NOTHING:
  381. case EM4CONST_COPY:
  382. break;
  383. case EM4CONST_IDENTITY:
  384. case EM4CONST_INVERSE:
  385. default:
  386. makeIdentity();
  387. break;
  388. }
  389. }
  390. // Copy constructor
  391. template <class T>
  392. inline CMatrix4<T>::CMatrix4(const CMatrix4<T> &other, eConstructor constructor)
  393. #if defined(USE_MATRIX_TEST)
  394. :
  395. definitelyIdentityMatrix(BIT_UNTESTED)
  396. #endif
  397. {
  398. switch (constructor) {
  399. case EM4CONST_IDENTITY:
  400. makeIdentity();
  401. break;
  402. case EM4CONST_NOTHING:
  403. break;
  404. case EM4CONST_COPY:
  405. *this = other;
  406. break;
  407. case EM4CONST_TRANSPOSED:
  408. other.getTransposed(*this);
  409. break;
  410. case EM4CONST_INVERSE:
  411. if (!other.getInverse(*this))
  412. memset(M, 0, 16 * sizeof(T));
  413. break;
  414. case EM4CONST_INVERSE_TRANSPOSED:
  415. if (!other.getInverse(*this))
  416. memset(M, 0, 16 * sizeof(T));
  417. else
  418. *this = getTransposed();
  419. break;
  420. }
  421. }
  422. //! Add another matrix.
  423. template <class T>
  424. inline CMatrix4<T> CMatrix4<T>::operator+(const CMatrix4<T> &other) const
  425. {
  426. CMatrix4<T> temp(EM4CONST_NOTHING);
  427. temp[0] = M[0] + other[0];
  428. temp[1] = M[1] + other[1];
  429. temp[2] = M[2] + other[2];
  430. temp[3] = M[3] + other[3];
  431. temp[4] = M[4] + other[4];
  432. temp[5] = M[5] + other[5];
  433. temp[6] = M[6] + other[6];
  434. temp[7] = M[7] + other[7];
  435. temp[8] = M[8] + other[8];
  436. temp[9] = M[9] + other[9];
  437. temp[10] = M[10] + other[10];
  438. temp[11] = M[11] + other[11];
  439. temp[12] = M[12] + other[12];
  440. temp[13] = M[13] + other[13];
  441. temp[14] = M[14] + other[14];
  442. temp[15] = M[15] + other[15];
  443. return temp;
  444. }
  445. //! Add another matrix.
  446. template <class T>
  447. inline CMatrix4<T> &CMatrix4<T>::operator+=(const CMatrix4<T> &other)
  448. {
  449. M[0] += other[0];
  450. M[1] += other[1];
  451. M[2] += other[2];
  452. M[3] += other[3];
  453. M[4] += other[4];
  454. M[5] += other[5];
  455. M[6] += other[6];
  456. M[7] += other[7];
  457. M[8] += other[8];
  458. M[9] += other[9];
  459. M[10] += other[10];
  460. M[11] += other[11];
  461. M[12] += other[12];
  462. M[13] += other[13];
  463. M[14] += other[14];
  464. M[15] += other[15];
  465. return *this;
  466. }
  467. //! Subtract another matrix.
  468. template <class T>
  469. inline CMatrix4<T> CMatrix4<T>::operator-(const CMatrix4<T> &other) const
  470. {
  471. CMatrix4<T> temp(EM4CONST_NOTHING);
  472. temp[0] = M[0] - other[0];
  473. temp[1] = M[1] - other[1];
  474. temp[2] = M[2] - other[2];
  475. temp[3] = M[3] - other[3];
  476. temp[4] = M[4] - other[4];
  477. temp[5] = M[5] - other[5];
  478. temp[6] = M[6] - other[6];
  479. temp[7] = M[7] - other[7];
  480. temp[8] = M[8] - other[8];
  481. temp[9] = M[9] - other[9];
  482. temp[10] = M[10] - other[10];
  483. temp[11] = M[11] - other[11];
  484. temp[12] = M[12] - other[12];
  485. temp[13] = M[13] - other[13];
  486. temp[14] = M[14] - other[14];
  487. temp[15] = M[15] - other[15];
  488. return temp;
  489. }
  490. //! Subtract another matrix.
  491. template <class T>
  492. inline CMatrix4<T> &CMatrix4<T>::operator-=(const CMatrix4<T> &other)
  493. {
  494. M[0] -= other[0];
  495. M[1] -= other[1];
  496. M[2] -= other[2];
  497. M[3] -= other[3];
  498. M[4] -= other[4];
  499. M[5] -= other[5];
  500. M[6] -= other[6];
  501. M[7] -= other[7];
  502. M[8] -= other[8];
  503. M[9] -= other[9];
  504. M[10] -= other[10];
  505. M[11] -= other[11];
  506. M[12] -= other[12];
  507. M[13] -= other[13];
  508. M[14] -= other[14];
  509. M[15] -= other[15];
  510. return *this;
  511. }
  512. //! Multiply by scalar.
  513. template <class T>
  514. inline CMatrix4<T> CMatrix4<T>::operator*(const T &scalar) const
  515. {
  516. CMatrix4<T> temp(EM4CONST_NOTHING);
  517. temp[0] = M[0] * scalar;
  518. temp[1] = M[1] * scalar;
  519. temp[2] = M[2] * scalar;
  520. temp[3] = M[3] * scalar;
  521. temp[4] = M[4] * scalar;
  522. temp[5] = M[5] * scalar;
  523. temp[6] = M[6] * scalar;
  524. temp[7] = M[7] * scalar;
  525. temp[8] = M[8] * scalar;
  526. temp[9] = M[9] * scalar;
  527. temp[10] = M[10] * scalar;
  528. temp[11] = M[11] * scalar;
  529. temp[12] = M[12] * scalar;
  530. temp[13] = M[13] * scalar;
  531. temp[14] = M[14] * scalar;
  532. temp[15] = M[15] * scalar;
  533. return temp;
  534. }
  535. //! Multiply by scalar.
  536. template <class T>
  537. inline CMatrix4<T> &CMatrix4<T>::operator*=(const T &scalar)
  538. {
  539. M[0] *= scalar;
  540. M[1] *= scalar;
  541. M[2] *= scalar;
  542. M[3] *= scalar;
  543. M[4] *= scalar;
  544. M[5] *= scalar;
  545. M[6] *= scalar;
  546. M[7] *= scalar;
  547. M[8] *= scalar;
  548. M[9] *= scalar;
  549. M[10] *= scalar;
  550. M[11] *= scalar;
  551. M[12] *= scalar;
  552. M[13] *= scalar;
  553. M[14] *= scalar;
  554. M[15] *= scalar;
  555. return *this;
  556. }
  557. //! Multiply by another matrix.
  558. template <class T>
  559. inline CMatrix4<T> &CMatrix4<T>::operator*=(const CMatrix4<T> &other)
  560. {
  561. #if defined(USE_MATRIX_TEST)
  562. // do checks on your own in order to avoid copy creation
  563. if (!other.isIdentity()) {
  564. if (this->isIdentity()) {
  565. return (*this = other);
  566. } else {
  567. CMatrix4<T> temp(*this);
  568. return setbyproduct_nocheck(temp, other);
  569. }
  570. }
  571. return *this;
  572. #else
  573. CMatrix4<T> temp(*this);
  574. return setbyproduct_nocheck(temp, other);
  575. #endif
  576. }
  577. //! multiply by another matrix
  578. // set this matrix to the product of two other matrices
  579. // goal is to reduce stack use and copy
  580. template <class T>
  581. inline CMatrix4<T> &CMatrix4<T>::setbyproduct_nocheck(const CMatrix4<T> &other_a, const CMatrix4<T> &other_b)
  582. {
  583. const T *m1 = other_a.M;
  584. const T *m2 = other_b.M;
  585. M[0] = m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3];
  586. M[1] = m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3];
  587. M[2] = m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3];
  588. M[3] = m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3];
  589. M[4] = m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7];
  590. M[5] = m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7];
  591. M[6] = m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7];
  592. M[7] = m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7];
  593. M[8] = m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11];
  594. M[9] = m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11];
  595. M[10] = m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11];
  596. M[11] = m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11];
  597. M[12] = m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15];
  598. M[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15];
  599. M[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15];
  600. M[15] = m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15];
  601. #if defined(USE_MATRIX_TEST)
  602. definitelyIdentityMatrix = false;
  603. #endif
  604. return *this;
  605. }
  606. //! multiply by another matrix
  607. // set this matrix to the product of two other matrices
  608. // goal is to reduce stack use and copy
  609. template <class T>
  610. inline CMatrix4<T> &CMatrix4<T>::setbyproduct(const CMatrix4<T> &other_a, const CMatrix4<T> &other_b)
  611. {
  612. #if defined(USE_MATRIX_TEST)
  613. if (other_a.isIdentity())
  614. return (*this = other_b);
  615. else if (other_b.isIdentity())
  616. return (*this = other_a);
  617. else
  618. return setbyproduct_nocheck(other_a, other_b);
  619. #else
  620. return setbyproduct_nocheck(other_a, other_b);
  621. #endif
  622. }
  623. //! multiply by another matrix
  624. template <class T>
  625. inline CMatrix4<T> CMatrix4<T>::operator*(const CMatrix4<T> &m2) const
  626. {
  627. #if defined(USE_MATRIX_TEST)
  628. // Testing purpose..
  629. if (this->isIdentity())
  630. return m2;
  631. if (m2.isIdentity())
  632. return *this;
  633. #endif
  634. CMatrix4<T> m3(EM4CONST_NOTHING);
  635. const T *m1 = M;
  636. m3[0] = m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3];
  637. m3[1] = m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3];
  638. m3[2] = m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3];
  639. m3[3] = m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3];
  640. m3[4] = m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7];
  641. m3[5] = m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7];
  642. m3[6] = m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7];
  643. m3[7] = m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7];
  644. m3[8] = m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11];
  645. m3[9] = m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11];
  646. m3[10] = m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11];
  647. m3[11] = m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11];
  648. m3[12] = m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15];
  649. m3[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15];
  650. m3[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15];
  651. m3[15] = m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15];
  652. return m3;
  653. }
  654. template <class T>
  655. inline vector3d<T> CMatrix4<T>::getTranslation() const
  656. {
  657. return vector3d<T>(M[12], M[13], M[14]);
  658. }
  659. template <class T>
  660. inline CMatrix4<T> &CMatrix4<T>::setTranslation(const vector3d<T> &translation)
  661. {
  662. M[12] = translation.X;
  663. M[13] = translation.Y;
  664. M[14] = translation.Z;
  665. #if defined(USE_MATRIX_TEST)
  666. definitelyIdentityMatrix = false;
  667. #endif
  668. return *this;
  669. }
  670. template <class T>
  671. inline CMatrix4<T> &CMatrix4<T>::setInverseTranslation(const vector3d<T> &translation)
  672. {
  673. M[12] = -translation.X;
  674. M[13] = -translation.Y;
  675. M[14] = -translation.Z;
  676. #if defined(USE_MATRIX_TEST)
  677. definitelyIdentityMatrix = false;
  678. #endif
  679. return *this;
  680. }
  681. template <class T>
  682. inline CMatrix4<T> &CMatrix4<T>::setScale(const vector3d<T> &scale)
  683. {
  684. M[0] = scale.X;
  685. M[5] = scale.Y;
  686. M[10] = scale.Z;
  687. #if defined(USE_MATRIX_TEST)
  688. definitelyIdentityMatrix = false;
  689. #endif
  690. return *this;
  691. }
  692. //! Returns the absolute values of the scales of the matrix.
  693. /**
  694. Note: You only get back original values if the matrix only set the scale.
  695. Otherwise the result is a scale you can use to normalize the matrix axes,
  696. but it's usually no longer what you did set with setScale.
  697. */
  698. template <class T>
  699. inline vector3d<T> CMatrix4<T>::getScale() const
  700. {
  701. // See http://www.robertblum.com/articles/2005/02/14/decomposing-matrices
  702. // Deal with the 0 rotation case first
  703. // Prior to Irrlicht 1.6, we always returned this value.
  704. if (core::iszero(M[1]) && core::iszero(M[2]) &&
  705. core::iszero(M[4]) && core::iszero(M[6]) &&
  706. core::iszero(M[8]) && core::iszero(M[9]))
  707. return vector3d<T>(M[0], M[5], M[10]);
  708. // We have to do the full calculation.
  709. return vector3d<T>(sqrtf(M[0] * M[0] + M[1] * M[1] + M[2] * M[2]),
  710. sqrtf(M[4] * M[4] + M[5] * M[5] + M[6] * M[6]),
  711. sqrtf(M[8] * M[8] + M[9] * M[9] + M[10] * M[10]));
  712. }
  713. template <class T>
  714. inline CMatrix4<T> &CMatrix4<T>::setRotationDegrees(const vector3d<T> &rotation)
  715. {
  716. return setRotationRadians(rotation * core::DEGTORAD);
  717. }
  718. template <class T>
  719. inline CMatrix4<T> &CMatrix4<T>::setInverseRotationDegrees(const vector3d<T> &rotation)
  720. {
  721. return setInverseRotationRadians(rotation * core::DEGTORAD);
  722. }
  723. template <class T>
  724. inline CMatrix4<T> &CMatrix4<T>::setRotationRadians(const vector3d<T> &rotation)
  725. {
  726. const f64 cr = cos(rotation.X);
  727. const f64 sr = sin(rotation.X);
  728. const f64 cp = cos(rotation.Y);
  729. const f64 sp = sin(rotation.Y);
  730. const f64 cy = cos(rotation.Z);
  731. const f64 sy = sin(rotation.Z);
  732. M[0] = (T)(cp * cy);
  733. M[1] = (T)(cp * sy);
  734. M[2] = (T)(-sp);
  735. const f64 srsp = sr * sp;
  736. const f64 crsp = cr * sp;
  737. M[4] = (T)(srsp * cy - cr * sy);
  738. M[5] = (T)(srsp * sy + cr * cy);
  739. M[6] = (T)(sr * cp);
  740. M[8] = (T)(crsp * cy + sr * sy);
  741. M[9] = (T)(crsp * sy - sr * cy);
  742. M[10] = (T)(cr * cp);
  743. #if defined(USE_MATRIX_TEST)
  744. definitelyIdentityMatrix = false;
  745. #endif
  746. return *this;
  747. }
  748. //! Returns a rotation which (mostly) works in combination with the given scale
  749. /**
  750. This code was originally written by by Chev (assuming no scaling back then,
  751. we can be blamed for all problems added by regarding scale)
  752. */
  753. template <class T>
  754. inline core::vector3d<T> CMatrix4<T>::getRotationDegrees(const vector3d<T> &scale_) const
  755. {
  756. const CMatrix4<T> &mat = *this;
  757. const core::vector3d<f64> scale(core::iszero(scale_.X) ? FLT_MAX : scale_.X, core::iszero(scale_.Y) ? FLT_MAX : scale_.Y, core::iszero(scale_.Z) ? FLT_MAX : scale_.Z);
  758. const core::vector3d<f64> invScale(core::reciprocal(scale.X), core::reciprocal(scale.Y), core::reciprocal(scale.Z));
  759. f64 Y = -asin(core::clamp(mat[2] * invScale.X, -1.0, 1.0));
  760. const f64 C = cos(Y);
  761. Y *= RADTODEG64;
  762. f64 rotx, roty, X, Z;
  763. if (!core::iszero((T)C)) {
  764. const f64 invC = core::reciprocal(C);
  765. rotx = mat[10] * invC * invScale.Z;
  766. roty = mat[6] * invC * invScale.Y;
  767. X = atan2(roty, rotx) * RADTODEG64;
  768. rotx = mat[0] * invC * invScale.X;
  769. roty = mat[1] * invC * invScale.X;
  770. Z = atan2(roty, rotx) * RADTODEG64;
  771. } else {
  772. X = 0.0;
  773. rotx = mat[5] * invScale.Y;
  774. roty = -mat[4] * invScale.Y;
  775. Z = atan2(roty, rotx) * RADTODEG64;
  776. }
  777. // fix values that get below zero
  778. if (X < 0.0)
  779. X += 360.0;
  780. if (Y < 0.0)
  781. Y += 360.0;
  782. if (Z < 0.0)
  783. Z += 360.0;
  784. return vector3d<T>((T)X, (T)Y, (T)Z);
  785. }
  786. //! Returns a rotation that is equivalent to that set by setRotationDegrees().
  787. template <class T>
  788. inline core::vector3d<T> CMatrix4<T>::getRotationDegrees() const
  789. {
  790. // Note: Using getScale() here make it look like it could do matrix decomposition.
  791. // It can't! It works (or should work) as long as rotation doesn't flip the handedness
  792. // aka scale swapping 1 or 3 axes. (I think we could catch that as well by comparing
  793. // crossproduct of first 2 axes to direction of third axis, but TODO)
  794. // And maybe it should also offer the solution for the simple calculation
  795. // without regarding scaling as Irrlicht did before 1.7
  796. core::vector3d<T> scale(getScale());
  797. // We assume the matrix uses rotations instead of negative scaling 2 axes.
  798. // Otherwise it fails even for some simple cases, like rotating around
  799. // 2 axes by 180° which getScale thinks is a negative scaling.
  800. if (scale.Y < 0 && scale.Z < 0) {
  801. scale.Y = -scale.Y;
  802. scale.Z = -scale.Z;
  803. } else if (scale.X < 0 && scale.Z < 0) {
  804. scale.X = -scale.X;
  805. scale.Z = -scale.Z;
  806. } else if (scale.X < 0 && scale.Y < 0) {
  807. scale.X = -scale.X;
  808. scale.Y = -scale.Y;
  809. }
  810. return getRotationDegrees(scale);
  811. }
  812. //! Sets matrix to rotation matrix of inverse angles given as parameters
  813. template <class T>
  814. inline CMatrix4<T> &CMatrix4<T>::setInverseRotationRadians(const vector3d<T> &rotation)
  815. {
  816. f64 cr = cos(rotation.X);
  817. f64 sr = sin(rotation.X);
  818. f64 cp = cos(rotation.Y);
  819. f64 sp = sin(rotation.Y);
  820. f64 cy = cos(rotation.Z);
  821. f64 sy = sin(rotation.Z);
  822. M[0] = (T)(cp * cy);
  823. M[4] = (T)(cp * sy);
  824. M[8] = (T)(-sp);
  825. f64 srsp = sr * sp;
  826. f64 crsp = cr * sp;
  827. M[1] = (T)(srsp * cy - cr * sy);
  828. M[5] = (T)(srsp * sy + cr * cy);
  829. M[9] = (T)(sr * cp);
  830. M[2] = (T)(crsp * cy + sr * sy);
  831. M[6] = (T)(crsp * sy - sr * cy);
  832. M[10] = (T)(cr * cp);
  833. #if defined(USE_MATRIX_TEST)
  834. definitelyIdentityMatrix = false;
  835. #endif
  836. return *this;
  837. }
  838. //! Sets matrix to rotation matrix defined by axis and angle, assuming LH rotation
  839. template <class T>
  840. inline CMatrix4<T> &CMatrix4<T>::setRotationAxisRadians(const T &angle, const vector3d<T> &axis)
  841. {
  842. const f64 c = cos(angle);
  843. const f64 s = sin(angle);
  844. const f64 t = 1.0 - c;
  845. const f64 tx = t * axis.X;
  846. const f64 ty = t * axis.Y;
  847. const f64 tz = t * axis.Z;
  848. const f64 sx = s * axis.X;
  849. const f64 sy = s * axis.Y;
  850. const f64 sz = s * axis.Z;
  851. M[0] = (T)(tx * axis.X + c);
  852. M[1] = (T)(tx * axis.Y + sz);
  853. M[2] = (T)(tx * axis.Z - sy);
  854. M[4] = (T)(ty * axis.X - sz);
  855. M[5] = (T)(ty * axis.Y + c);
  856. M[6] = (T)(ty * axis.Z + sx);
  857. M[8] = (T)(tz * axis.X + sy);
  858. M[9] = (T)(tz * axis.Y - sx);
  859. M[10] = (T)(tz * axis.Z + c);
  860. #if defined(USE_MATRIX_TEST)
  861. definitelyIdentityMatrix = false;
  862. #endif
  863. return *this;
  864. }
  865. /*!
  866. */
  867. template <class T>
  868. inline CMatrix4<T> &CMatrix4<T>::makeIdentity()
  869. {
  870. memset(M, 0, 16 * sizeof(T));
  871. M[0] = M[5] = M[10] = M[15] = (T)1;
  872. #if defined(USE_MATRIX_TEST)
  873. definitelyIdentityMatrix = true;
  874. #endif
  875. return *this;
  876. }
  877. /*
  878. check identity with epsilon
  879. solve floating range problems..
  880. */
  881. template <class T>
  882. inline bool CMatrix4<T>::isIdentity() const
  883. {
  884. #if defined(USE_MATRIX_TEST)
  885. if (definitelyIdentityMatrix)
  886. return true;
  887. #endif
  888. 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))
  889. return false;
  890. 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))
  891. return false;
  892. 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))
  893. return false;
  894. 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))
  895. return false;
  896. /*
  897. if (!core::equals( M[ 0], (T)1 ) ||
  898. !core::equals( M[ 5], (T)1 ) ||
  899. !core::equals( M[10], (T)1 ) ||
  900. !core::equals( M[15], (T)1 ))
  901. return false;
  902. for (s32 i=0; i<4; ++i)
  903. for (s32 j=0; j<4; ++j)
  904. if ((j != i) && (!iszero((*this)(i,j))))
  905. return false;
  906. */
  907. #if defined(USE_MATRIX_TEST)
  908. definitelyIdentityMatrix = true;
  909. #endif
  910. return true;
  911. }
  912. /* Check orthogonality of matrix. */
  913. template <class T>
  914. inline bool CMatrix4<T>::isOrthogonal() const
  915. {
  916. T dp = M[0] * M[4] + M[1] * M[5] + M[2] * M[6] + M[3] * M[7];
  917. if (!iszero(dp))
  918. return false;
  919. dp = M[0] * M[8] + M[1] * M[9] + M[2] * M[10] + M[3] * M[11];
  920. if (!iszero(dp))
  921. return false;
  922. dp = M[0] * M[12] + M[1] * M[13] + M[2] * M[14] + M[3] * M[15];
  923. if (!iszero(dp))
  924. return false;
  925. dp = M[4] * M[8] + M[5] * M[9] + M[6] * M[10] + M[7] * M[11];
  926. if (!iszero(dp))
  927. return false;
  928. dp = M[4] * M[12] + M[5] * M[13] + M[6] * M[14] + M[7] * M[15];
  929. if (!iszero(dp))
  930. return false;
  931. dp = M[8] * M[12] + M[9] * M[13] + M[10] * M[14] + M[11] * M[15];
  932. return (iszero(dp));
  933. }
  934. /*
  935. doesn't solve floating range problems..
  936. but takes care on +/- 0 on translation because we are changing it..
  937. reducing floating point branches
  938. but it needs the floats in memory..
  939. */
  940. template <class T>
  941. inline bool CMatrix4<T>::isIdentity_integer_base() const
  942. {
  943. #if defined(USE_MATRIX_TEST)
  944. if (definitelyIdentityMatrix)
  945. return true;
  946. #endif
  947. if (IR(M[0]) != F32_VALUE_1)
  948. return false;
  949. if (IR(M[1]) != 0)
  950. return false;
  951. if (IR(M[2]) != 0)
  952. return false;
  953. if (IR(M[3]) != 0)
  954. return false;
  955. if (IR(M[4]) != 0)
  956. return false;
  957. if (IR(M[5]) != F32_VALUE_1)
  958. return false;
  959. if (IR(M[6]) != 0)
  960. return false;
  961. if (IR(M[7]) != 0)
  962. return false;
  963. if (IR(M[8]) != 0)
  964. return false;
  965. if (IR(M[9]) != 0)
  966. return false;
  967. if (IR(M[10]) != F32_VALUE_1)
  968. return false;
  969. if (IR(M[11]) != 0)
  970. return false;
  971. if (IR(M[12]) != 0)
  972. return false;
  973. if (IR(M[13]) != 0)
  974. return false;
  975. if (IR(M[13]) != 0)
  976. return false;
  977. if (IR(M[15]) != F32_VALUE_1)
  978. return false;
  979. #if defined(USE_MATRIX_TEST)
  980. definitelyIdentityMatrix = true;
  981. #endif
  982. return true;
  983. }
  984. template <class T>
  985. inline void CMatrix4<T>::rotateVect(vector3df &vect) const
  986. {
  987. vector3d<T> tmp(static_cast<T>(vect.X), static_cast<T>(vect.Y), static_cast<T>(vect.Z));
  988. vect.X = static_cast<f32>(tmp.X * M[0] + tmp.Y * M[4] + tmp.Z * M[8]);
  989. vect.Y = static_cast<f32>(tmp.X * M[1] + tmp.Y * M[5] + tmp.Z * M[9]);
  990. vect.Z = static_cast<f32>(tmp.X * M[2] + tmp.Y * M[6] + tmp.Z * M[10]);
  991. }
  992. //! An alternate transform vector method, writing into a second vector
  993. template <class T>
  994. inline void CMatrix4<T>::rotateVect(core::vector3df &out, const core::vector3df &in) const
  995. {
  996. out.X = in.X * M[0] + in.Y * M[4] + in.Z * M[8];
  997. out.Y = in.X * M[1] + in.Y * M[5] + in.Z * M[9];
  998. out.Z = in.X * M[2] + in.Y * M[6] + in.Z * M[10];
  999. }
  1000. //! An alternate transform vector method, writing into an array of 3 floats
  1001. template <class T>
  1002. inline void CMatrix4<T>::rotateVect(T *out, const core::vector3df &in) const
  1003. {
  1004. out[0] = in.X * M[0] + in.Y * M[4] + in.Z * M[8];
  1005. out[1] = in.X * M[1] + in.Y * M[5] + in.Z * M[9];
  1006. out[2] = in.X * M[2] + in.Y * M[6] + in.Z * M[10];
  1007. }
  1008. template <class T>
  1009. inline void CMatrix4<T>::inverseRotateVect(vector3df &vect) const
  1010. {
  1011. vector3d<T> tmp(static_cast<T>(vect.X), static_cast<T>(vect.Y), static_cast<T>(vect.Z));
  1012. vect.X = static_cast<f32>(tmp.X * M[0] + tmp.Y * M[1] + tmp.Z * M[2]);
  1013. vect.Y = static_cast<f32>(tmp.X * M[4] + tmp.Y * M[5] + tmp.Z * M[6]);
  1014. vect.Z = static_cast<f32>(tmp.X * M[8] + tmp.Y * M[9] + tmp.Z * M[10]);
  1015. }
  1016. template <class T>
  1017. inline void CMatrix4<T>::transformVect(vector3df &vect) const
  1018. {
  1019. T vector[3];
  1020. vector[0] = vect.X * M[0] + vect.Y * M[4] + vect.Z * M[8] + M[12];
  1021. vector[1] = vect.X * M[1] + vect.Y * M[5] + vect.Z * M[9] + M[13];
  1022. vector[2] = vect.X * M[2] + vect.Y * M[6] + vect.Z * M[10] + M[14];
  1023. vect.X = static_cast<f32>(vector[0]);
  1024. vect.Y = static_cast<f32>(vector[1]);
  1025. vect.Z = static_cast<f32>(vector[2]);
  1026. }
  1027. template <class T>
  1028. inline void CMatrix4<T>::transformVect(vector3df &out, const vector3df &in) const
  1029. {
  1030. out.X = in.X * M[0] + in.Y * M[4] + in.Z * M[8] + M[12];
  1031. out.Y = in.X * M[1] + in.Y * M[5] + in.Z * M[9] + M[13];
  1032. out.Z = in.X * M[2] + in.Y * M[6] + in.Z * M[10] + M[14];
  1033. }
  1034. template <class T>
  1035. inline void CMatrix4<T>::transformVect(T *out, const core::vector3df &in) const
  1036. {
  1037. out[0] = in.X * M[0] + in.Y * M[4] + in.Z * M[8] + M[12];
  1038. out[1] = in.X * M[1] + in.Y * M[5] + in.Z * M[9] + M[13];
  1039. out[2] = in.X * M[2] + in.Y * M[6] + in.Z * M[10] + M[14];
  1040. out[3] = in.X * M[3] + in.Y * M[7] + in.Z * M[11] + M[15];
  1041. }
  1042. template <class T>
  1043. inline void CMatrix4<T>::transformVec3(T *out, const T *in) const
  1044. {
  1045. out[0] = in[0] * M[0] + in[1] * M[4] + in[2] * M[8] + M[12];
  1046. out[1] = in[0] * M[1] + in[1] * M[5] + in[2] * M[9] + M[13];
  1047. out[2] = in[0] * M[2] + in[1] * M[6] + in[2] * M[10] + M[14];
  1048. }
  1049. template <class T>
  1050. inline void CMatrix4<T>::transformVec4(T *out, const T *in) const
  1051. {
  1052. out[0] = in[0] * M[0] + in[1] * M[4] + in[2] * M[8] + in[3] * M[12];
  1053. out[1] = in[0] * M[1] + in[1] * M[5] + in[2] * M[9] + in[3] * M[13];
  1054. out[2] = in[0] * M[2] + in[1] * M[6] + in[2] * M[10] + in[3] * M[14];
  1055. out[3] = in[0] * M[3] + in[1] * M[7] + in[2] * M[11] + in[3] * M[15];
  1056. }
  1057. //! Transforms a plane by this matrix
  1058. template <class T>
  1059. inline void CMatrix4<T>::transformPlane(core::plane3d<f32> &plane) const
  1060. {
  1061. vector3df member;
  1062. // Transform the plane member point, i.e. rotate, translate and scale it.
  1063. transformVect(member, plane.getMemberPoint());
  1064. // Transform the normal by the transposed inverse of the matrix
  1065. CMatrix4<T> transposedInverse(*this, EM4CONST_INVERSE_TRANSPOSED);
  1066. vector3df normal = plane.Normal;
  1067. transposedInverse.rotateVect(normal);
  1068. plane.setPlane(member, normal.normalize());
  1069. }
  1070. //! Transforms a plane by this matrix
  1071. template <class T>
  1072. inline void CMatrix4<T>::transformPlane(const core::plane3d<f32> &in, core::plane3d<f32> &out) const
  1073. {
  1074. out = in;
  1075. transformPlane(out);
  1076. }
  1077. //! Transforms a axis aligned bounding box more accurately than transformBox()
  1078. template <class T>
  1079. inline void CMatrix4<T>::transformBoxEx(core::aabbox3d<f32> &box) const
  1080. {
  1081. #if defined(USE_MATRIX_TEST)
  1082. if (isIdentity())
  1083. return;
  1084. #endif
  1085. const f32 Amin[3] = {box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z};
  1086. const f32 Amax[3] = {box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z};
  1087. f32 Bmin[3];
  1088. f32 Bmax[3];
  1089. Bmin[0] = Bmax[0] = M[12];
  1090. Bmin[1] = Bmax[1] = M[13];
  1091. Bmin[2] = Bmax[2] = M[14];
  1092. const CMatrix4<T> &m = *this;
  1093. for (u32 i = 0; i < 3; ++i) {
  1094. for (u32 j = 0; j < 3; ++j) {
  1095. const f32 a = m(j, i) * Amin[j];
  1096. const f32 b = m(j, i) * Amax[j];
  1097. if (a < b) {
  1098. Bmin[i] += a;
  1099. Bmax[i] += b;
  1100. } else {
  1101. Bmin[i] += b;
  1102. Bmax[i] += a;
  1103. }
  1104. }
  1105. }
  1106. box.MinEdge.X = Bmin[0];
  1107. box.MinEdge.Y = Bmin[1];
  1108. box.MinEdge.Z = Bmin[2];
  1109. box.MaxEdge.X = Bmax[0];
  1110. box.MaxEdge.Y = Bmax[1];
  1111. box.MaxEdge.Z = Bmax[2];
  1112. }
  1113. //! Multiplies this matrix by a 1x4 matrix
  1114. template <class T>
  1115. inline void CMatrix4<T>::multiplyWith1x4Matrix(T *matrix) const
  1116. {
  1117. /*
  1118. 0 1 2 3
  1119. 4 5 6 7
  1120. 8 9 10 11
  1121. 12 13 14 15
  1122. */
  1123. T mat[4];
  1124. mat[0] = matrix[0];
  1125. mat[1] = matrix[1];
  1126. mat[2] = matrix[2];
  1127. mat[3] = matrix[3];
  1128. matrix[0] = M[0] * mat[0] + M[4] * mat[1] + M[8] * mat[2] + M[12] * mat[3];
  1129. matrix[1] = M[1] * mat[0] + M[5] * mat[1] + M[9] * mat[2] + M[13] * mat[3];
  1130. matrix[2] = M[2] * mat[0] + M[6] * mat[1] + M[10] * mat[2] + M[14] * mat[3];
  1131. matrix[3] = M[3] * mat[0] + M[7] * mat[1] + M[11] * mat[2] + M[15] * mat[3];
  1132. }
  1133. template <class T>
  1134. inline void CMatrix4<T>::inverseTranslateVect(vector3df &vect) const
  1135. {
  1136. vect.X = vect.X - M[12];
  1137. vect.Y = vect.Y - M[13];
  1138. vect.Z = vect.Z - M[14];
  1139. }
  1140. template <class T>
  1141. inline void CMatrix4<T>::translateVect(vector3df &vect) const
  1142. {
  1143. vect.X = vect.X + M[12];
  1144. vect.Y = vect.Y + M[13];
  1145. vect.Z = vect.Z + M[14];
  1146. }
  1147. template <class T>
  1148. inline bool CMatrix4<T>::getInverse(CMatrix4<T> &out) const
  1149. {
  1150. /// Calculates the inverse of this Matrix
  1151. /// The inverse is calculated using Cramers rule.
  1152. /// If no inverse exists then 'false' is returned.
  1153. #if defined(USE_MATRIX_TEST)
  1154. if (this->isIdentity()) {
  1155. out = *this;
  1156. return true;
  1157. }
  1158. #endif
  1159. const CMatrix4<T> &m = *this;
  1160. f32 d = (m[0] * m[5] - m[1] * m[4]) * (m[10] * m[15] - m[11] * m[14]) -
  1161. (m[0] * m[6] - m[2] * m[4]) * (m[9] * m[15] - m[11] * m[13]) +
  1162. (m[0] * m[7] - m[3] * m[4]) * (m[9] * m[14] - m[10] * m[13]) +
  1163. (m[1] * m[6] - m[2] * m[5]) * (m[8] * m[15] - m[11] * m[12]) -
  1164. (m[1] * m[7] - m[3] * m[5]) * (m[8] * m[14] - m[10] * m[12]) +
  1165. (m[2] * m[7] - m[3] * m[6]) * (m[8] * m[13] - m[9] * m[12]);
  1166. if (core::iszero(d, FLT_MIN))
  1167. return false;
  1168. d = core::reciprocal(d);
  1169. out[0] = d * (m[5] * (m[10] * m[15] - m[11] * m[14]) +
  1170. m[6] * (m[11] * m[13] - m[9] * m[15]) +
  1171. m[7] * (m[9] * m[14] - m[10] * m[13]));
  1172. out[1] = d * (m[9] * (m[2] * m[15] - m[3] * m[14]) +
  1173. m[10] * (m[3] * m[13] - m[1] * m[15]) +
  1174. m[11] * (m[1] * m[14] - m[2] * m[13]));
  1175. out[2] = d * (m[13] * (m[2] * m[7] - m[3] * m[6]) +
  1176. m[14] * (m[3] * m[5] - m[1] * m[7]) +
  1177. m[15] * (m[1] * m[6] - m[2] * m[5]));
  1178. out[3] = d * (m[1] * (m[7] * m[10] - m[6] * m[11]) +
  1179. m[2] * (m[5] * m[11] - m[7] * m[9]) +
  1180. m[3] * (m[6] * m[9] - m[5] * m[10]));
  1181. out[4] = d * (m[6] * (m[8] * m[15] - m[11] * m[12]) +
  1182. m[7] * (m[10] * m[12] - m[8] * m[14]) +
  1183. m[4] * (m[11] * m[14] - m[10] * m[15]));
  1184. out[5] = d * (m[10] * (m[0] * m[15] - m[3] * m[12]) +
  1185. m[11] * (m[2] * m[12] - m[0] * m[14]) +
  1186. m[8] * (m[3] * m[14] - m[2] * m[15]));
  1187. out[6] = d * (m[14] * (m[0] * m[7] - m[3] * m[4]) +
  1188. m[15] * (m[2] * m[4] - m[0] * m[6]) +
  1189. m[12] * (m[3] * m[6] - m[2] * m[7]));
  1190. out[7] = d * (m[2] * (m[7] * m[8] - m[4] * m[11]) +
  1191. m[3] * (m[4] * m[10] - m[6] * m[8]) +
  1192. m[0] * (m[6] * m[11] - m[7] * m[10]));
  1193. out[8] = d * (m[7] * (m[8] * m[13] - m[9] * m[12]) +
  1194. m[4] * (m[9] * m[15] - m[11] * m[13]) +
  1195. m[5] * (m[11] * m[12] - m[8] * m[15]));
  1196. out[9] = d * (m[11] * (m[0] * m[13] - m[1] * m[12]) +
  1197. m[8] * (m[1] * m[15] - m[3] * m[13]) +
  1198. m[9] * (m[3] * m[12] - m[0] * m[15]));
  1199. out[10] = d * (m[15] * (m[0] * m[5] - m[1] * m[4]) +
  1200. m[12] * (m[1] * m[7] - m[3] * m[5]) +
  1201. m[13] * (m[3] * m[4] - m[0] * m[7]));
  1202. out[11] = d * (m[3] * (m[5] * m[8] - m[4] * m[9]) +
  1203. m[0] * (m[7] * m[9] - m[5] * m[11]) +
  1204. m[1] * (m[4] * m[11] - m[7] * m[8]));
  1205. out[12] = d * (m[4] * (m[10] * m[13] - m[9] * m[14]) +
  1206. m[5] * (m[8] * m[14] - m[10] * m[12]) +
  1207. m[6] * (m[9] * m[12] - m[8] * m[13]));
  1208. out[13] = d * (m[8] * (m[2] * m[13] - m[1] * m[14]) +
  1209. m[9] * (m[0] * m[14] - m[2] * m[12]) +
  1210. m[10] * (m[1] * m[12] - m[0] * m[13]));
  1211. out[14] = d * (m[12] * (m[2] * m[5] - m[1] * m[6]) +
  1212. m[13] * (m[0] * m[6] - m[2] * m[4]) +
  1213. m[14] * (m[1] * m[4] - m[0] * m[5]));
  1214. out[15] = d * (m[0] * (m[5] * m[10] - m[6] * m[9]) +
  1215. m[1] * (m[6] * m[8] - m[4] * m[10]) +
  1216. m[2] * (m[4] * m[9] - m[5] * m[8]));
  1217. #if defined(USE_MATRIX_TEST)
  1218. out.definitelyIdentityMatrix = definitelyIdentityMatrix;
  1219. #endif
  1220. return true;
  1221. }
  1222. //! Inverts a primitive matrix which only contains a translation and a rotation
  1223. //! \param out: where result matrix is written to.
  1224. template <class T>
  1225. inline bool CMatrix4<T>::getInversePrimitive(CMatrix4<T> &out) const
  1226. {
  1227. out.M[0] = M[0];
  1228. out.M[1] = M[4];
  1229. out.M[2] = M[8];
  1230. out.M[3] = 0;
  1231. out.M[4] = M[1];
  1232. out.M[5] = M[5];
  1233. out.M[6] = M[9];
  1234. out.M[7] = 0;
  1235. out.M[8] = M[2];
  1236. out.M[9] = M[6];
  1237. out.M[10] = M[10];
  1238. out.M[11] = 0;
  1239. out.M[12] = (T) - (M[12] * M[0] + M[13] * M[1] + M[14] * M[2]);
  1240. out.M[13] = (T) - (M[12] * M[4] + M[13] * M[5] + M[14] * M[6]);
  1241. out.M[14] = (T) - (M[12] * M[8] + M[13] * M[9] + M[14] * M[10]);
  1242. out.M[15] = 1;
  1243. #if defined(USE_MATRIX_TEST)
  1244. out.definitelyIdentityMatrix = definitelyIdentityMatrix;
  1245. #endif
  1246. return true;
  1247. }
  1248. /*!
  1249. */
  1250. template <class T>
  1251. inline bool CMatrix4<T>::makeInverse()
  1252. {
  1253. #if defined(USE_MATRIX_TEST)
  1254. if (definitelyIdentityMatrix)
  1255. return true;
  1256. #endif
  1257. CMatrix4<T> temp(EM4CONST_NOTHING);
  1258. if (getInverse(temp)) {
  1259. *this = temp;
  1260. return true;
  1261. }
  1262. return false;
  1263. }
  1264. template <class T>
  1265. inline CMatrix4<T> &CMatrix4<T>::operator=(const T &scalar)
  1266. {
  1267. for (s32 i = 0; i < 16; ++i)
  1268. M[i] = scalar;
  1269. #if defined(USE_MATRIX_TEST)
  1270. definitelyIdentityMatrix = false;
  1271. #endif
  1272. return *this;
  1273. }
  1274. // Builds a right-handed perspective projection matrix based on a field of view
  1275. template <class T>
  1276. inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixPerspectiveFovRH(
  1277. f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero)
  1278. {
  1279. const f64 h = reciprocal(tan(fieldOfViewRadians * 0.5));
  1280. _IRR_DEBUG_BREAK_IF(aspectRatio == 0.f); // divide by zero
  1281. const T w = static_cast<T>(h / aspectRatio);
  1282. _IRR_DEBUG_BREAK_IF(zNear == zFar); // divide by zero
  1283. M[0] = w;
  1284. M[1] = 0;
  1285. M[2] = 0;
  1286. M[3] = 0;
  1287. M[4] = 0;
  1288. M[5] = (T)h;
  1289. M[6] = 0;
  1290. M[7] = 0;
  1291. M[8] = 0;
  1292. M[9] = 0;
  1293. // M[10]
  1294. M[11] = -1;
  1295. M[12] = 0;
  1296. M[13] = 0;
  1297. // M[14]
  1298. M[15] = 0;
  1299. if (zClipFromZero) { // DirectX version
  1300. M[10] = (T)(zFar / (zNear - zFar));
  1301. M[14] = (T)(zNear * zFar / (zNear - zFar));
  1302. } else // OpenGL version
  1303. {
  1304. M[10] = (T)((zFar + zNear) / (zNear - zFar));
  1305. M[14] = (T)(2.0f * zNear * zFar / (zNear - zFar));
  1306. }
  1307. #if defined(USE_MATRIX_TEST)
  1308. definitelyIdentityMatrix = false;
  1309. #endif
  1310. return *this;
  1311. }
  1312. // Builds a left-handed perspective projection matrix based on a field of view
  1313. template <class T>
  1314. inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixPerspectiveFovLH(
  1315. f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero)
  1316. {
  1317. const f64 h = reciprocal(tan(fieldOfViewRadians * 0.5));
  1318. _IRR_DEBUG_BREAK_IF(aspectRatio == 0.f); // divide by zero
  1319. const T w = static_cast<T>(h / aspectRatio);
  1320. _IRR_DEBUG_BREAK_IF(zNear == zFar); // divide by zero
  1321. M[0] = w;
  1322. M[1] = 0;
  1323. M[2] = 0;
  1324. M[3] = 0;
  1325. M[4] = 0;
  1326. M[5] = (T)h;
  1327. M[6] = 0;
  1328. M[7] = 0;
  1329. M[8] = 0;
  1330. M[9] = 0;
  1331. // M[10]
  1332. M[11] = 1;
  1333. M[12] = 0;
  1334. M[13] = 0;
  1335. // M[14]
  1336. M[15] = 0;
  1337. if (zClipFromZero) { // DirectX version
  1338. M[10] = (T)(zFar / (zFar - zNear));
  1339. M[14] = (T)(-zNear * zFar / (zFar - zNear));
  1340. } else // OpenGL version
  1341. {
  1342. M[10] = (T)((zFar + zNear) / (zFar - zNear));
  1343. M[14] = (T)(2.0f * zNear * zFar / (zNear - zFar));
  1344. }
  1345. #if defined(USE_MATRIX_TEST)
  1346. definitelyIdentityMatrix = false;
  1347. #endif
  1348. return *this;
  1349. }
  1350. // Builds a left-handed perspective projection matrix based on a field of view, with far plane culling at infinity
  1351. template <class T>
  1352. inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixPerspectiveFovInfinityLH(
  1353. f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon)
  1354. {
  1355. const f64 h = reciprocal(tan(fieldOfViewRadians * 0.5));
  1356. _IRR_DEBUG_BREAK_IF(aspectRatio == 0.f); // divide by zero
  1357. const T w = static_cast<T>(h / aspectRatio);
  1358. M[0] = w;
  1359. M[1] = 0;
  1360. M[2] = 0;
  1361. M[3] = 0;
  1362. M[4] = 0;
  1363. M[5] = (T)h;
  1364. M[6] = 0;
  1365. M[7] = 0;
  1366. M[8] = 0;
  1367. M[9] = 0;
  1368. M[10] = (T)(1.f - epsilon);
  1369. M[11] = 1;
  1370. M[12] = 0;
  1371. M[13] = 0;
  1372. M[14] = (T)(zNear * (epsilon - 1.f));
  1373. M[15] = 0;
  1374. #if defined(USE_MATRIX_TEST)
  1375. definitelyIdentityMatrix = false;
  1376. #endif
  1377. return *this;
  1378. }
  1379. // Builds a left-handed orthogonal projection matrix.
  1380. template <class T>
  1381. inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixOrthoLH(
  1382. f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
  1383. {
  1384. _IRR_DEBUG_BREAK_IF(widthOfViewVolume == 0.f); // divide by zero
  1385. _IRR_DEBUG_BREAK_IF(heightOfViewVolume == 0.f); // divide by zero
  1386. _IRR_DEBUG_BREAK_IF(zNear == zFar); // divide by zero
  1387. M[0] = (T)(2 / widthOfViewVolume);
  1388. M[1] = 0;
  1389. M[2] = 0;
  1390. M[3] = 0;
  1391. M[4] = 0;
  1392. M[5] = (T)(2 / heightOfViewVolume);
  1393. M[6] = 0;
  1394. M[7] = 0;
  1395. M[8] = 0;
  1396. M[9] = 0;
  1397. // M[10]
  1398. M[11] = 0;
  1399. M[12] = 0;
  1400. M[13] = 0;
  1401. // M[14]
  1402. M[15] = 1;
  1403. if (zClipFromZero) {
  1404. M[10] = (T)(1 / (zFar - zNear));
  1405. M[14] = (T)(zNear / (zNear - zFar));
  1406. } else {
  1407. M[10] = (T)(2 / (zFar - zNear));
  1408. M[14] = (T) - (zFar + zNear) / (zFar - zNear);
  1409. }
  1410. #if defined(USE_MATRIX_TEST)
  1411. definitelyIdentityMatrix = false;
  1412. #endif
  1413. return *this;
  1414. }
  1415. // Builds a right-handed orthogonal projection matrix.
  1416. template <class T>
  1417. inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixOrthoRH(
  1418. f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
  1419. {
  1420. _IRR_DEBUG_BREAK_IF(widthOfViewVolume == 0.f); // divide by zero
  1421. _IRR_DEBUG_BREAK_IF(heightOfViewVolume == 0.f); // divide by zero
  1422. _IRR_DEBUG_BREAK_IF(zNear == zFar); // divide by zero
  1423. M[0] = (T)(2 / widthOfViewVolume);
  1424. M[1] = 0;
  1425. M[2] = 0;
  1426. M[3] = 0;
  1427. M[4] = 0;
  1428. M[5] = (T)(2 / heightOfViewVolume);
  1429. M[6] = 0;
  1430. M[7] = 0;
  1431. M[8] = 0;
  1432. M[9] = 0;
  1433. // M[10]
  1434. M[11] = 0;
  1435. M[12] = 0;
  1436. M[13] = 0;
  1437. // M[14]
  1438. M[15] = 1;
  1439. if (zClipFromZero) {
  1440. M[10] = (T)(1 / (zNear - zFar));
  1441. M[14] = (T)(zNear / (zNear - zFar));
  1442. } else {
  1443. M[10] = (T)(2 / (zNear - zFar));
  1444. M[14] = (T) - (zFar + zNear) / (zFar - zNear);
  1445. }
  1446. #if defined(USE_MATRIX_TEST)
  1447. definitelyIdentityMatrix = false;
  1448. #endif
  1449. return *this;
  1450. }
  1451. // Builds a right-handed perspective projection matrix.
  1452. template <class T>
  1453. inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixPerspectiveRH(
  1454. f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
  1455. {
  1456. _IRR_DEBUG_BREAK_IF(widthOfViewVolume == 0.f); // divide by zero
  1457. _IRR_DEBUG_BREAK_IF(heightOfViewVolume == 0.f); // divide by zero
  1458. _IRR_DEBUG_BREAK_IF(zNear == zFar); // divide by zero
  1459. M[0] = (T)(2 * zNear / widthOfViewVolume);
  1460. M[1] = 0;
  1461. M[2] = 0;
  1462. M[3] = 0;
  1463. M[4] = 0;
  1464. M[5] = (T)(2 * zNear / heightOfViewVolume);
  1465. M[6] = 0;
  1466. M[7] = 0;
  1467. M[8] = 0;
  1468. M[9] = 0;
  1469. // M[10]
  1470. M[11] = -1;
  1471. M[12] = 0;
  1472. M[13] = 0;
  1473. // M[14]
  1474. M[15] = 0;
  1475. if (zClipFromZero) { // DirectX version
  1476. M[10] = (T)(zFar / (zNear - zFar));
  1477. M[14] = (T)(zNear * zFar / (zNear - zFar));
  1478. } else // OpenGL version
  1479. {
  1480. M[10] = (T)((zFar + zNear) / (zNear - zFar));
  1481. M[14] = (T)(2.0f * zNear * zFar / (zNear - zFar));
  1482. }
  1483. #if defined(USE_MATRIX_TEST)
  1484. definitelyIdentityMatrix = false;
  1485. #endif
  1486. return *this;
  1487. }
  1488. // Builds a left-handed perspective projection matrix.
  1489. template <class T>
  1490. inline CMatrix4<T> &CMatrix4<T>::buildProjectionMatrixPerspectiveLH(
  1491. f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
  1492. {
  1493. _IRR_DEBUG_BREAK_IF(widthOfViewVolume == 0.f); // divide by zero
  1494. _IRR_DEBUG_BREAK_IF(heightOfViewVolume == 0.f); // divide by zero
  1495. _IRR_DEBUG_BREAK_IF(zNear == zFar); // divide by zero
  1496. M[0] = (T)(2 * zNear / widthOfViewVolume);
  1497. M[1] = 0;
  1498. M[2] = 0;
  1499. M[3] = 0;
  1500. M[4] = 0;
  1501. M[5] = (T)(2 * zNear / heightOfViewVolume);
  1502. M[6] = 0;
  1503. M[7] = 0;
  1504. M[8] = 0;
  1505. M[9] = 0;
  1506. // M[10]
  1507. M[11] = 1;
  1508. M[12] = 0;
  1509. M[13] = 0;
  1510. // M[14] = (T)(zNear*zFar/(zNear-zFar));
  1511. M[15] = 0;
  1512. if (zClipFromZero) { // DirectX version
  1513. M[10] = (T)(zFar / (zFar - zNear));
  1514. M[14] = (T)(zNear * zFar / (zNear - zFar));
  1515. } else // OpenGL version
  1516. {
  1517. M[10] = (T)((zFar + zNear) / (zFar - zNear));
  1518. M[14] = (T)(2.0f * zNear * zFar / (zNear - zFar));
  1519. }
  1520. #if defined(USE_MATRIX_TEST)
  1521. definitelyIdentityMatrix = false;
  1522. #endif
  1523. return *this;
  1524. }
  1525. // Builds a matrix that flattens geometry into a plane.
  1526. template <class T>
  1527. inline CMatrix4<T> &CMatrix4<T>::buildShadowMatrix(const core::vector3df &light, core::plane3df plane, f32 point)
  1528. {
  1529. plane.Normal.normalize();
  1530. const f32 d = plane.Normal.dotProduct(light);
  1531. M[0] = (T)(-plane.Normal.X * light.X + d);
  1532. M[1] = (T)(-plane.Normal.X * light.Y);
  1533. M[2] = (T)(-plane.Normal.X * light.Z);
  1534. M[3] = (T)(-plane.Normal.X * point);
  1535. M[4] = (T)(-plane.Normal.Y * light.X);
  1536. M[5] = (T)(-plane.Normal.Y * light.Y + d);
  1537. M[6] = (T)(-plane.Normal.Y * light.Z);
  1538. M[7] = (T)(-plane.Normal.Y * point);
  1539. M[8] = (T)(-plane.Normal.Z * light.X);
  1540. M[9] = (T)(-plane.Normal.Z * light.Y);
  1541. M[10] = (T)(-plane.Normal.Z * light.Z + d);
  1542. M[11] = (T)(-plane.Normal.Z * point);
  1543. M[12] = (T)(-plane.D * light.X);
  1544. M[13] = (T)(-plane.D * light.Y);
  1545. M[14] = (T)(-plane.D * light.Z);
  1546. M[15] = (T)(-plane.D * point + d);
  1547. #if defined(USE_MATRIX_TEST)
  1548. definitelyIdentityMatrix = false;
  1549. #endif
  1550. return *this;
  1551. }
  1552. // Builds a left-handed look-at matrix.
  1553. template <class T>
  1554. inline CMatrix4<T> &CMatrix4<T>::buildCameraLookAtMatrixLH(
  1555. const vector3df &position,
  1556. const vector3df &target,
  1557. const vector3df &upVector)
  1558. {
  1559. vector3df zaxis = target - position;
  1560. zaxis.normalize();
  1561. vector3df xaxis = upVector.crossProduct(zaxis);
  1562. xaxis.normalize();
  1563. vector3df yaxis = zaxis.crossProduct(xaxis);
  1564. M[0] = (T)xaxis.X;
  1565. M[1] = (T)yaxis.X;
  1566. M[2] = (T)zaxis.X;
  1567. M[3] = 0;
  1568. M[4] = (T)xaxis.Y;
  1569. M[5] = (T)yaxis.Y;
  1570. M[6] = (T)zaxis.Y;
  1571. M[7] = 0;
  1572. M[8] = (T)xaxis.Z;
  1573. M[9] = (T)yaxis.Z;
  1574. M[10] = (T)zaxis.Z;
  1575. M[11] = 0;
  1576. M[12] = (T)-xaxis.dotProduct(position);
  1577. M[13] = (T)-yaxis.dotProduct(position);
  1578. M[14] = (T)-zaxis.dotProduct(position);
  1579. M[15] = 1;
  1580. #if defined(USE_MATRIX_TEST)
  1581. definitelyIdentityMatrix = false;
  1582. #endif
  1583. return *this;
  1584. }
  1585. // Builds a right-handed look-at matrix.
  1586. template <class T>
  1587. inline CMatrix4<T> &CMatrix4<T>::buildCameraLookAtMatrixRH(
  1588. const vector3df &position,
  1589. const vector3df &target,
  1590. const vector3df &upVector)
  1591. {
  1592. vector3df zaxis = position - target;
  1593. zaxis.normalize();
  1594. vector3df xaxis = upVector.crossProduct(zaxis);
  1595. xaxis.normalize();
  1596. vector3df yaxis = zaxis.crossProduct(xaxis);
  1597. M[0] = (T)xaxis.X;
  1598. M[1] = (T)yaxis.X;
  1599. M[2] = (T)zaxis.X;
  1600. M[3] = 0;
  1601. M[4] = (T)xaxis.Y;
  1602. M[5] = (T)yaxis.Y;
  1603. M[6] = (T)zaxis.Y;
  1604. M[7] = 0;
  1605. M[8] = (T)xaxis.Z;
  1606. M[9] = (T)yaxis.Z;
  1607. M[10] = (T)zaxis.Z;
  1608. M[11] = 0;
  1609. M[12] = (T)-xaxis.dotProduct(position);
  1610. M[13] = (T)-yaxis.dotProduct(position);
  1611. M[14] = (T)-zaxis.dotProduct(position);
  1612. M[15] = 1;
  1613. #if defined(USE_MATRIX_TEST)
  1614. definitelyIdentityMatrix = false;
  1615. #endif
  1616. return *this;
  1617. }
  1618. // creates a new matrix as interpolated matrix from this and the passed one.
  1619. template <class T>
  1620. inline CMatrix4<T> CMatrix4<T>::interpolate(const core::CMatrix4<T> &b, f32 time) const
  1621. {
  1622. CMatrix4<T> mat(EM4CONST_NOTHING);
  1623. for (u32 i = 0; i < 16; i += 4) {
  1624. mat.M[i + 0] = (T)(M[i + 0] + (b.M[i + 0] - M[i + 0]) * time);
  1625. mat.M[i + 1] = (T)(M[i + 1] + (b.M[i + 1] - M[i + 1]) * time);
  1626. mat.M[i + 2] = (T)(M[i + 2] + (b.M[i + 2] - M[i + 2]) * time);
  1627. mat.M[i + 3] = (T)(M[i + 3] + (b.M[i + 3] - M[i + 3]) * time);
  1628. }
  1629. return mat;
  1630. }
  1631. // returns transposed matrix
  1632. template <class T>
  1633. inline CMatrix4<T> CMatrix4<T>::getTransposed() const
  1634. {
  1635. CMatrix4<T> t(EM4CONST_NOTHING);
  1636. getTransposed(t);
  1637. return t;
  1638. }
  1639. // returns transposed matrix
  1640. template <class T>
  1641. inline void CMatrix4<T>::getTransposed(CMatrix4<T> &o) const
  1642. {
  1643. o[0] = M[0];
  1644. o[1] = M[4];
  1645. o[2] = M[8];
  1646. o[3] = M[12];
  1647. o[4] = M[1];
  1648. o[5] = M[5];
  1649. o[6] = M[9];
  1650. o[7] = M[13];
  1651. o[8] = M[2];
  1652. o[9] = M[6];
  1653. o[10] = M[10];
  1654. o[11] = M[14];
  1655. o[12] = M[3];
  1656. o[13] = M[7];
  1657. o[14] = M[11];
  1658. o[15] = M[15];
  1659. #if defined(USE_MATRIX_TEST)
  1660. o.definitelyIdentityMatrix = definitelyIdentityMatrix;
  1661. #endif
  1662. }
  1663. // used to scale <-1,-1><1,1> to viewport
  1664. template <class T>
  1665. inline CMatrix4<T> &CMatrix4<T>::buildNDCToDCMatrix(const core::rect<s32> &viewport, f32 zScale)
  1666. {
  1667. const f32 scaleX = (viewport.getWidth() - 0.75f) * 0.5f;
  1668. const f32 scaleY = -(viewport.getHeight() - 0.75f) * 0.5f;
  1669. const f32 dx = -0.5f + ((viewport.UpperLeftCorner.X + viewport.LowerRightCorner.X) * 0.5f);
  1670. const f32 dy = -0.5f + ((viewport.UpperLeftCorner.Y + viewport.LowerRightCorner.Y) * 0.5f);
  1671. makeIdentity();
  1672. M[12] = (T)dx;
  1673. M[13] = (T)dy;
  1674. return setScale(core::vector3d<T>((T)scaleX, (T)scaleY, (T)zScale));
  1675. }
  1676. //! Builds a matrix that rotates from one vector to another
  1677. /** \param from: vector to rotate from
  1678. \param to: vector to rotate to
  1679. http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/index.htm
  1680. */
  1681. template <class T>
  1682. inline CMatrix4<T> &CMatrix4<T>::buildRotateFromTo(const core::vector3df &from, const core::vector3df &to)
  1683. {
  1684. // unit vectors
  1685. core::vector3df f(from);
  1686. core::vector3df t(to);
  1687. f.normalize();
  1688. t.normalize();
  1689. // axis multiplication by sin
  1690. core::vector3df vs(t.crossProduct(f));
  1691. // axis of rotation
  1692. core::vector3df v(vs);
  1693. v.normalize();
  1694. // cosine angle
  1695. T ca = f.dotProduct(t);
  1696. core::vector3df vt(v * (1 - ca));
  1697. M[0] = vt.X * v.X + ca;
  1698. M[5] = vt.Y * v.Y + ca;
  1699. M[10] = vt.Z * v.Z + ca;
  1700. vt.X *= v.Y;
  1701. vt.Z *= v.X;
  1702. vt.Y *= v.Z;
  1703. M[1] = vt.X - vs.Z;
  1704. M[2] = vt.Z + vs.Y;
  1705. M[3] = 0;
  1706. M[4] = vt.X + vs.Z;
  1707. M[6] = vt.Y - vs.X;
  1708. M[7] = 0;
  1709. M[8] = vt.Z - vs.Y;
  1710. M[9] = vt.Y + vs.X;
  1711. M[11] = 0;
  1712. M[12] = 0;
  1713. M[13] = 0;
  1714. M[14] = 0;
  1715. M[15] = 1;
  1716. return *this;
  1717. }
  1718. //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis
  1719. /** \param camPos: viewer position in world coord
  1720. \param center: object position in world-coord, rotation pivot
  1721. \param translation: object final translation from center
  1722. \param axis: axis to rotate about
  1723. \param from: source vector to rotate from
  1724. */
  1725. template <class T>
  1726. inline void CMatrix4<T>::buildAxisAlignedBillboard(
  1727. const core::vector3df &camPos,
  1728. const core::vector3df &center,
  1729. const core::vector3df &translation,
  1730. const core::vector3df &axis,
  1731. const core::vector3df &from)
  1732. {
  1733. // axis of rotation
  1734. core::vector3df up = axis;
  1735. up.normalize();
  1736. const core::vector3df forward = (camPos - center).normalize();
  1737. const core::vector3df right = up.crossProduct(forward).normalize();
  1738. // correct look vector
  1739. const core::vector3df look = right.crossProduct(up);
  1740. // rotate from to
  1741. // axis multiplication by sin
  1742. const core::vector3df vs = look.crossProduct(from);
  1743. // cosine angle
  1744. const f32 ca = from.dotProduct(look);
  1745. core::vector3df vt(up * (1.f - ca));
  1746. M[0] = static_cast<T>(vt.X * up.X + ca);
  1747. M[5] = static_cast<T>(vt.Y * up.Y + ca);
  1748. M[10] = static_cast<T>(vt.Z * up.Z + ca);
  1749. vt.X *= up.Y;
  1750. vt.Z *= up.X;
  1751. vt.Y *= up.Z;
  1752. M[1] = static_cast<T>(vt.X - vs.Z);
  1753. M[2] = static_cast<T>(vt.Z + vs.Y);
  1754. M[3] = 0;
  1755. M[4] = static_cast<T>(vt.X + vs.Z);
  1756. M[6] = static_cast<T>(vt.Y - vs.X);
  1757. M[7] = 0;
  1758. M[8] = static_cast<T>(vt.Z - vs.Y);
  1759. M[9] = static_cast<T>(vt.Y + vs.X);
  1760. M[11] = 0;
  1761. setRotationCenter(center, translation);
  1762. }
  1763. //! Builds a combined matrix which translate to a center before rotation and translate afterward
  1764. template <class T>
  1765. inline void CMatrix4<T>::setRotationCenter(const core::vector3df &center, const core::vector3df &translation)
  1766. {
  1767. M[12] = -M[0] * center.X - M[4] * center.Y - M[8] * center.Z + (center.X - translation.X);
  1768. M[13] = -M[1] * center.X - M[5] * center.Y - M[9] * center.Z + (center.Y - translation.Y);
  1769. M[14] = -M[2] * center.X - M[6] * center.Y - M[10] * center.Z + (center.Z - translation.Z);
  1770. M[15] = (T)1.0;
  1771. #if defined(USE_MATRIX_TEST)
  1772. definitelyIdentityMatrix = false;
  1773. #endif
  1774. }
  1775. /*!
  1776. Generate texture coordinates as linear functions so that:
  1777. u = Ux*x + Uy*y + Uz*z + Uw
  1778. v = Vx*x + Vy*y + Vz*z + Vw
  1779. The matrix M for this case is:
  1780. Ux Vx 0 0
  1781. Uy Vy 0 0
  1782. Uz Vz 0 0
  1783. Uw Vw 0 0
  1784. */
  1785. template <class T>
  1786. inline CMatrix4<T> &CMatrix4<T>::buildTextureTransform(f32 rotateRad,
  1787. const core::vector2df &rotatecenter,
  1788. const core::vector2df &translate,
  1789. const core::vector2df &scale)
  1790. {
  1791. const f32 c = cosf(rotateRad);
  1792. const f32 s = sinf(rotateRad);
  1793. M[0] = (T)(c * scale.X);
  1794. M[1] = (T)(s * scale.Y);
  1795. M[2] = 0;
  1796. M[3] = 0;
  1797. M[4] = (T)(-s * scale.X);
  1798. M[5] = (T)(c * scale.Y);
  1799. M[6] = 0;
  1800. M[7] = 0;
  1801. M[8] = (T)(c * scale.X * rotatecenter.X + -s * rotatecenter.Y + translate.X);
  1802. M[9] = (T)(s * scale.Y * rotatecenter.X + c * rotatecenter.Y + translate.Y);
  1803. M[10] = 1;
  1804. M[11] = 0;
  1805. M[12] = 0;
  1806. M[13] = 0;
  1807. M[14] = 0;
  1808. M[15] = 1;
  1809. #if defined(USE_MATRIX_TEST)
  1810. definitelyIdentityMatrix = false;
  1811. #endif
  1812. return *this;
  1813. }
  1814. // rotate about z axis, center ( 0.5, 0.5 )
  1815. template <class T>
  1816. inline CMatrix4<T> &CMatrix4<T>::setTextureRotationCenter(f32 rotateRad)
  1817. {
  1818. const f32 c = cosf(rotateRad);
  1819. const f32 s = sinf(rotateRad);
  1820. M[0] = (T)c;
  1821. M[1] = (T)s;
  1822. M[4] = (T)-s;
  1823. M[5] = (T)c;
  1824. M[8] = (T)(0.5f * (s - c) + 0.5f);
  1825. M[9] = (T)(-0.5f * (s + c) + 0.5f);
  1826. #if defined(USE_MATRIX_TEST)
  1827. definitelyIdentityMatrix = definitelyIdentityMatrix && (rotateRad == 0.0f);
  1828. #endif
  1829. return *this;
  1830. }
  1831. template <class T>
  1832. inline CMatrix4<T> &CMatrix4<T>::setTextureTranslate(f32 x, f32 y)
  1833. {
  1834. M[8] = (T)x;
  1835. M[9] = (T)y;
  1836. #if defined(USE_MATRIX_TEST)
  1837. definitelyIdentityMatrix = definitelyIdentityMatrix && (x == 0.0f) && (y == 0.0f);
  1838. #endif
  1839. return *this;
  1840. }
  1841. template <class T>
  1842. inline void CMatrix4<T>::getTextureTranslate(f32 &x, f32 &y) const
  1843. {
  1844. x = (f32)M[8];
  1845. y = (f32)M[9];
  1846. }
  1847. template <class T>
  1848. inline CMatrix4<T> &CMatrix4<T>::setTextureTranslateTransposed(f32 x, f32 y)
  1849. {
  1850. M[2] = (T)x;
  1851. M[6] = (T)y;
  1852. #if defined(USE_MATRIX_TEST)
  1853. definitelyIdentityMatrix = definitelyIdentityMatrix && (x == 0.0f) && (y == 0.0f);
  1854. #endif
  1855. return *this;
  1856. }
  1857. template <class T>
  1858. inline CMatrix4<T> &CMatrix4<T>::setTextureScale(f32 sx, f32 sy)
  1859. {
  1860. M[0] = (T)sx;
  1861. M[5] = (T)sy;
  1862. #if defined(USE_MATRIX_TEST)
  1863. definitelyIdentityMatrix = definitelyIdentityMatrix && (sx == 1.0f) && (sy == 1.0f);
  1864. #endif
  1865. return *this;
  1866. }
  1867. template <class T>
  1868. inline void CMatrix4<T>::getTextureScale(f32 &sx, f32 &sy) const
  1869. {
  1870. sx = (f32)M[0];
  1871. sy = (f32)M[5];
  1872. }
  1873. template <class T>
  1874. inline CMatrix4<T> &CMatrix4<T>::setTextureScaleCenter(f32 sx, f32 sy)
  1875. {
  1876. M[0] = (T)sx;
  1877. M[5] = (T)sy;
  1878. M[8] = (T)(0.5f - 0.5f * sx);
  1879. M[9] = (T)(0.5f - 0.5f * sy);
  1880. #if defined(USE_MATRIX_TEST)
  1881. definitelyIdentityMatrix = definitelyIdentityMatrix && (sx == 1.0f) && (sy == 1.0f);
  1882. #endif
  1883. return *this;
  1884. }
  1885. // sets all matrix data members at once
  1886. template <class T>
  1887. inline CMatrix4<T> &CMatrix4<T>::setM(const T *data)
  1888. {
  1889. memcpy(M, data, 16 * sizeof(T));
  1890. #if defined(USE_MATRIX_TEST)
  1891. definitelyIdentityMatrix = false;
  1892. #endif
  1893. return *this;
  1894. }
  1895. // sets if the matrix is definitely identity matrix
  1896. template <class T>
  1897. inline void CMatrix4<T>::setDefinitelyIdentityMatrix(bool isDefinitelyIdentityMatrix)
  1898. {
  1899. #if defined(USE_MATRIX_TEST)
  1900. definitelyIdentityMatrix = isDefinitelyIdentityMatrix;
  1901. #else
  1902. (void)isDefinitelyIdentityMatrix; // prevent compiler warning
  1903. #endif
  1904. }
  1905. // gets if the matrix is definitely identity matrix
  1906. template <class T>
  1907. inline bool CMatrix4<T>::getDefinitelyIdentityMatrix() const
  1908. {
  1909. #if defined(USE_MATRIX_TEST)
  1910. return definitelyIdentityMatrix;
  1911. #else
  1912. return false;
  1913. #endif
  1914. }
  1915. //! Compare two matrices using the equal method
  1916. template <class T>
  1917. inline bool CMatrix4<T>::equals(const core::CMatrix4<T> &other, const T tolerance) const
  1918. {
  1919. #if defined(USE_MATRIX_TEST)
  1920. if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
  1921. return true;
  1922. #endif
  1923. for (s32 i = 0; i < 16; ++i)
  1924. if (!core::equals(M[i], other.M[i], tolerance))
  1925. return false;
  1926. return true;
  1927. }
  1928. // Multiply by scalar.
  1929. template <class T>
  1930. inline CMatrix4<T> operator*(const T scalar, const CMatrix4<T> &mat)
  1931. {
  1932. return mat * scalar;
  1933. }
  1934. //! Typedef for f32 matrix
  1935. typedef CMatrix4<f32> matrix4;
  1936. //! global const identity matrix
  1937. IRRLICHT_API extern const matrix4 IdentityMatrix;
  1938. } // end namespace core
  1939. } // end namespace irr