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