matrix4.h 69 KB

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