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