IrrlichtEngine
matrix4.h
Go to the documentation of this file.
00001 // Copyright (C) 2002-2011 Nikolaus Gebhardt
00002 // This file is part of the "Irrlicht Engine".
00003 // For conditions of distribution and use, see copyright notice in irrlicht.h
00004 
00005 #ifndef __IRR_MATRIX_H_INCLUDED__
00006 #define __IRR_MATRIX_H_INCLUDED__
00007 
00008 #include "irrMath.h"
00009 #include "vector3d.h"
00010 #include "vector2d.h"
00011 #include "plane3d.h"
00012 #include "aabbox3d.h"
00013 #include "rect.h"
00014 #include "irrString.h"
00015 
00016 // enable this to keep track of changes to the matrix
00017 // and make simpler identity check for seldomly changing matrices
00018 // otherwise identity check will always compare the elements
00019 //#define USE_MATRIX_TEST
00020 
00021 // this is only for debugging purposes
00022 //#define USE_MATRIX_TEST_DEBUG
00023 
00024 #if defined( USE_MATRIX_TEST_DEBUG )
00025 
00026 struct MatrixTest
00027 {
00028         MatrixTest () : ID(0), Calls(0) {}
00029         char buf[256];
00030         int Calls;
00031         int ID;
00032 };
00033 static MatrixTest MTest;
00034 
00035 #endif
00036 
00037 namespace irr
00038 {
00039 namespace core
00040 {
00041 
00043 
00044         template <class T>
00045         class CMatrix4
00046         {
00047                 public:
00048 
00050                         enum eConstructor
00051                         {
00052                                 EM4CONST_NOTHING = 0,
00053                                 EM4CONST_COPY,
00054                                 EM4CONST_IDENTITY,
00055                                 EM4CONST_TRANSPOSED,
00056                                 EM4CONST_INVERSE,
00057                                 EM4CONST_INVERSE_TRANSPOSED
00058                         };
00059 
00061 
00062                         CMatrix4( eConstructor constructor = EM4CONST_IDENTITY );
00064 
00066                         CMatrix4(const CMatrix4<T>& other, eConstructor constructor = EM4CONST_COPY);
00067 
00069                         T& operator()(const s32 row, const s32 col)
00070                         { 
00071 #if defined ( USE_MATRIX_TEST )
00072                                 definitelyIdentityMatrix=false;
00073 #endif
00074                                 return M[ row * 4 + col ];
00075                         }
00076 
00078                         const T& operator()(const s32 row, const s32 col) const { return M[row * 4 + col]; }
00079 
00081                         T& operator[](u32 index)
00082                         { 
00083 #if defined ( USE_MATRIX_TEST )
00084                                 definitelyIdentityMatrix=false; 
00085 #endif
00086                                 return M[index];
00087                         }
00088 
00090                         const T& operator[](u32 index) const { return M[index]; }
00091 
00093                         inline CMatrix4<T>& operator=(const CMatrix4<T> &other);
00094 
00096                         inline CMatrix4<T>& operator=(const T& scalar);
00097 
00099                         const T* pointer() const { return M; }
00100                         T* pointer() 
00101                         { 
00102 #if defined ( USE_MATRIX_TEST )
00103                                 definitelyIdentityMatrix=false;
00104 #endif
00105                                 return M;
00106                         }
00107 
00109                         bool operator==(const CMatrix4<T> &other) const;
00110 
00112                         bool operator!=(const CMatrix4<T> &other) const;
00113 
00115                         CMatrix4<T> operator+(const CMatrix4<T>& other) const;
00116 
00118                         CMatrix4<T>& operator+=(const CMatrix4<T>& other);
00119 
00121                         CMatrix4<T> operator-(const CMatrix4<T>& other) const;
00122 
00124                         CMatrix4<T>& operator-=(const CMatrix4<T>& other);
00125 
00127 
00128                         inline CMatrix4<T>& setbyproduct(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b );
00129 
00131 
00133                         CMatrix4<T>& setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b );
00134 
00136 
00137                         CMatrix4<T> operator*(const CMatrix4<T>& other) const;
00138 
00140 
00141                         CMatrix4<T>& operator*=(const CMatrix4<T>& other);
00142 
00144                         CMatrix4<T> operator*(const T& scalar) const;
00145 
00147                         CMatrix4<T>& operator*=(const T& scalar);
00148 
00150                         inline CMatrix4<T>& makeIdentity();
00151 
00153                         inline bool isIdentity() const;
00154 
00156                         inline bool isOrthogonal() const;
00157 
00159                         bool isIdentity_integer_base () const;
00160 
00162                         CMatrix4<T>& setTranslation( const vector3d<T>& translation );
00163 
00165                         vector3d<T> getTranslation() const;
00166 
00168                         CMatrix4<T>& setInverseTranslation( const vector3d<T>& translation );
00169 
00171                         inline CMatrix4<T>& setRotationRadians( const vector3d<T>& rotation );
00172 
00174                         CMatrix4<T>& setRotationDegrees( const vector3d<T>& rotation );
00175 
00177 
00178                         core::vector3d<T> getRotationDegrees() const;
00179 
00181 
00182                         inline CMatrix4<T>& setInverseRotationRadians( const vector3d<T>& rotation );
00183 
00185 
00186                         CMatrix4<T>& setInverseRotationDegrees( const vector3d<T>& rotation );
00187 
00189                         CMatrix4<T>& setScale( const vector3d<T>& scale );
00190 
00192                         CMatrix4<T>& setScale( const T scale ) { return setScale(core::vector3d<T>(scale,scale,scale)); }
00193 
00195                         core::vector3d<T> getScale() const;
00196 
00198                         void inverseTranslateVect( vector3df& vect ) const;
00199 
00201                         void inverseRotateVect( vector3df& vect ) const;
00202 
00204                         void rotateVect( vector3df& vect ) const;
00205 
00207                         void rotateVect(core::vector3df& out, const core::vector3df& in) const;
00208 
00210                         void rotateVect(T *out,const core::vector3df &in) const;
00211 
00213                         void transformVect( vector3df& vect) const;
00214 
00216                         void transformVect( vector3df& out, const vector3df& in ) const;
00217 
00219                         void transformVect(T *out,const core::vector3df &in) const;
00220                         void transformVec3(T *out, const T * in) const;
00221 
00223                         void translateVect( vector3df& vect ) const;
00224 
00226                         void transformPlane( core::plane3d<f32> &plane) const;
00227 
00229                         void transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const;
00230 
00232 
00234                         void transformBox(core::aabbox3d<f32>& box) const;
00235 
00237 
00239                         void transformBoxEx(core::aabbox3d<f32>& box) const;
00240 
00242                         void multiplyWith1x4Matrix(T* matrix) const;
00243 
00245 
00246                         bool makeInverse();
00247 
00248 
00250 
00251                         bool getInversePrimitive ( CMatrix4<T>& out ) const;
00252 
00254 
00256                         bool getInverse(CMatrix4<T>& out) const;
00257 
00259                         CMatrix4<T>& buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar);
00260 
00262                         CMatrix4<T>& buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar);
00263 
00265                         CMatrix4<T>& buildProjectionMatrixPerspectiveFovInfinityLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon=0);
00266 
00268                         CMatrix4<T>& buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar);
00269 
00271                         CMatrix4<T>& buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar);
00272 
00274                         CMatrix4<T>& buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar);
00275 
00277                         CMatrix4<T>& buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar);
00278 
00280                         CMatrix4<T>& buildCameraLookAtMatrixLH(
00281                                         const vector3df& position,
00282                                         const vector3df& target,
00283                                         const vector3df& upVector);
00284 
00286                         CMatrix4<T>& buildCameraLookAtMatrixRH(
00287                                         const vector3df& position,
00288                                         const vector3df& target,
00289                                         const vector3df& upVector);
00290 
00292 
00296                         CMatrix4<T>& buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point=1.0f);
00297 
00299 
00300                         CMatrix4<T>& buildNDCToDCMatrix( const core::rect<s32>& area, f32 zScale);
00301 
00303 
00305                         CMatrix4<T> interpolate(const core::CMatrix4<T>& b, f32 time) const;
00306 
00308                         CMatrix4<T> getTransposed() const;
00309 
00311                         inline void getTransposed( CMatrix4<T>& dest ) const;
00312 
00314 
00317                         CMatrix4<T>& buildRotateFromTo(const core::vector3df& from, const core::vector3df& to);
00318 
00320 
00323                         void setRotationCenter(const core::vector3df& center, const core::vector3df& translate);
00324 
00326 
00332                         void buildAxisAlignedBillboard(const core::vector3df& camPos,
00333                                                 const core::vector3df& center,
00334                                                 const core::vector3df& translation,
00335                                                 const core::vector3df& axis,
00336                                                 const core::vector3df& from);
00337 
00338                         /*
00339                                 construct 2D Texture transformations
00340                                 rotate about center, scale, and transform.
00341                         */
00343                         CMatrix4<T>& buildTextureTransform( f32 rotateRad,
00344                                         const core::vector2df &rotatecenter,
00345                                         const core::vector2df &translate,
00346                                         const core::vector2df &scale);
00347 
00349 
00353                         CMatrix4<T>& setTextureRotationCenter( f32 radAngle );
00354 
00356 
00360                         CMatrix4<T>& setTextureTranslate( f32 x, f32 y );
00361 
00363 
00367                         CMatrix4<T>& setTextureTranslateTransposed( f32 x, f32 y );
00368 
00370 
00374                         CMatrix4<T>& setTextureScale( f32 sx, f32 sy );
00375 
00377 
00381                         CMatrix4<T>& setTextureScaleCenter( f32 sx, f32 sy );
00382 
00384                         CMatrix4<T>& setM(const T* data);
00385 
00387                         void setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix);
00388 
00390                         bool getDefinitelyIdentityMatrix() const;
00391 
00393                         bool equals(const core::CMatrix4<T>& other, const T tolerance=(T)ROUNDING_ERROR_f64) const;
00394 
00395                 private:
00397                         T M[16];
00398 #if defined ( USE_MATRIX_TEST )
00399 
00400                         mutable u32 definitelyIdentityMatrix;
00401 #endif
00402 #if defined ( USE_MATRIX_TEST_DEBUG )
00403                         u32 id;
00404                         mutable u32 calls;
00405 #endif
00406 
00407         };
00408 
00409         // Default constructor
00410         template <class T>
00411         inline CMatrix4<T>::CMatrix4( eConstructor constructor )
00412 #if defined ( USE_MATRIX_TEST )
00413                 : definitelyIdentityMatrix(BIT_UNTESTED)
00414 #endif
00415 #if defined ( USE_MATRIX_TEST_DEBUG )
00416                 ,id ( MTest.ID++), calls ( 0 )
00417 #endif
00418         {
00419                 switch ( constructor )
00420                 {
00421                         case EM4CONST_NOTHING:
00422                         case EM4CONST_COPY:
00423                                 break;
00424                         case EM4CONST_IDENTITY:
00425                         case EM4CONST_INVERSE:
00426                         default:
00427                                 makeIdentity();
00428                                 break;
00429                 }
00430         }
00431 
00432         // Copy constructor
00433         template <class T>
00434         inline CMatrix4<T>::CMatrix4( const CMatrix4<T>& other, eConstructor constructor)
00435 #if defined ( USE_MATRIX_TEST )
00436                 : definitelyIdentityMatrix(BIT_UNTESTED)
00437 #endif
00438 #if defined ( USE_MATRIX_TEST_DEBUG )
00439                 ,id ( MTest.ID++), calls ( 0 )
00440 #endif
00441         {
00442                 switch ( constructor )
00443                 {
00444                         case EM4CONST_IDENTITY:
00445                                 makeIdentity();
00446                                 break;
00447                         case EM4CONST_NOTHING:
00448                                 break;
00449                         case EM4CONST_COPY:
00450                                 *this = other;
00451                                 break;
00452                         case EM4CONST_TRANSPOSED:
00453                                 other.getTransposed(*this);
00454                                 break;
00455                         case EM4CONST_INVERSE:
00456                                 if (!other.getInverse(*this))
00457                                         memset(M, 0, 16*sizeof(T));
00458                                 break;
00459                         case EM4CONST_INVERSE_TRANSPOSED:
00460                                 if (!other.getInverse(*this))
00461                                         memset(M, 0, 16*sizeof(T));
00462                                 else
00463                                         *this=getTransposed();
00464                                 break;
00465                 }
00466         }
00467 
00469         template <class T>
00470         inline CMatrix4<T> CMatrix4<T>::operator+(const CMatrix4<T>& other) const
00471         {
00472                 CMatrix4<T> temp ( EM4CONST_NOTHING );
00473 
00474                 temp[0] = M[0]+other[0];
00475                 temp[1] = M[1]+other[1];
00476                 temp[2] = M[2]+other[2];
00477                 temp[3] = M[3]+other[3];
00478                 temp[4] = M[4]+other[4];
00479                 temp[5] = M[5]+other[5];
00480                 temp[6] = M[6]+other[6];
00481                 temp[7] = M[7]+other[7];
00482                 temp[8] = M[8]+other[8];
00483                 temp[9] = M[9]+other[9];
00484                 temp[10] = M[10]+other[10];
00485                 temp[11] = M[11]+other[11];
00486                 temp[12] = M[12]+other[12];
00487                 temp[13] = M[13]+other[13];
00488                 temp[14] = M[14]+other[14];
00489                 temp[15] = M[15]+other[15];
00490 
00491                 return temp;
00492         }
00493 
00495         template <class T>
00496         inline CMatrix4<T>& CMatrix4<T>::operator+=(const CMatrix4<T>& other)
00497         {
00498                 M[0]+=other[0];
00499                 M[1]+=other[1];
00500                 M[2]+=other[2];
00501                 M[3]+=other[3];
00502                 M[4]+=other[4];
00503                 M[5]+=other[5];
00504                 M[6]+=other[6];
00505                 M[7]+=other[7];
00506                 M[8]+=other[8];
00507                 M[9]+=other[9];
00508                 M[10]+=other[10];
00509                 M[11]+=other[11];
00510                 M[12]+=other[12];
00511                 M[13]+=other[13];
00512                 M[14]+=other[14];
00513                 M[15]+=other[15];
00514 
00515                 return *this;
00516         }
00517 
00519         template <class T>
00520         inline CMatrix4<T> CMatrix4<T>::operator-(const CMatrix4<T>& other) const
00521         {
00522                 CMatrix4<T> temp ( EM4CONST_NOTHING );
00523 
00524                 temp[0] = M[0]-other[0];
00525                 temp[1] = M[1]-other[1];
00526                 temp[2] = M[2]-other[2];
00527                 temp[3] = M[3]-other[3];
00528                 temp[4] = M[4]-other[4];
00529                 temp[5] = M[5]-other[5];
00530                 temp[6] = M[6]-other[6];
00531                 temp[7] = M[7]-other[7];
00532                 temp[8] = M[8]-other[8];
00533                 temp[9] = M[9]-other[9];
00534                 temp[10] = M[10]-other[10];
00535                 temp[11] = M[11]-other[11];
00536                 temp[12] = M[12]-other[12];
00537                 temp[13] = M[13]-other[13];
00538                 temp[14] = M[14]-other[14];
00539                 temp[15] = M[15]-other[15];
00540 
00541                 return temp;
00542         }
00543 
00545         template <class T>
00546         inline CMatrix4<T>& CMatrix4<T>::operator-=(const CMatrix4<T>& other)
00547         {
00548                 M[0]-=other[0];
00549                 M[1]-=other[1];
00550                 M[2]-=other[2];
00551                 M[3]-=other[3];
00552                 M[4]-=other[4];
00553                 M[5]-=other[5];
00554                 M[6]-=other[6];
00555                 M[7]-=other[7];
00556                 M[8]-=other[8];
00557                 M[9]-=other[9];
00558                 M[10]-=other[10];
00559                 M[11]-=other[11];
00560                 M[12]-=other[12];
00561                 M[13]-=other[13];
00562                 M[14]-=other[14];
00563                 M[15]-=other[15];
00564 
00565                 return *this;
00566         }
00567 
00569         template <class T>
00570         inline CMatrix4<T> CMatrix4<T>::operator*(const T& scalar) const
00571         {
00572                 CMatrix4<T> temp ( EM4CONST_NOTHING );
00573 
00574                 temp[0] = M[0]*scalar;
00575                 temp[1] = M[1]*scalar;
00576                 temp[2] = M[2]*scalar;
00577                 temp[3] = M[3]*scalar;
00578                 temp[4] = M[4]*scalar;
00579                 temp[5] = M[5]*scalar;
00580                 temp[6] = M[6]*scalar;
00581                 temp[7] = M[7]*scalar;
00582                 temp[8] = M[8]*scalar;
00583                 temp[9] = M[9]*scalar;
00584                 temp[10] = M[10]*scalar;
00585                 temp[11] = M[11]*scalar;
00586                 temp[12] = M[12]*scalar;
00587                 temp[13] = M[13]*scalar;
00588                 temp[14] = M[14]*scalar;
00589                 temp[15] = M[15]*scalar;
00590 
00591                 return temp;
00592         }
00593 
00595         template <class T>
00596         inline CMatrix4<T>& CMatrix4<T>::operator*=(const T& scalar)
00597         {
00598                 M[0]*=scalar;
00599                 M[1]*=scalar;
00600                 M[2]*=scalar;
00601                 M[3]*=scalar;
00602                 M[4]*=scalar;
00603                 M[5]*=scalar;
00604                 M[6]*=scalar;
00605                 M[7]*=scalar;
00606                 M[8]*=scalar;
00607                 M[9]*=scalar;
00608                 M[10]*=scalar;
00609                 M[11]*=scalar;
00610                 M[12]*=scalar;
00611                 M[13]*=scalar;
00612                 M[14]*=scalar;
00613                 M[15]*=scalar;
00614 
00615                 return *this;
00616         }
00617 
00619         template <class T>
00620         inline CMatrix4<T>& CMatrix4<T>::operator*=(const CMatrix4<T>& other)
00621         {
00622 #if defined ( USE_MATRIX_TEST )
00623                 // do checks on your own in order to avoid copy creation
00624                 if ( !other.isIdentity() )
00625                 {
00626                         if ( this->isIdentity() )
00627                         {
00628                                 return (*this = other);
00629                         }
00630                         else
00631                         {
00632                                 CMatrix4<T> temp ( *this );
00633                                 return setbyproduct_nocheck( temp, other );
00634                         }
00635                 }
00636                 return *this;
00637 #else
00638                 CMatrix4<T> temp ( *this );
00639                 return setbyproduct_nocheck( temp, other );
00640 #endif
00641         }
00642 
00644         // set this matrix to the product of two other matrices
00645         // goal is to reduce stack use and copy
00646         template <class T>
00647         inline CMatrix4<T>& CMatrix4<T>::setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b )
00648         {
00649                 const T *m1 = other_a.M;
00650                 const T *m2 = other_b.M;
00651 
00652                 M[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
00653                 M[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
00654                 M[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
00655                 M[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
00656 
00657                 M[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
00658                 M[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
00659                 M[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
00660                 M[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
00661 
00662                 M[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
00663                 M[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
00664                 M[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
00665                 M[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
00666 
00667                 M[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
00668                 M[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
00669                 M[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
00670                 M[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
00671 #if defined ( USE_MATRIX_TEST )
00672                 definitelyIdentityMatrix=false;
00673 #endif
00674                 return *this;
00675         }
00676 
00677 
00679         // set this matrix to the product of two other matrices
00680         // goal is to reduce stack use and copy
00681         template <class T>
00682         inline CMatrix4<T>& CMatrix4<T>::setbyproduct(const CMatrix4<T>& other_a, const CMatrix4<T>& other_b )
00683         {
00684 #if defined ( USE_MATRIX_TEST )
00685                 if ( other_a.isIdentity () )
00686                         return (*this = other_b);
00687                 else
00688                 if ( other_b.isIdentity () )
00689                         return (*this = other_a);
00690                 else
00691                         return setbyproduct_nocheck(other_a,other_b);
00692 #else
00693                 return setbyproduct_nocheck(other_a,other_b);
00694 #endif
00695         }
00696 
00698         template <class T>
00699         inline CMatrix4<T> CMatrix4<T>::operator*(const CMatrix4<T>& m2) const
00700         {
00701 #if defined ( USE_MATRIX_TEST )
00702                 // Testing purpose..
00703                 if ( this->isIdentity() )
00704                         return m2;
00705                 if ( m2.isIdentity() )
00706                         return *this;
00707 #endif
00708 
00709                 CMatrix4<T> m3 ( EM4CONST_NOTHING );
00710 
00711                 const T *m1 = M;
00712 
00713                 m3[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
00714                 m3[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
00715                 m3[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
00716                 m3[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
00717 
00718                 m3[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
00719                 m3[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
00720                 m3[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
00721                 m3[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
00722 
00723                 m3[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
00724                 m3[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
00725                 m3[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
00726                 m3[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
00727 
00728                 m3[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
00729                 m3[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
00730                 m3[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
00731                 m3[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
00732                 return m3;
00733         }
00734 
00735 
00736 
00737         template <class T>
00738         inline vector3d<T> CMatrix4<T>::getTranslation() const
00739         {
00740                 return vector3d<T>(M[12], M[13], M[14]);
00741         }
00742 
00743 
00744         template <class T>
00745         inline CMatrix4<T>& CMatrix4<T>::setTranslation( const vector3d<T>& translation )
00746         {
00747                 M[12] = translation.X;
00748                 M[13] = translation.Y;
00749                 M[14] = translation.Z;
00750 #if defined ( USE_MATRIX_TEST )
00751                 definitelyIdentityMatrix=false;
00752 #endif
00753                 return *this;
00754         }
00755 
00756         template <class T>
00757         inline CMatrix4<T>& CMatrix4<T>::setInverseTranslation( const vector3d<T>& translation )
00758         {
00759                 M[12] = -translation.X;
00760                 M[13] = -translation.Y;
00761                 M[14] = -translation.Z;
00762 #if defined ( USE_MATRIX_TEST )
00763                 definitelyIdentityMatrix=false;
00764 #endif
00765                 return *this;
00766         }
00767 
00768         template <class T>
00769         inline CMatrix4<T>& CMatrix4<T>::setScale( const vector3d<T>& scale )
00770         {
00771                 M[0] = scale.X;
00772                 M[5] = scale.Y;
00773                 M[10] = scale.Z;
00774 #if defined ( USE_MATRIX_TEST )
00775                 definitelyIdentityMatrix=false;
00776 #endif
00777                 return *this;
00778         }
00779 
00781 
00788         template <class T>
00789         inline vector3d<T> CMatrix4<T>::getScale() const
00790         {
00791                 // See http://www.robertblum.com/articles/2005/02/14/decomposing-matrices
00792 
00793                 // Deal with the 0 rotation case first
00794                 // Prior to Irrlicht 1.6, we always returned this value.
00795                 if(core::iszero(M[1]) && core::iszero(M[2]) &&
00796                         core::iszero(M[4]) && core::iszero(M[6]) &&
00797                         core::iszero(M[8]) && core::iszero(M[9]))
00798                         return vector3d<T>(M[0], M[5], M[10]);
00799 
00800                 // We have to do the full calculation.
00801                 return vector3d<T>(sqrtf(M[0] * M[0] + M[1] * M[1] + M[2] * M[2]),
00802                                                         sqrtf(M[4] * M[4] + M[5] * M[5] + M[6] * M[6]),
00803                                                         sqrtf(M[8] * M[8] + M[9] * M[9] + M[10] * M[10]));
00804         }
00805 
00806         template <class T>
00807         inline CMatrix4<T>& CMatrix4<T>::setRotationDegrees( const vector3d<T>& rotation )
00808         {
00809                 return setRotationRadians( rotation * core::DEGTORAD );
00810         }
00811 
00812         template <class T>
00813         inline CMatrix4<T>& CMatrix4<T>::setInverseRotationDegrees( const vector3d<T>& rotation )
00814         {
00815                 return setInverseRotationRadians( rotation * core::DEGTORAD );
00816         }
00817 
00818         template <class T>
00819         inline CMatrix4<T>& CMatrix4<T>::setRotationRadians( const vector3d<T>& rotation )
00820         {
00821                 const f64 cr = cos( rotation.X );
00822                 const f64 sr = sin( rotation.X );
00823                 const f64 cp = cos( rotation.Y );
00824                 const f64 sp = sin( rotation.Y );
00825                 const f64 cy = cos( rotation.Z );
00826                 const f64 sy = sin( rotation.Z );
00827 
00828                 M[0] = (T)( cp*cy );
00829                 M[1] = (T)( cp*sy );
00830                 M[2] = (T)( -sp );
00831 
00832                 const f64 srsp = sr*sp;
00833                 const f64 crsp = cr*sp;
00834 
00835                 M[4] = (T)( srsp*cy-cr*sy );
00836                 M[5] = (T)( srsp*sy+cr*cy );
00837                 M[6] = (T)( sr*cp );
00838 
00839                 M[8] = (T)( crsp*cy+sr*sy );
00840                 M[9] = (T)( crsp*sy-sr*cy );
00841                 M[10] = (T)( cr*cp );
00842 #if defined ( USE_MATRIX_TEST )
00843                 definitelyIdentityMatrix=false;
00844 #endif
00845                 return *this;
00846         }
00847 
00848 
00850 
00853         template <class T>
00854         inline core::vector3d<T> CMatrix4<T>::getRotationDegrees() const
00855         {
00856                 const CMatrix4<T> &mat = *this;
00857                 core::vector3d<T> scale = getScale();
00858                 // we need to check for negative scale on to axes, which would bring up wrong results
00859                 if (scale.Y<0 && scale.Z<0)
00860                 {
00861                         scale.Y =-scale.Y;
00862                         scale.Z =-scale.Z;
00863                 }
00864                 else if (scale.X<0 && scale.Z<0)
00865                 {
00866                         scale.X =-scale.X;
00867                         scale.Z =-scale.Z;
00868                 }
00869                 else if (scale.X<0 && scale.Y<0)
00870                 {
00871                         scale.X =-scale.X;
00872                         scale.Y =-scale.Y;
00873                 }
00874                 const core::vector3d<f64> invScale(core::reciprocal(scale.X),core::reciprocal(scale.Y),core::reciprocal(scale.Z));
00875 
00876                 f64 Y = -asin(core::clamp(mat[2]*invScale.X, -1.0, 1.0));
00877                 const f64 C = cos(Y);
00878                 Y *= RADTODEG64;
00879 
00880                 f64 rotx, roty, X, Z;
00881 
00882                 if (!core::iszero(C))
00883                 {
00884                         const f64 invC = core::reciprocal(C);
00885                         rotx = mat[10] * invC * invScale.Z;
00886                         roty = mat[6] * invC * invScale.Y;
00887                         X = atan2( roty, rotx ) * RADTODEG64;
00888                         rotx = mat[0] * invC * invScale.X;
00889                         roty = mat[1] * invC * invScale.X;
00890                         Z = atan2( roty, rotx ) * RADTODEG64;
00891                 }
00892                 else
00893                 {
00894                         X = 0.0;
00895                         rotx = mat[5] * invScale.Y;
00896                         roty = -mat[4] * invScale.Y;
00897                         Z = atan2( roty, rotx ) * RADTODEG64;
00898                 }
00899 
00900                 // fix values that get below zero
00901                 if (X < 0.0) X += 360.0;
00902                 if (Y < 0.0) Y += 360.0;
00903                 if (Z < 0.0) Z += 360.0;
00904 
00905                 return vector3d<T>((T)X,(T)Y,(T)Z);
00906         }
00907 
00908 
00909         template <class T>
00910         inline CMatrix4<T>& CMatrix4<T>::setInverseRotationRadians( const vector3d<T>& rotation )
00911         {
00912                 f64 cr = cos( rotation.X );
00913                 f64 sr = sin( rotation.X );
00914                 f64 cp = cos( rotation.Y );
00915                 f64 sp = sin( rotation.Y );
00916                 f64 cy = cos( rotation.Z );
00917                 f64 sy = sin( rotation.Z );
00918 
00919                 M[0] = (T)( cp*cy );
00920                 M[4] = (T)( cp*sy );
00921                 M[8] = (T)( -sp );
00922 
00923                 f64 srsp = sr*sp;
00924                 f64 crsp = cr*sp;
00925 
00926                 M[1] = (T)( srsp*cy-cr*sy );
00927                 M[5] = (T)( srsp*sy+cr*cy );
00928                 M[9] = (T)( sr*cp );
00929 
00930                 M[2] = (T)( crsp*cy+sr*sy );
00931                 M[6] = (T)( crsp*sy-sr*cy );
00932                 M[10] = (T)( cr*cp );
00933 #if defined ( USE_MATRIX_TEST )
00934                 definitelyIdentityMatrix=false;
00935 #endif
00936                 return *this;
00937         }
00938 
00939 
00942         template <class T>
00943         inline CMatrix4<T>& CMatrix4<T>::makeIdentity()
00944         {
00945                 memset(M, 0, 16*sizeof(T));
00946                 M[0] = M[5] = M[10] = M[15] = (T)1;
00947 #if defined ( USE_MATRIX_TEST )
00948                 definitelyIdentityMatrix=true;
00949 #endif
00950                 return *this;
00951         }
00952 
00953 
00954         /*
00955                 check identity with epsilon
00956                 solve floating range problems..
00957         */
00958         template <class T>
00959         inline bool CMatrix4<T>::isIdentity() const
00960         {
00961 #if defined ( USE_MATRIX_TEST )
00962                 if (definitelyIdentityMatrix)
00963                         return true;
00964 #endif
00965                 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 ))
00966                         return false;
00967 
00968                 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 ))
00969                         return false;
00970 
00971                 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 ))
00972                         return false;
00973 
00974                 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 ))
00975                         return false;
00976 /*
00977                 if (!core::equals( M[ 0], (T)1 ) ||
00978                         !core::equals( M[ 5], (T)1 ) ||
00979                         !core::equals( M[10], (T)1 ) ||
00980                         !core::equals( M[15], (T)1 ))
00981                         return false;
00982 
00983                 for (s32 i=0; i<4; ++i)
00984                         for (s32 j=0; j<4; ++j)
00985                                 if ((j != i) && (!iszero((*this)(i,j))))
00986                                         return false;
00987 */
00988 #if defined ( USE_MATRIX_TEST )
00989                 definitelyIdentityMatrix=true;
00990 #endif
00991                 return true;
00992         }
00993 
00994 
00995         /* Check orthogonality of matrix. */
00996         template <class T>
00997         inline bool CMatrix4<T>::isOrthogonal() const
00998         {
00999                 T dp=M[0] * M[4 ] + M[1] * M[5 ] + M[2 ] * M[6 ] + M[3 ] * M[7 ];
01000                 if (!iszero(dp))
01001                         return false;
01002                 dp = M[0] * M[8 ] + M[1] * M[9 ] + M[2 ] * M[10] + M[3 ] * M[11];
01003                 if (!iszero(dp))
01004                         return false;
01005                 dp = M[0] * M[12] + M[1] * M[13] + M[2 ] * M[14] + M[3 ] * M[15];
01006                 if (!iszero(dp))
01007                         return false;
01008                 dp = M[4] * M[8 ] + M[5] * M[9 ] + M[6 ] * M[10] + M[7 ] * M[11];
01009                 if (!iszero(dp))
01010                         return false;
01011                 dp = M[4] * M[12] + M[5] * M[13] + M[6 ] * M[14] + M[7 ] * M[15];
01012                 if (!iszero(dp))
01013                         return false;
01014                 dp = M[8] * M[12] + M[9] * M[13] + M[10] * M[14] + M[11] * M[15];
01015                 return (iszero(dp));
01016         }
01017 
01018 
01019         /*
01020                 doesn't solve floating range problems..
01021                 but takes care on +/- 0 on translation because we are changing it..
01022                 reducing floating point branches
01023                 but it needs the floats in memory..
01024         */
01025         template <class T>
01026         inline bool CMatrix4<T>::isIdentity_integer_base() const
01027         {
01028 #if defined ( USE_MATRIX_TEST )
01029                 if (definitelyIdentityMatrix)
01030                         return true;
01031 #endif
01032                 if(IR(M[0])!=F32_VALUE_1)       return false;
01033                 if(IR(M[1])!=0)                 return false;
01034                 if(IR(M[2])!=0)                 return false;
01035                 if(IR(M[3])!=0)                 return false;
01036 
01037                 if(IR(M[4])!=0)                 return false;
01038                 if(IR(M[5])!=F32_VALUE_1)       return false;
01039                 if(IR(M[6])!=0)                 return false;
01040                 if(IR(M[7])!=0)                 return false;
01041 
01042                 if(IR(M[8])!=0)                 return false;
01043                 if(IR(M[9])!=0)                 return false;
01044                 if(IR(M[10])!=F32_VALUE_1)      return false;
01045                 if(IR(M[11])!=0)                return false;
01046 
01047                 if(IR(M[12])!=0)                return false;
01048                 if(IR(M[13])!=0)                return false;
01049                 if(IR(M[13])!=0)                return false;
01050                 if(IR(M[15])!=F32_VALUE_1)      return false;
01051 
01052 #if defined ( USE_MATRIX_TEST )
01053                 definitelyIdentityMatrix=true;
01054 #endif
01055                 return true;
01056         }
01057 
01058 
01059         template <class T>
01060         inline void CMatrix4<T>::rotateVect( vector3df& vect ) const
01061         {
01062                 vector3df tmp = vect;
01063                 vect.X = tmp.X*M[0] + tmp.Y*M[4] + tmp.Z*M[8];
01064                 vect.Y = tmp.X*M[1] + tmp.Y*M[5] + tmp.Z*M[9];
01065                 vect.Z = tmp.X*M[2] + tmp.Y*M[6] + tmp.Z*M[10];
01066         }
01067 
01069         template <class T>
01070         inline void CMatrix4<T>::rotateVect(core::vector3df& out, const core::vector3df& in) const
01071         {
01072                 out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
01073                 out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
01074                 out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
01075         }
01076 
01078         template <class T>
01079         inline void CMatrix4<T>::rotateVect(T *out, const core::vector3df& in) const
01080         {
01081                 out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
01082                 out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
01083                 out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
01084         }
01085 
01086         template <class T>
01087         inline void CMatrix4<T>::inverseRotateVect( vector3df& vect ) const
01088         {
01089                 vector3df tmp = vect;
01090                 vect.X = tmp.X*M[0] + tmp.Y*M[1] + tmp.Z*M[2];
01091                 vect.Y = tmp.X*M[4] + tmp.Y*M[5] + tmp.Z*M[6];
01092                 vect.Z = tmp.X*M[8] + tmp.Y*M[9] + tmp.Z*M[10];
01093         }
01094 
01095         template <class T>
01096         inline void CMatrix4<T>::transformVect( vector3df& vect) const
01097         {
01098                 f32 vector[3];
01099 
01100                 vector[0] = vect.X*M[0] + vect.Y*M[4] + vect.Z*M[8] + M[12];
01101                 vector[1] = vect.X*M[1] + vect.Y*M[5] + vect.Z*M[9] + M[13];
01102                 vector[2] = vect.X*M[2] + vect.Y*M[6] + vect.Z*M[10] + M[14];
01103 
01104                 vect.X = vector[0];
01105                 vect.Y = vector[1];
01106                 vect.Z = vector[2];
01107         }
01108 
01109         template <class T>
01110         inline void CMatrix4<T>::transformVect( vector3df& out, const vector3df& in) const
01111         {
01112                 out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
01113                 out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
01114                 out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
01115         }
01116 
01117 
01118         template <class T>
01119         inline void CMatrix4<T>::transformVect(T *out, const core::vector3df &in) const
01120         {
01121                 out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
01122                 out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
01123                 out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
01124                 out[3] = in.X*M[3] + in.Y*M[7] + in.Z*M[11] + M[15];
01125         }
01126 
01127         template <class T>
01128         inline void CMatrix4<T>::transformVec3(T *out, const T * in) const
01129         {
01130                 out[0] = in[0]*M[0] + in[1]*M[4] + in[2]*M[8] + M[12];
01131                 out[1] = in[0]*M[1] + in[1]*M[5] + in[2]*M[9] + M[13];
01132                 out[2] = in[0]*M[2] + in[1]*M[6] + in[2]*M[10] + M[14];
01133         }
01134 
01135 
01137         template <class T>
01138         inline void CMatrix4<T>::transformPlane( core::plane3d<f32> &plane) const
01139         {
01140                 vector3df member;
01141                 // Transform the plane member point, i.e. rotate, translate and scale it.
01142                 transformVect(member, plane.getMemberPoint());
01143 
01144                 // Transform the normal by the transposed inverse of the matrix
01145                 CMatrix4<T> transposedInverse(*this, EM4CONST_INVERSE_TRANSPOSED);
01146                 vector3df normal = plane.Normal;
01147                 transposedInverse.transformVect(normal);
01148 
01149                 plane.setPlane(member, normal);
01150         }
01151 
01153         template <class T>
01154         inline void CMatrix4<T>::transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const
01155         {
01156                 out = in;
01157                 transformPlane( out );
01158         }
01159 
01161         template <class T>
01162         inline void CMatrix4<T>::transformBox(core::aabbox3d<f32>& box) const
01163         {
01164 #if defined ( USE_MATRIX_TEST )
01165                 if (isIdentity())
01166                         return;
01167 #endif
01168 
01169                 transformVect(box.MinEdge);
01170                 transformVect(box.MaxEdge);
01171                 box.repair();
01172         }
01173 
01175         template <class T>
01176         inline void CMatrix4<T>::transformBoxEx(core::aabbox3d<f32>& box) const
01177         {
01178 #if defined ( USE_MATRIX_TEST )
01179                 if (isIdentity())
01180                         return;
01181 #endif
01182 
01183                 const f32 Amin[3] = {box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z};
01184                 const f32 Amax[3] = {box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z};
01185 
01186                 f32 Bmin[3];
01187                 f32 Bmax[3];
01188 
01189                 Bmin[0] = Bmax[0] = M[12];
01190                 Bmin[1] = Bmax[1] = M[13];
01191                 Bmin[2] = Bmax[2] = M[14];
01192 
01193                 const CMatrix4<T> &m = *this;
01194 
01195                 for (u32 i = 0; i < 3; ++i)
01196                 {
01197                         for (u32 j = 0; j < 3; ++j)
01198                         {
01199                                 const f32 a = m(j,i) * Amin[j];
01200                                 const f32 b = m(j,i) * Amax[j];
01201 
01202                                 if (a < b)
01203                                 {
01204                                         Bmin[i] += a;
01205                                         Bmax[i] += b;
01206                                 }
01207                                 else
01208                                 {
01209                                         Bmin[i] += b;
01210                                         Bmax[i] += a;
01211                                 }
01212                         }
01213                 }
01214 
01215                 box.MinEdge.X = Bmin[0];
01216                 box.MinEdge.Y = Bmin[1];
01217                 box.MinEdge.Z = Bmin[2];
01218 
01219                 box.MaxEdge.X = Bmax[0];
01220                 box.MaxEdge.Y = Bmax[1];
01221                 box.MaxEdge.Z = Bmax[2];
01222         }
01223 
01224 
01226         template <class T>
01227         inline void CMatrix4<T>::multiplyWith1x4Matrix(T* matrix) const
01228         {
01229                 /*
01230                 0  1  2  3
01231                 4  5  6  7
01232                 8  9  10 11
01233                 12 13 14 15
01234                 */
01235 
01236                 T mat[4];
01237                 mat[0] = matrix[0];
01238                 mat[1] = matrix[1];
01239                 mat[2] = matrix[2];
01240                 mat[3] = matrix[3];
01241 
01242                 matrix[0] = M[0]*mat[0] + M[4]*mat[1] + M[8]*mat[2] + M[12]*mat[3];
01243                 matrix[1] = M[1]*mat[0] + M[5]*mat[1] + M[9]*mat[2] + M[13]*mat[3];
01244                 matrix[2] = M[2]*mat[0] + M[6]*mat[1] + M[10]*mat[2] + M[14]*mat[3];
01245                 matrix[3] = M[3]*mat[0] + M[7]*mat[1] + M[11]*mat[2] + M[15]*mat[3];
01246         }
01247 
01248         template <class T>
01249         inline void CMatrix4<T>::inverseTranslateVect( vector3df& vect ) const
01250         {
01251                 vect.X = vect.X-M[12];
01252                 vect.Y = vect.Y-M[13];
01253                 vect.Z = vect.Z-M[14];
01254         }
01255 
01256         template <class T>
01257         inline void CMatrix4<T>::translateVect( vector3df& vect ) const
01258         {
01259                 vect.X = vect.X+M[12];
01260                 vect.Y = vect.Y+M[13];
01261                 vect.Z = vect.Z+M[14];
01262         }
01263 
01264 
01265         template <class T>
01266         inline bool CMatrix4<T>::getInverse(CMatrix4<T>& out) const
01267         {
01271 
01272 #if defined ( USE_MATRIX_TEST )
01273                 if ( this->isIdentity() )
01274                 {
01275                         out=*this;
01276                         return true;
01277                 }
01278 #endif
01279                 const CMatrix4<T> &m = *this;
01280 
01281                 f32 d = (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) * (m(2, 2) * m(3, 3) - m(2, 3) * m(3, 2)) -
01282                         (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) +
01283                         (m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1)) +
01284                         (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) -
01285                         (m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) +
01286                         (m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0));
01287 
01288                 if( core::iszero ( d ) )
01289                         return false;
01290 
01291                 d = core::reciprocal ( d );
01292 
01293                 out(0, 0) = d * (m(1, 1) * (m(2, 2) * m(3, 3) - m(2, 3) * m(3, 2)) +
01294                                 m(1, 2) * (m(2, 3) * m(3, 1) - m(2, 1) * m(3, 3)) +
01295                                 m(1, 3) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1)));
01296                 out(0, 1) = d * (m(2, 1) * (m(0, 2) * m(3, 3) - m(0, 3) * m(3, 2)) +
01297                                 m(2, 2) * (m(0, 3) * m(3, 1) - m(0, 1) * m(3, 3)) +
01298                                 m(2, 3) * (m(0, 1) * m(3, 2) - m(0, 2) * m(3, 1)));
01299                 out(0, 2) = d * (m(3, 1) * (m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) +
01300                                 m(3, 2) * (m(0, 3) * m(1, 1) - m(0, 1) * m(1, 3)) +
01301                                 m(3, 3) * (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)));
01302                 out(0, 3) = d * (m(0, 1) * (m(1, 3) * m(2, 2) - m(1, 2) * m(2, 3)) +
01303                                 m(0, 2) * (m(1, 1) * m(2, 3) - m(1, 3) * m(2, 1)) +
01304                                 m(0, 3) * (m(1, 2) * m(2, 1) - m(1, 1) * m(2, 2)));
01305                 out(1, 0) = d * (m(1, 2) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) +
01306                                 m(1, 3) * (m(2, 2) * m(3, 0) - m(2, 0) * m(3, 2)) +
01307                                 m(1, 0) * (m(2, 3) * m(3, 2) - m(2, 2) * m(3, 3)));
01308                 out(1, 1) = d * (m(2, 2) * (m(0, 0) * m(3, 3) - m(0, 3) * m(3, 0)) +
01309                                 m(2, 3) * (m(0, 2) * m(3, 0) - m(0, 0) * m(3, 2)) +
01310                                 m(2, 0) * (m(0, 3) * m(3, 2) - m(0, 2) * m(3, 3)));
01311                 out(1, 2) = d * (m(3, 2) * (m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) +
01312                                 m(3, 3) * (m(0, 2) * m(1, 0) - m(0, 0) * m(1, 2)) +
01313                                 m(3, 0) * (m(0, 3) * m(1, 2) - m(0, 2) * m(1, 3)));
01314                 out(1, 3) = d * (m(0, 2) * (m(1, 3) * m(2, 0) - m(1, 0) * m(2, 3)) +
01315                                 m(0, 3) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) +
01316                                 m(0, 0) * (m(1, 2) * m(2, 3) - m(1, 3) * m(2, 2)));
01317                 out(2, 0) = d * (m(1, 3) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0)) +
01318                                 m(1, 0) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) +
01319                                 m(1, 1) * (m(2, 3) * m(3, 0) - m(2, 0) * m(3, 3)));
01320                 out(2, 1) = d * (m(2, 3) * (m(0, 0) * m(3, 1) - m(0, 1) * m(3, 0)) +
01321                                 m(2, 0) * (m(0, 1) * m(3, 3) - m(0, 3) * m(3, 1)) +
01322                                 m(2, 1) * (m(0, 3) * m(3, 0) - m(0, 0) * m(3, 3)));
01323                 out(2, 2) = d * (m(3, 3) * (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) +
01324                                 m(3, 0) * (m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) +
01325                                 m(3, 1) * (m(0, 3) * m(1, 0) - m(0, 0) * m(1, 3)));
01326                 out(2, 3) = d * (m(0, 3) * (m(1, 1) * m(2, 0) - m(1, 0) * m(2, 1)) +
01327                                 m(0, 0) * (m(1, 3) * m(2, 1) - m(1, 1) * m(2, 3)) +
01328                                 m(0, 1) * (m(1, 0) * m(2, 3) - m(1, 3) * m(2, 0)));
01329                 out(3, 0) = d * (m(1, 0) * (m(2, 2) * m(3, 1) - m(2, 1) * m(3, 2)) +
01330                                 m(1, 1) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) +
01331                                 m(1, 2) * (m(2, 1) * m(3, 0) - m(2, 0) * m(3, 1)));
01332                 out(3, 1) = d * (m(2, 0) * (m(0, 2) * m(3, 1) - m(0, 1) * m(3, 2)) +
01333                                 m(2, 1) * (m(0, 0) * m(3, 2) - m(0, 2) * m(3, 0)) +
01334                                 m(2, 2) * (m(0, 1) * m(3, 0) - m(0, 0) * m(3, 1)));
01335                 out(3, 2) = d * (m(3, 0) * (m(0, 2) * m(1, 1) - m(0, 1) * m(1, 2)) +
01336                                 m(3, 1) * (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) +
01337                                 m(3, 2) * (m(0, 1) * m(1, 0) - m(0, 0) * m(1, 1)));
01338                 out(3, 3) = d * (m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) +
01339                                 m(0, 1) * (m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2)) +
01340                                 m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0)));
01341 
01342 #if defined ( USE_MATRIX_TEST )
01343                 out.definitelyIdentityMatrix = definitelyIdentityMatrix;
01344 #endif
01345                 return true;
01346         }
01347 
01348 
01351         template <class T>
01352         inline bool CMatrix4<T>::getInversePrimitive ( CMatrix4<T>& out ) const
01353         {
01354                 out.M[0 ] = M[0];
01355                 out.M[1 ] = M[4];
01356                 out.M[2 ] = M[8];
01357                 out.M[3 ] = 0;
01358 
01359                 out.M[4 ] = M[1];
01360                 out.M[5 ] = M[5];
01361                 out.M[6 ] = M[9];
01362                 out.M[7 ] = 0;
01363 
01364                 out.M[8 ] = M[2];
01365                 out.M[9 ] = M[6];
01366                 out.M[10] = M[10];
01367                 out.M[11] = 0;
01368 
01369                 out.M[12] = (T)-(M[12]*M[0] + M[13]*M[1] + M[14]*M[2]);
01370                 out.M[13] = (T)-(M[12]*M[4] + M[13]*M[5] + M[14]*M[6]);
01371                 out.M[14] = (T)-(M[12]*M[8] + M[13]*M[9] + M[14]*M[10]);
01372                 out.M[15] = 1;
01373 
01374 #if defined ( USE_MATRIX_TEST )
01375                 out.definitelyIdentityMatrix = definitelyIdentityMatrix;
01376 #endif
01377                 return true;
01378         }
01379 
01382         template <class T>
01383         inline bool CMatrix4<T>::makeInverse()
01384         {
01385 #if defined ( USE_MATRIX_TEST )
01386                 if (definitelyIdentityMatrix)
01387                         return true;
01388 #endif
01389                 CMatrix4<T> temp ( EM4CONST_NOTHING );
01390 
01391                 if (getInverse(temp))
01392                 {
01393                         *this = temp;
01394                         return true;
01395                 }
01396 
01397                 return false;
01398         }
01399 
01400 
01401         template <class T>
01402         inline CMatrix4<T>& CMatrix4<T>::operator=(const CMatrix4<T> &other)
01403         {
01404                 if (this==&other)
01405                         return *this;
01406                 memcpy(M, other.M, 16*sizeof(T));
01407 #if defined ( USE_MATRIX_TEST )
01408                 definitelyIdentityMatrix=other.definitelyIdentityMatrix;
01409 #endif
01410                 return *this;
01411         }
01412 
01413 
01414         template <class T>
01415         inline CMatrix4<T>& CMatrix4<T>::operator=(const T& scalar)
01416         {
01417                 for (s32 i = 0; i < 16; ++i)
01418                         M[i]=scalar;
01419 
01420 #if defined ( USE_MATRIX_TEST )
01421                 definitelyIdentityMatrix=false;
01422 #endif
01423                 return *this;
01424         }
01425 
01426 
01427         template <class T>
01428         inline bool CMatrix4<T>::operator==(const CMatrix4<T> &other) const
01429         {
01430 #if defined ( USE_MATRIX_TEST )
01431                 if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
01432                         return true;
01433 #endif
01434                 for (s32 i = 0; i < 16; ++i)
01435                         if (M[i] != other.M[i])
01436                                 return false;
01437 
01438                 return true;
01439         }
01440 
01441 
01442         template <class T>
01443         inline bool CMatrix4<T>::operator!=(const CMatrix4<T> &other) const
01444         {
01445                 return !(*this == other);
01446         }
01447 
01448 
01449         // Builds a right-handed perspective projection matrix based on a field of view
01450         template <class T>
01451         inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovRH(
01452                         f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar)
01453         {
01454                 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
01455                 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
01456                 const T w = static_cast<T>(h / aspectRatio);
01457 
01458                 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
01459                 M[0] = w;
01460                 M[1] = 0;
01461                 M[2] = 0;
01462                 M[3] = 0;
01463 
01464                 M[4] = 0;
01465                 M[5] = (T)h;
01466                 M[6] = 0;
01467                 M[7] = 0;
01468 
01469                 M[8] = 0;
01470                 M[9] = 0;
01471                 M[10] = (T)(zFar/(zNear-zFar)); // DirectX version
01472 //              M[10] = (T)(zFar+zNear/(zNear-zFar)); // OpenGL version
01473                 M[11] = -1;
01474 
01475                 M[12] = 0;
01476                 M[13] = 0;
01477                 M[14] = (T)(zNear*zFar/(zNear-zFar)); // DirectX version
01478 //              M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar)); // OpenGL version
01479                 M[15] = 0;
01480 
01481 #if defined ( USE_MATRIX_TEST )
01482                 definitelyIdentityMatrix=false;
01483 #endif
01484                 return *this;
01485         }
01486 
01487 
01488         // Builds a left-handed perspective projection matrix based on a field of view
01489         template <class T>
01490         inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovLH(
01491                         f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar)
01492         {
01493                 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
01494                 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
01495                 const T w = static_cast<T>(h / aspectRatio);
01496 
01497                 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
01498                 M[0] = w;
01499                 M[1] = 0;
01500                 M[2] = 0;
01501                 M[3] = 0;
01502 
01503                 M[4] = 0;
01504                 M[5] = (T)h;
01505                 M[6] = 0;
01506                 M[7] = 0;
01507 
01508                 M[8] = 0;
01509                 M[9] = 0;
01510                 M[10] = (T)(zFar/(zFar-zNear));
01511                 M[11] = 1;
01512 
01513                 M[12] = 0;
01514                 M[13] = 0;
01515                 M[14] = (T)(-zNear*zFar/(zFar-zNear));
01516                 M[15] = 0;
01517 
01518 #if defined ( USE_MATRIX_TEST )
01519                 definitelyIdentityMatrix=false;
01520 #endif
01521                 return *this;
01522         }
01523 
01524 
01525         // Builds a left-handed perspective projection matrix based on a field of view, with far plane culling at infinity
01526         template <class T>
01527         inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovInfinityLH(
01528                         f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon)
01529         {
01530                 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
01531                 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
01532                 const T w = static_cast<T>(h / aspectRatio);
01533 
01534                 M[0] = w;
01535                 M[1] = 0;
01536                 M[2] = 0;
01537                 M[3] = 0;
01538 
01539                 M[4] = 0;
01540                 M[5] = (T)h;
01541                 M[6] = 0;
01542                 M[7] = 0;
01543 
01544                 M[8] = 0;
01545                 M[9] = 0;
01546                 M[10] = (T)(1.f-epsilon);
01547                 M[11] = 1;
01548 
01549                 M[12] = 0;
01550                 M[13] = 0;
01551                 M[14] = (T)(zNear*(epsilon-1.f));
01552                 M[15] = 0;
01553 
01554 #if defined ( USE_MATRIX_TEST )
01555                 definitelyIdentityMatrix=false;
01556 #endif
01557                 return *this;
01558         }
01559 
01560 
01561         // Builds a left-handed orthogonal projection matrix.
01562         template <class T>
01563         inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoLH(
01564                         f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
01565         {
01566                 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
01567                 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
01568                 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
01569                 M[0] = (T)(2/widthOfViewVolume);
01570                 M[1] = 0;
01571                 M[2] = 0;
01572                 M[3] = 0;
01573 
01574                 M[4] = 0;
01575                 M[5] = (T)(2/heightOfViewVolume);
01576                 M[6] = 0;
01577                 M[7] = 0;
01578 
01579                 M[8] = 0;
01580                 M[9] = 0;
01581                 M[10] = (T)(1/(zFar-zNear));
01582                 M[11] = 0;
01583 
01584                 M[12] = 0;
01585                 M[13] = 0;
01586                 M[14] = (T)(zNear/(zNear-zFar));
01587                 M[15] = 1;
01588 
01589 #if defined ( USE_MATRIX_TEST )
01590                 definitelyIdentityMatrix=false;
01591 #endif
01592                 return *this;
01593         }
01594 
01595 
01596         // Builds a right-handed orthogonal projection matrix.
01597         template <class T>
01598         inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoRH(
01599                         f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
01600         {
01601                 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
01602                 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
01603                 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
01604                 M[0] = (T)(2/widthOfViewVolume);
01605                 M[1] = 0;
01606                 M[2] = 0;
01607                 M[3] = 0;
01608 
01609                 M[4] = 0;
01610                 M[5] = (T)(2/heightOfViewVolume);
01611                 M[6] = 0;
01612                 M[7] = 0;
01613 
01614                 M[8] = 0;
01615                 M[9] = 0;
01616                 M[10] = (T)(1/(zNear-zFar));
01617                 M[11] = 0;
01618 
01619                 M[12] = 0;
01620                 M[13] = 0;
01621                 M[14] = (T)(zNear/(zNear-zFar));
01622                 M[15] = 1;
01623 
01624 #if defined ( USE_MATRIX_TEST )
01625                 definitelyIdentityMatrix=false;
01626 #endif
01627                 return *this;
01628         }
01629 
01630 
01631         // Builds a right-handed perspective projection matrix.
01632         template <class T>
01633         inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveRH(
01634                         f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
01635         {
01636                 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
01637                 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
01638                 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
01639                 M[0] = (T)(2*zNear/widthOfViewVolume);
01640                 M[1] = 0;
01641                 M[2] = 0;
01642                 M[3] = 0;
01643 
01644                 M[4] = 0;
01645                 M[5] = (T)(2*zNear/heightOfViewVolume);
01646                 M[6] = 0;
01647                 M[7] = 0;
01648 
01649                 M[8] = 0;
01650                 M[9] = 0;
01651                 M[10] = (T)(zFar/(zNear-zFar));
01652                 M[11] = -1;
01653 
01654                 M[12] = 0;
01655                 M[13] = 0;
01656                 M[14] = (T)(zNear*zFar/(zNear-zFar));
01657                 M[15] = 0;
01658 
01659 #if defined ( USE_MATRIX_TEST )
01660                 definitelyIdentityMatrix=false;
01661 #endif
01662                 return *this;
01663         }
01664 
01665 
01666         // Builds a left-handed perspective projection matrix.
01667         template <class T>
01668         inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveLH(
01669                         f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
01670         {
01671                 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
01672                 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
01673                 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
01674                 M[0] = (T)(2*zNear/widthOfViewVolume);
01675                 M[1] = 0;
01676                 M[2] = 0;
01677                 M[3] = 0;
01678 
01679                 M[4] = 0;
01680                 M[5] = (T)(2*zNear/heightOfViewVolume);
01681                 M[6] = 0;
01682                 M[7] = 0;
01683 
01684                 M[8] = 0;
01685                 M[9] = 0;
01686                 M[10] = (T)(zFar/(zFar-zNear));
01687                 M[11] = 1;
01688 
01689                 M[12] = 0;
01690                 M[13] = 0;
01691                 M[14] = (T)(zNear*zFar/(zNear-zFar));
01692                 M[15] = 0;
01693 #if defined ( USE_MATRIX_TEST )
01694                 definitelyIdentityMatrix=false;
01695 #endif
01696                 return *this;
01697         }
01698 
01699 
01700         // Builds a matrix that flattens geometry into a plane.
01701         template <class T>
01702         inline CMatrix4<T>& CMatrix4<T>::buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point)
01703         {
01704                 plane.Normal.normalize();
01705                 const f32 d = plane.Normal.dotProduct(light);
01706 
01707                 M[ 0] = (T)(-plane.Normal.X * light.X + d);
01708                 M[ 1] = (T)(-plane.Normal.X * light.Y);
01709                 M[ 2] = (T)(-plane.Normal.X * light.Z);
01710                 M[ 3] = (T)(-plane.Normal.X * point);
01711 
01712                 M[ 4] = (T)(-plane.Normal.Y * light.X);
01713                 M[ 5] = (T)(-plane.Normal.Y * light.Y + d);
01714                 M[ 6] = (T)(-plane.Normal.Y * light.Z);
01715                 M[ 7] = (T)(-plane.Normal.Y * point);
01716 
01717                 M[ 8] = (T)(-plane.Normal.Z * light.X);
01718                 M[ 9] = (T)(-plane.Normal.Z * light.Y);
01719                 M[10] = (T)(-plane.Normal.Z * light.Z + d);
01720                 M[11] = (T)(-plane.Normal.Z * point);
01721 
01722                 M[12] = (T)(-plane.D * light.X);
01723                 M[13] = (T)(-plane.D * light.Y);
01724                 M[14] = (T)(-plane.D * light.Z);
01725                 M[15] = (T)(-plane.D * point + d);
01726 #if defined ( USE_MATRIX_TEST )
01727                 definitelyIdentityMatrix=false;
01728 #endif
01729                 return *this;
01730         }
01731 
01732         // Builds a left-handed look-at matrix.
01733         template <class T>
01734         inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixLH(
01735                                 const vector3df& position,
01736                                 const vector3df& target,
01737                                 const vector3df& upVector)
01738         {
01739                 vector3df zaxis = target - position;
01740                 zaxis.normalize();
01741 
01742                 vector3df xaxis = upVector.crossProduct(zaxis);
01743                 xaxis.normalize();
01744 
01745                 vector3df yaxis = zaxis.crossProduct(xaxis);
01746 
01747                 M[0] = (T)xaxis.X;
01748                 M[1] = (T)yaxis.X;
01749                 M[2] = (T)zaxis.X;
01750                 M[3] = 0;
01751 
01752                 M[4] = (T)xaxis.Y;
01753                 M[5] = (T)yaxis.Y;
01754                 M[6] = (T)zaxis.Y;
01755                 M[7] = 0;
01756 
01757                 M[8] = (T)xaxis.Z;
01758                 M[9] = (T)yaxis.Z;
01759                 M[10] = (T)zaxis.Z;
01760                 M[11] = 0;
01761 
01762                 M[12] = (T)-xaxis.dotProduct(position);
01763                 M[13] = (T)-yaxis.dotProduct(position);
01764                 M[14] = (T)-zaxis.dotProduct(position);
01765                 M[15] = 1;
01766 #if defined ( USE_MATRIX_TEST )
01767                 definitelyIdentityMatrix=false;
01768 #endif
01769                 return *this;
01770         }
01771 
01772 
01773         // Builds a right-handed look-at matrix.
01774         template <class T>
01775         inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixRH(
01776                                 const vector3df& position,
01777                                 const vector3df& target,
01778                                 const vector3df& upVector)
01779         {
01780                 vector3df zaxis = position - target;
01781                 zaxis.normalize();
01782 
01783                 vector3df xaxis = upVector.crossProduct(zaxis);
01784                 xaxis.normalize();
01785 
01786                 vector3df yaxis = zaxis.crossProduct(xaxis);
01787 
01788                 M[0] = (T)xaxis.X;
01789                 M[1] = (T)yaxis.X;
01790                 M[2] = (T)zaxis.X;
01791                 M[3] = 0;
01792 
01793                 M[4] = (T)xaxis.Y;
01794                 M[5] = (T)yaxis.Y;
01795                 M[6] = (T)zaxis.Y;
01796                 M[7] = 0;
01797 
01798                 M[8] = (T)xaxis.Z;
01799                 M[9] = (T)yaxis.Z;
01800                 M[10] = (T)zaxis.Z;
01801                 M[11] = 0;
01802 
01803                 M[12] = (T)-xaxis.dotProduct(position);
01804                 M[13] = (T)-yaxis.dotProduct(position);
01805                 M[14] = (T)-zaxis.dotProduct(position);
01806                 M[15] = 1;
01807 #if defined ( USE_MATRIX_TEST )
01808                 definitelyIdentityMatrix=false;
01809 #endif
01810                 return *this;
01811         }
01812 
01813 
01814         // creates a new matrix as interpolated matrix from this and the passed one.
01815         template <class T>
01816         inline CMatrix4<T> CMatrix4<T>::interpolate(const core::CMatrix4<T>& b, f32 time) const
01817         {
01818                 CMatrix4<T> mat ( EM4CONST_NOTHING );
01819 
01820                 for (u32 i=0; i < 16; i += 4)
01821                 {
01822                         mat.M[i+0] = (T)(M[i+0] + ( b.M[i+0] - M[i+0] ) * time);
01823                         mat.M[i+1] = (T)(M[i+1] + ( b.M[i+1] - M[i+1] ) * time);
01824                         mat.M[i+2] = (T)(M[i+2] + ( b.M[i+2] - M[i+2] ) * time);
01825                         mat.M[i+3] = (T)(M[i+3] + ( b.M[i+3] - M[i+3] ) * time);
01826                 }
01827                 return mat;
01828         }
01829 
01830 
01831         // returns transposed matrix
01832         template <class T>
01833         inline CMatrix4<T> CMatrix4<T>::getTransposed() const
01834         {
01835                 CMatrix4<T> t ( EM4CONST_NOTHING );
01836                 getTransposed ( t );
01837                 return t;
01838         }
01839 
01840 
01841         // returns transposed matrix
01842         template <class T>
01843         inline void CMatrix4<T>::getTransposed( CMatrix4<T>& o ) const
01844         {
01845                 o[ 0] = M[ 0];
01846                 o[ 1] = M[ 4];
01847                 o[ 2] = M[ 8];
01848                 o[ 3] = M[12];
01849 
01850                 o[ 4] = M[ 1];
01851                 o[ 5] = M[ 5];
01852                 o[ 6] = M[ 9];
01853                 o[ 7] = M[13];
01854 
01855                 o[ 8] = M[ 2];
01856                 o[ 9] = M[ 6];
01857                 o[10] = M[10];
01858                 o[11] = M[14];
01859 
01860                 o[12] = M[ 3];
01861                 o[13] = M[ 7];
01862                 o[14] = M[11];
01863                 o[15] = M[15];
01864 #if defined ( USE_MATRIX_TEST )
01865                 o.definitelyIdentityMatrix=definitelyIdentityMatrix;
01866 #endif
01867         }
01868 
01869 
01870         // used to scale <-1,-1><1,1> to viewport
01871         template <class T>
01872         inline CMatrix4<T>& CMatrix4<T>::buildNDCToDCMatrix( const core::rect<s32>& viewport, f32 zScale)
01873         {
01874                 const f32 scaleX = (viewport.getWidth() - 0.75f ) * 0.5f;
01875                 const f32 scaleY = -(viewport.getHeight() - 0.75f ) * 0.5f;
01876 
01877                 const f32 dx = -0.5f + ( (viewport.UpperLeftCorner.X + viewport.LowerRightCorner.X ) * 0.5f );
01878                 const f32 dy = -0.5f + ( (viewport.UpperLeftCorner.Y + viewport.LowerRightCorner.Y ) * 0.5f );
01879 
01880                 makeIdentity();
01881                 M[12] = (T)dx;
01882                 M[13] = (T)dy;
01883                 return setScale(core::vector3d<T>((T)scaleX, (T)scaleY, (T)zScale));
01884         }
01885 
01887 
01892         template <class T>
01893         inline CMatrix4<T>& CMatrix4<T>::buildRotateFromTo(const core::vector3df& from, const core::vector3df& to)
01894         {
01895                 // unit vectors
01896                 core::vector3df f(from);
01897                 core::vector3df t(to);
01898                 f.normalize();
01899                 t.normalize();
01900 
01901                 // axis multiplication by sin
01902                 core::vector3df vs(t.crossProduct(f));
01903 
01904                 // axis of rotation
01905                 core::vector3df v(vs);
01906                 v.normalize();
01907 
01908                 // cosinus angle
01909                 T ca = f.dotProduct(t); 
01910 
01911                 core::vector3df vt(v * (1 - ca));
01912 
01913                 M[0] = vt.X * v.X + ca;
01914                 M[5] = vt.Y * v.Y + ca;
01915                 M[10] = vt.Z * v.Z + ca;
01916 
01917                 vt.X *= v.Y;
01918                 vt.Z *= v.X;
01919                 vt.Y *= v.Z;
01920 
01921                 M[1] = vt.X - vs.Z;
01922                 M[2] = vt.Z + vs.Y;
01923                 M[3] = 0;
01924 
01925                 M[4] = vt.X + vs.Z;
01926                 M[6] = vt.Y - vs.X;
01927                 M[7] = 0;
01928 
01929                 M[8] = vt.Z - vs.Y;
01930                 M[9] = vt.Y + vs.X;
01931                 M[11] = 0;
01932 
01933                 M[12] = 0;
01934                 M[13] = 0;
01935                 M[14] = 0;
01936                 M[15] = 1;
01937 
01938                 return *this;
01939         }
01940 
01942 
01948         template <class T>
01949         inline void CMatrix4<T>::buildAxisAlignedBillboard(
01950                                 const core::vector3df& camPos,
01951                                 const core::vector3df& center,
01952                                 const core::vector3df& translation,
01953                                 const core::vector3df& axis,
01954                                 const core::vector3df& from)
01955         {
01956                 // axis of rotation
01957                 core::vector3df up = axis;
01958                 up.normalize();
01959                 const core::vector3df forward = (camPos - center).normalize();
01960                 const core::vector3df right = up.crossProduct(forward).normalize();
01961 
01962                 // correct look vector
01963                 const core::vector3df look = right.crossProduct(up);
01964 
01965                 // rotate from to
01966                 // axis multiplication by sin
01967                 const core::vector3df vs = look.crossProduct(from);
01968 
01969                 // cosinus angle
01970                 const f32 ca = from.dotProduct(look);   
01971 
01972                 core::vector3df vt(up * (1.f - ca));
01973 
01974                 M[0] = static_cast<T>(vt.X * up.X + ca);
01975                 M[5] = static_cast<T>(vt.Y * up.Y + ca);
01976                 M[10] = static_cast<T>(vt.Z * up.Z + ca);
01977 
01978                 vt.X *= up.Y;
01979                 vt.Z *= up.X;
01980                 vt.Y *= up.Z;
01981 
01982                 M[1] = static_cast<T>(vt.X - vs.Z);
01983                 M[2] = static_cast<T>(vt.Z + vs.Y);
01984                 M[3] = 0;
01985 
01986                 M[4] = static_cast<T>(vt.X + vs.Z);
01987                 M[6] = static_cast<T>(vt.Y - vs.X);
01988                 M[7] = 0;
01989 
01990                 M[8] = static_cast<T>(vt.Z - vs.Y);
01991                 M[9] = static_cast<T>(vt.Y + vs.X);
01992                 M[11] = 0;
01993 
01994                 setRotationCenter(center, translation);
01995         }
01996 
01997 
01999         template <class T>
02000         inline void CMatrix4<T>::setRotationCenter(const core::vector3df& center, const core::vector3df& translation)
02001         {
02002                 M[12] = -M[0]*center.X - M[4]*center.Y - M[8]*center.Z + (center.X - translation.X );
02003                 M[13] = -M[1]*center.X - M[5]*center.Y - M[9]*center.Z + (center.Y - translation.Y );
02004                 M[14] = -M[2]*center.X - M[6]*center.Y - M[10]*center.Z + (center.Z - translation.Z );
02005                 M[15] = (T) 1.0;
02006 #if defined ( USE_MATRIX_TEST )
02007                 definitelyIdentityMatrix=false;
02008 #endif
02009         }
02010 
02023         template <class T>
02024         inline CMatrix4<T>& CMatrix4<T>::buildTextureTransform( f32 rotateRad,
02025                         const core::vector2df &rotatecenter,
02026                         const core::vector2df &translate,
02027                         const core::vector2df &scale)
02028         {
02029                 const f32 c = cosf(rotateRad);
02030                 const f32 s = sinf(rotateRad);
02031 
02032                 M[0] = (T)(c * scale.X);
02033                 M[1] = (T)(s * scale.Y);
02034                 M[2] = 0;
02035                 M[3] = 0;
02036 
02037                 M[4] = (T)(-s * scale.X);
02038                 M[5] = (T)(c * scale.Y);
02039                 M[6] = 0;
02040                 M[7] = 0;
02041 
02042                 M[8] = (T)(c * scale.X * rotatecenter.X + -s * rotatecenter.Y + translate.X);
02043                 M[9] = (T)(s * scale.Y * rotatecenter.X +  c * rotatecenter.Y + translate.Y);
02044                 M[10] = 1;
02045                 M[11] = 0;
02046 
02047                 M[12] = 0;
02048                 M[13] = 0;
02049                 M[14] = 0;
02050                 M[15] = 1;
02051 #if defined ( USE_MATRIX_TEST )
02052                 definitelyIdentityMatrix=false;
02053 #endif
02054                 return *this;
02055         }
02056 
02057 
02058         // rotate about z axis, center ( 0.5, 0.5 )
02059         template <class T>
02060         inline CMatrix4<T>& CMatrix4<T>::setTextureRotationCenter( f32 rotateRad )
02061         {
02062                 const f32 c = cosf(rotateRad);
02063                 const f32 s = sinf(rotateRad);
02064                 M[0] = (T)c;
02065                 M[1] = (T)s;
02066 
02067                 M[4] = (T)-s;
02068                 M[5] = (T)c;
02069 
02070                 M[8] = (T)(0.5f * ( s - c) + 0.5f);
02071                 M[9] = (T)(-0.5f * ( s + c) + 0.5f);
02072 
02073 #if defined ( USE_MATRIX_TEST )
02074                 definitelyIdentityMatrix = definitelyIdentityMatrix && (rotateRad==0.0f);
02075 #endif
02076                 return *this;
02077         }
02078 
02079 
02080         template <class T>
02081         inline CMatrix4<T>& CMatrix4<T>::setTextureTranslate ( f32 x, f32 y )
02082         {
02083                 M[8] = (T)x;
02084                 M[9] = (T)y;
02085 
02086 #if defined ( USE_MATRIX_TEST )
02087                 definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f);
02088 #endif
02089                 return *this;
02090         }
02091 
02092 
02093         template <class T>
02094         inline CMatrix4<T>& CMatrix4<T>::setTextureTranslateTransposed ( f32 x, f32 y )
02095         {
02096                 M[2] = (T)x;
02097                 M[6] = (T)y;
02098 
02099 #if defined ( USE_MATRIX_TEST )
02100                 definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f) ;
02101 #endif
02102                 return *this;
02103         }
02104 
02105         template <class T>
02106         inline CMatrix4<T>& CMatrix4<T>::setTextureScale ( f32 sx, f32 sy )
02107         {
02108                 M[0] = (T)sx;
02109                 M[5] = (T)sy;
02110 #if defined ( USE_MATRIX_TEST )
02111                 definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
02112 #endif
02113                 return *this;
02114         }
02115 
02116 
02117         template <class T>
02118         inline CMatrix4<T>& CMatrix4<T>::setTextureScaleCenter( f32 sx, f32 sy )
02119         {
02120                 M[0] = (T)sx;
02121                 M[5] = (T)sy;
02122                 M[8] = (T)(0.5f - 0.5f * sx);
02123                 M[9] = (T)(0.5f - 0.5f * sy);
02124 
02125 #if defined ( USE_MATRIX_TEST )
02126                 definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
02127 #endif
02128                 return *this;
02129         }
02130 
02131 
02132         // sets all matrix data members at once
02133         template <class T>
02134         inline CMatrix4<T>& CMatrix4<T>::setM(const T* data)
02135         {
02136                 memcpy(M,data, 16*sizeof(T));
02137 
02138 #if defined ( USE_MATRIX_TEST )
02139                 definitelyIdentityMatrix=false;
02140 #endif
02141                 return *this;
02142         }
02143 
02144 
02145         // sets if the matrix is definitely identity matrix
02146         template <class T>
02147         inline void CMatrix4<T>::setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix)
02148         {
02149 #if defined ( USE_MATRIX_TEST )
02150                 definitelyIdentityMatrix = isDefinitelyIdentityMatrix;
02151 #endif
02152         }
02153 
02154 
02155         // gets if the matrix is definitely identity matrix
02156         template <class T>
02157         inline bool CMatrix4<T>::getDefinitelyIdentityMatrix() const
02158         {
02159 #if defined ( USE_MATRIX_TEST )
02160                 return definitelyIdentityMatrix;
02161 #else
02162                 return false;
02163 #endif
02164         }
02165 
02166 
02168         template <class T>
02169         inline bool CMatrix4<T>::equals(const core::CMatrix4<T>& other, const T tolerance) const
02170         {
02171 #if defined ( USE_MATRIX_TEST )
02172                 if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
02173                         return true;
02174 #endif
02175                 for (s32 i = 0; i < 16; ++i)
02176                         if (!core::equals(M[i],other.M[i], tolerance))
02177                                 return false;
02178 
02179                 return true;
02180         }
02181 
02182 
02183         // Multiply by scalar.
02184         template <class T>
02185         inline CMatrix4<T> operator*(const T scalar, const CMatrix4<T>& mat)
02186         {
02187                 return mat*scalar;
02188         }
02189 
02190 
02192         typedef CMatrix4<f32> matrix4;
02193 
02195         IRRLICHT_API extern const matrix4 IdentityMatrix;
02196 
02197 } // end namespace core
02198 } // end namespace irr
02199 
02200 #endif
02201