matrix4.h 67 KB

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