| 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
    01202     template <class T>
    01203     inline void CMatrix4<T>::transformBox(core::aabbox3d<f32>& box) const
    01204     {
    01205 #if defined ( USE_MATRIX_TEST )
    01206         if (isIdentity())
    01207             return;
    01208 #endif
    01209
    01210         transformVect(box.MinEdge);
    01211         transformVect(box.MaxEdge);
    01212         box.repair();
    01213     }
    01214
    01216     template <class T>
    01217     inline void CMatrix4<T>::transformBoxEx(core::aabbox3d<f32>& box) const
    01218     {
    01219 #if defined ( USE_MATRIX_TEST )
    01220         if (isIdentity())
    01221             return;
    01222 #endif
    01223
    01224         const f32 Amin[3] = {box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z};
    01225         const f32 Amax[3] = {box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z};
    01226
    01227         f32 Bmin[3];
    01228         f32 Bmax[3];
    01229
    01230         Bmin[0] = Bmax[0] = M[12];
    01231         Bmin[1] = Bmax[1] = M[13];
    01232         Bmin[2] = Bmax[2] = M[14];
    01233
    01234         const CMatrix4<T> &m = *this;
    01235
    01236         for (u32 i = 0; i < 3; ++i)
    01237         {
    01238             for (u32 j = 0; j < 3; ++j)
    01239             {
    01240                 const f32 a = m(j,i) * Amin[j];
    01241                 const f32 b = m(j,i) * Amax[j];
    01242
    01243                 if (a < b)
    01244                 {
    01245                     Bmin[i] += a;
    01246                     Bmax[i] += b;
    01247                 }
    01248                 else
    01249                 {
    01250                     Bmin[i] += b;
    01251                     Bmax[i] += a;
    01252                 }
    01253             }
    01254         }
    01255
    01256         box.MinEdge.X = Bmin[0];
    01257         box.MinEdge.Y = Bmin[1];
    01258         box.MinEdge.Z = Bmin[2];
    01259
    01260         box.MaxEdge.X = Bmax[0];
    01261         box.MaxEdge.Y = Bmax[1];
    01262         box.MaxEdge.Z = Bmax[2];
    01263     }
    01264
    01265
    01267     template <class T>
    01268     inline void CMatrix4<T>::multiplyWith1x4Matrix(T* matrix) const
    01269     {
    01270         /*
    01271         0  1  2  3
    01272         4  5  6  7
    01273         8  9  10 11
    01274         12 13 14 15
    01275         */
    01276
    01277         T mat[4];
    01278         mat[0] = matrix[0];
    01279         mat[1] = matrix[1];
    01280         mat[2] = matrix[2];
    01281         mat[3] = matrix[3];
    01282
    01283         matrix[0] = M[0]*mat[0] + M[4]*mat[1] + M[8]*mat[2] + M[12]*mat[3];
    01284         matrix[1] = M[1]*mat[0] + M[5]*mat[1] + M[9]*mat[2] + M[13]*mat[3];
    01285         matrix[2] = M[2]*mat[0] + M[6]*mat[1] + M[10]*mat[2] + M[14]*mat[3];
    01286         matrix[3] = M[3]*mat[0] + M[7]*mat[1] + M[11]*mat[2] + M[15]*mat[3];
    01287     }
    01288
    01289     template <class T>
    01290     inline void CMatrix4<T>::inverseTranslateVect( vector3df& vect ) const
    01291     {
    01292         vect.X = vect.X-M[12];
    01293         vect.Y = vect.Y-M[13];
    01294         vect.Z = vect.Z-M[14];
    01295     }
    01296
    01297     template <class T>
    01298     inline void CMatrix4<T>::translateVect( vector3df& vect ) const
    01299     {
    01300         vect.X = vect.X+M[12];
    01301         vect.Y = vect.Y+M[13];
    01302         vect.Z = vect.Z+M[14];
    01303     }
    01304
    01305
    01306     template <class T>
    01307     inline bool CMatrix4<T>::getInverse(CMatrix4<T>& out) const
    01308     {
    01312
    01313 #if defined ( USE_MATRIX_TEST )
    01314         if ( this->isIdentity() )
    01315         {
    01316             out=*this;
    01317             return true;
    01318         }
    01319 #endif
    01320         const CMatrix4<T> &m = *this;
    01321
    01322         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)) -
    01323             (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) +
    01324             (m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1)) +
    01325             (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) -
    01326             (m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) +
    01327             (m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0));
    01328
    01329         if( core::iszero ( d, FLT_MIN ) )
    01330             return false;
    01331
    01332         d = core::reciprocal ( d );
    01333
    01334         out(0, 0) = d * (m(1, 1) * (m(2, 2) * m(3, 3) - m(2, 3) * m(3, 2)) +
    01335                 m(1, 2) * (m(2, 3) * m(3, 1) - m(2, 1) * m(3, 3)) +
    01336                 m(1, 3) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1)));
    01337         out(0, 1) = d * (m(2, 1) * (m(0, 2) * m(3, 3) - m(0, 3) * m(3, 2)) +
    01338                 m(2, 2) * (m(0, 3) * m(3, 1) - m(0, 1) * m(3, 3)) +
    01339                 m(2, 3) * (m(0, 1) * m(3, 2) - m(0, 2) * m(3, 1)));
    01340         out(0, 2) = d * (m(3, 1) * (m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) +
    01341                 m(3, 2) * (m(0, 3) * m(1, 1) - m(0, 1) * m(1, 3)) +
    01342                 m(3, 3) * (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)));
    01343         out(0, 3) = d * (m(0, 1) * (m(1, 3) * m(2, 2) - m(1, 2) * m(2, 3)) +
    01344                 m(0, 2) * (m(1, 1) * m(2, 3) - m(1, 3) * m(2, 1)) +
    01345                 m(0, 3) * (m(1, 2) * m(2, 1) - m(1, 1) * m(2, 2)));
    01346         out(1, 0) = d * (m(1, 2) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) +
    01347                 m(1, 3) * (m(2, 2) * m(3, 0) - m(2, 0) * m(3, 2)) +
    01348                 m(1, 0) * (m(2, 3) * m(3, 2) - m(2, 2) * m(3, 3)));
    01349         out(1, 1) = d * (m(2, 2) * (m(0, 0) * m(3, 3) - m(0, 3) * m(3, 0)) +
    01350                 m(2, 3) * (m(0, 2) * m(3, 0) - m(0, 0) * m(3, 2)) +
    01351                 m(2, 0) * (m(0, 3) * m(3, 2) - m(0, 2) * m(3, 3)));
    01352         out(1, 2) = d * (m(3, 2) * (m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) +
    01353                 m(3, 3) * (m(0, 2) * m(1, 0) - m(0, 0) * m(1, 2)) +
    01354                 m(3, 0) * (m(0, 3) * m(1, 2) - m(0, 2) * m(1, 3)));
    01355         out(1, 3) = d * (m(0, 2) * (m(1, 3) * m(2, 0) - m(1, 0) * m(2, 3)) +
    01356                 m(0, 3) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) +
    01357                 m(0, 0) * (m(1, 2) * m(2, 3) - m(1, 3) * m(2, 2)));
    01358         out(2, 0) = d * (m(1, 3) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0)) +
    01359                 m(1, 0) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) +
    01360                 m(1, 1) * (m(2, 3) * m(3, 0) - m(2, 0) * m(3, 3)));
    01361         out(2, 1) = d * (m(2, 3) * (m(0, 0) * m(3, 1) - m(0, 1) * m(3, 0)) +
    01362                 m(2, 0) * (m(0, 1) * m(3, 3) - m(0, 3) * m(3, 1)) +
    01363                 m(2, 1) * (m(0, 3) * m(3, 0) - m(0, 0) * m(3, 3)));
    01364         out(2, 2) = d * (m(3, 3) * (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) +
    01365                 m(3, 0) * (m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) +
    01366                 m(3, 1) * (m(0, 3) * m(1, 0) - m(0, 0) * m(1, 3)));
    01367         out(2, 3) = d * (m(0, 3) * (m(1, 1) * m(2, 0) - m(1, 0) * m(2, 1)) +
    01368                 m(0, 0) * (m(1, 3) * m(2, 1) - m(1, 1) * m(2, 3)) +
    01369                 m(0, 1) * (m(1, 0) * m(2, 3) - m(1, 3) * m(2, 0)));
    01370         out(3, 0) = d * (m(1, 0) * (m(2, 2) * m(3, 1) - m(2, 1) * m(3, 2)) +
    01371                 m(1, 1) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) +
    01372                 m(1, 2) * (m(2, 1) * m(3, 0) - m(2, 0) * m(3, 1)));
    01373         out(3, 1) = d * (m(2, 0) * (m(0, 2) * m(3, 1) - m(0, 1) * m(3, 2)) +
    01374                 m(2, 1) * (m(0, 0) * m(3, 2) - m(0, 2) * m(3, 0)) +
    01375                 m(2, 2) * (m(0, 1) * m(3, 0) - m(0, 0) * m(3, 1)));
    01376         out(3, 2) = d * (m(3, 0) * (m(0, 2) * m(1, 1) - m(0, 1) * m(1, 2)) +
    01377                 m(3, 1) * (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) +
    01378                 m(3, 2) * (m(0, 1) * m(1, 0) - m(0, 0) * m(1, 1)));
    01379         out(3, 3) = d * (m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) +
    01380                 m(0, 1) * (m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2)) +
    01381                 m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0)));
    01382
    01383 #if defined ( USE_MATRIX_TEST )
    01384         out.definitelyIdentityMatrix = definitelyIdentityMatrix;
    01385 #endif
    01386         return true;
    01387     }
    01388
    01389
    01392     template <class T>
    01393     inline bool CMatrix4<T>::getInversePrimitive ( CMatrix4<T>& out ) const
    01394     {
    01395         out.M[0 ] = M[0];
    01396         out.M[1 ] = M[4];
    01397         out.M[2 ] = M[8];
    01398         out.M[3 ] = 0;
    01399
    01400         out.M[4 ] = M[1];
    01401         out.M[5 ] = M[5];
    01402         out.M[6 ] = M[9];
    01403         out.M[7 ] = 0;
    01404
    01405         out.M[8 ] = M[2];
    01406         out.M[9 ] = M[6];
    01407         out.M[10] = M[10];
    01408         out.M[11] = 0;
    01409
    01410         out.M[12] = (T)-(M[12]*M[0] + M[13]*M[1] + M[14]*M[2]);
    01411         out.M[13] = (T)-(M[12]*M[4] + M[13]*M[5] + M[14]*M[6]);
    01412         out.M[14] = (T)-(M[12]*M[8] + M[13]*M[9] + M[14]*M[10]);
    01413         out.M[15] = 1;
    01414
    01415 #if defined ( USE_MATRIX_TEST )
    01416         out.definitelyIdentityMatrix = definitelyIdentityMatrix;
    01417 #endif
    01418         return true;
    01419     }
    01420
    01423     template <class T>
    01424     inline bool CMatrix4<T>::makeInverse()
    01425     {
    01426 #if defined ( USE_MATRIX_TEST )
    01427         if (definitelyIdentityMatrix)
    01428             return true;
    01429 #endif
    01430         CMatrix4<T> temp ( EM4CONST_NOTHING );
    01431
    01432         if (getInverse(temp))
    01433         {
    01434             *this = temp;
    01435             return true;
    01436         }
    01437
    01438         return false;
    01439     }
    01440
    01441
    01442     template <class T>
    01443     inline CMatrix4<T>& CMatrix4<T>::operator=(const CMatrix4<T> &other)
    01444     {
    01445         if (this==&other)
    01446             return *this;
    01447         memcpy(M, other.M, 16*sizeof(T));
    01448 #if defined ( USE_MATRIX_TEST )
    01449         definitelyIdentityMatrix=other.definitelyIdentityMatrix;
    01450 #endif
    01451         return *this;
    01452     }
    01453
    01454
    01455     template <class T>
    01456     inline CMatrix4<T>& CMatrix4<T>::operator=(const T& scalar)
    01457     {
    01458         for (s32 i = 0; i < 16; ++i)
    01459             M[i]=scalar;
    01460
    01461 #if defined ( USE_MATRIX_TEST )
    01462         definitelyIdentityMatrix=false;
    01463 #endif
    01464         return *this;
    01465     }
    01466
    01467
    01468     template <class T>
    01469     inline bool CMatrix4<T>::operator==(const CMatrix4<T> &other) const
    01470     {
    01471 #if defined ( USE_MATRIX_TEST )
    01472         if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
    01473             return true;
    01474 #endif
    01475         for (s32 i = 0; i < 16; ++i)
    01476             if (M[i] != other.M[i])
    01477                 return false;
    01478
    01479         return true;
    01480     }
    01481
    01482
    01483     template <class T>
    01484     inline bool CMatrix4<T>::operator!=(const CMatrix4<T> &other) const
    01485     {
    01486         return !(*this == other);
    01487     }
    01488
    01489
    01490     // Builds a right-handed perspective projection matrix based on a field of view
    01491     template <class T>
    01492     inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovRH(
    01493             f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar)
    01494     {
    01495         const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
    01496         _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
    01497         const T w = static_cast<T>(h / aspectRatio);
    01498
    01499         _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
    01500         M[0] = w;
    01501         M[1] = 0;
    01502         M[2] = 0;
    01503         M[3] = 0;
    01504
    01505         M[4] = 0;
    01506         M[5] = (T)h;
    01507         M[6] = 0;
    01508         M[7] = 0;
    01509
    01510         M[8] = 0;
    01511         M[9] = 0;
    01512         M[10] = (T)(zFar/(zNear-zFar)); // DirectX version
    01513 //      M[10] = (T)(zFar+zNear/(zNear-zFar)); // OpenGL version
    01514         M[11] = -1;
    01515
    01516         M[12] = 0;
    01517         M[13] = 0;
    01518         M[14] = (T)(zNear*zFar/(zNear-zFar)); // DirectX version
    01519 //      M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar)); // OpenGL version
    01520         M[15] = 0;
    01521
    01522 #if defined ( USE_MATRIX_TEST )
    01523         definitelyIdentityMatrix=false;
    01524 #endif
    01525         return *this;
    01526     }
    01527
    01528
    01529     // Builds a left-handed perspective projection matrix based on a field of view
    01530     template <class T>
    01531     inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovLH(
    01532             f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar)
    01533     {
    01534         const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
    01535         _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
    01536         const T w = static_cast<T>(h / aspectRatio);
    01537
    01538         _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
    01539         M[0] = w;
    01540         M[1] = 0;
    01541         M[2] = 0;
    01542         M[3] = 0;
    01543
    01544         M[4] = 0;
    01545         M[5] = (T)h;
    01546         M[6] = 0;
    01547         M[7] = 0;
    01548
    01549         M[8] = 0;
    01550         M[9] = 0;
    01551         M[10] = (T)(zFar/(zFar-zNear));
    01552         M[11] = 1;
    01553
    01554         M[12] = 0;
    01555         M[13] = 0;
    01556         M[14] = (T)(-zNear*zFar/(zFar-zNear));
    01557         M[15] = 0;
    01558
    01559 #if defined ( USE_MATRIX_TEST )
    01560         definitelyIdentityMatrix=false;
    01561 #endif
    01562         return *this;
    01563     }
    01564
    01565
    01566     // Builds a left-handed perspective projection matrix based on a field of view, with far plane culling at infinity
    01567     template <class T>
    01568     inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovInfinityLH(
    01569             f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon)
    01570     {
    01571         const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
    01572         _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
    01573         const T w = static_cast<T>(h / aspectRatio);
    01574
    01575         M[0] = w;
    01576         M[1] = 0;
    01577         M[2] = 0;
    01578         M[3] = 0;
    01579
    01580         M[4] = 0;
    01581         M[5] = (T)h;
    01582         M[6] = 0;
    01583         M[7] = 0;
    01584
    01585         M[8] = 0;
    01586         M[9] = 0;
    01587         M[10] = (T)(1.f-epsilon);
    01588         M[11] = 1;
    01589
    01590         M[12] = 0;
    01591         M[13] = 0;
    01592         M[14] = (T)(zNear*(epsilon-1.f));
    01593         M[15] = 0;
    01594
    01595 #if defined ( USE_MATRIX_TEST )
    01596         definitelyIdentityMatrix=false;
    01597 #endif
    01598         return *this;
    01599     }
    01600
    01601
    01602     // Builds a left-handed orthogonal projection matrix.
    01603     template <class T>
    01604     inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoLH(
    01605             f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
    01606     {
    01607         _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
    01608         _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
    01609         _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
    01610         M[0] = (T)(2/widthOfViewVolume);
    01611         M[1] = 0;
    01612         M[2] = 0;
    01613         M[3] = 0;
    01614
    01615         M[4] = 0;
    01616         M[5] = (T)(2/heightOfViewVolume);
    01617         M[6] = 0;
    01618         M[7] = 0;
    01619
    01620         M[8] = 0;
    01621         M[9] = 0;
    01622         M[10] = (T)(1/(zFar-zNear));
    01623         M[11] = 0;
    01624
    01625         M[12] = 0;
    01626         M[13] = 0;
    01627         M[14] = (T)(zNear/(zNear-zFar));
    01628         M[15] = 1;
    01629
    01630 #if defined ( USE_MATRIX_TEST )
    01631         definitelyIdentityMatrix=false;
    01632 #endif
    01633         return *this;
    01634     }
    01635
    01636
    01637     // Builds a right-handed orthogonal projection matrix.
    01638     template <class T>
    01639     inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoRH(
    01640             f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
    01641     {
    01642         _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
    01643         _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
    01644         _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
    01645         M[0] = (T)(2/widthOfViewVolume);
    01646         M[1] = 0;
    01647         M[2] = 0;
    01648         M[3] = 0;
    01649
    01650         M[4] = 0;
    01651         M[5] = (T)(2/heightOfViewVolume);
    01652         M[6] = 0;
    01653         M[7] = 0;
    01654
    01655         M[8] = 0;
    01656         M[9] = 0;
    01657         M[10] = (T)(1/(zNear-zFar));
    01658         M[11] = 0;
    01659
    01660         M[12] = 0;
    01661         M[13] = 0;
    01662         M[14] = (T)(zNear/(zNear-zFar));
    01663         M[15] = 1;
    01664
    01665 #if defined ( USE_MATRIX_TEST )
    01666         definitelyIdentityMatrix=false;
    01667 #endif
    01668         return *this;
    01669     }
    01670
    01671
    01672     // Builds a right-handed perspective projection matrix.
    01673     template <class T>
    01674     inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveRH(
    01675             f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
    01676     {
    01677         _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
    01678         _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
    01679         _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
    01680         M[0] = (T)(2*zNear/widthOfViewVolume);
    01681         M[1] = 0;
    01682         M[2] = 0;
    01683         M[3] = 0;
    01684
    01685         M[4] = 0;
    01686         M[5] = (T)(2*zNear/heightOfViewVolume);
    01687         M[6] = 0;
    01688         M[7] = 0;
    01689
    01690         M[8] = 0;
    01691         M[9] = 0;
    01692         M[10] = (T)(zFar/(zNear-zFar));
    01693         M[11] = -1;
    01694
    01695         M[12] = 0;
    01696         M[13] = 0;
    01697         M[14] = (T)(zNear*zFar/(zNear-zFar));
    01698         M[15] = 0;
    01699
    01700 #if defined ( USE_MATRIX_TEST )
    01701         definitelyIdentityMatrix=false;
    01702 #endif
    01703         return *this;
    01704     }
    01705
    01706
    01707     // Builds a left-handed perspective projection matrix.
    01708     template <class T>
    01709     inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveLH(
    01710             f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
    01711     {
    01712         _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
    01713         _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
    01714         _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
    01715         M[0] = (T)(2*zNear/widthOfViewVolume);
    01716         M[1] = 0;
    01717         M[2] = 0;
    01718         M[3] = 0;
    01719
    01720         M[4] = 0;
    01721         M[5] = (T)(2*zNear/heightOfViewVolume);
    01722         M[6] = 0;
    01723         M[7] = 0;
    01724
    01725         M[8] = 0;
    01726         M[9] = 0;
    01727         M[10] = (T)(zFar/(zFar-zNear));
    01728         M[11] = 1;
    01729
    01730         M[12] = 0;
    01731         M[13] = 0;
    01732         M[14] = (T)(zNear*zFar/(zNear-zFar));
    01733         M[15] = 0;
    01734 #if defined ( USE_MATRIX_TEST )
    01735         definitelyIdentityMatrix=false;
    01736 #endif
    01737         return *this;
    01738     }
    01739
    01740
    01741     // Builds a matrix that flattens geometry into a plane.
    01742     template <class T>
    01743     inline CMatrix4<T>& CMatrix4<T>::buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point)
    01744     {
    01745         plane.Normal.normalize();
    01746         const f32 d = plane.Normal.dotProduct(light);
    01747
    01748         M[ 0] = (T)(-plane.Normal.X * light.X + d);
    01749         M[ 1] = (T)(-plane.Normal.X * light.Y);
    01750         M[ 2] = (T)(-plane.Normal.X * light.Z);
    01751         M[ 3] = (T)(-plane.Normal.X * point);
    01752
    01753         M[ 4] = (T)(-plane.Normal.Y * light.X);
    01754         M[ 5] = (T)(-plane.Normal.Y * light.Y + d);
    01755         M[ 6] = (T)(-plane.Normal.Y * light.Z);
    01756         M[ 7] = (T)(-plane.Normal.Y * point);
    01757
    01758         M[ 8] = (T)(-plane.Normal.Z * light.X);
    01759         M[ 9] = (T)(-plane.Normal.Z * light.Y);
    01760         M[10] = (T)(-plane.Normal.Z * light.Z + d);
    01761         M[11] = (T)(-plane.Normal.Z * point);
    01762
    01763         M[12] = (T)(-plane.D * light.X);
    01764         M[13] = (T)(-plane.D * light.Y);
    01765         M[14] = (T)(-plane.D * light.Z);
    01766         M[15] = (T)(-plane.D * point + d);
    01767 #if defined ( USE_MATRIX_TEST )
    01768         definitelyIdentityMatrix=false;
    01769 #endif
    01770         return *this;
    01771     }
    01772
    01773     // Builds a left-handed look-at matrix.
    01774     template <class T>
    01775     inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixLH(
    01776                 const vector3df& position,
    01777                 const vector3df& target,
    01778                 const vector3df& upVector)
    01779     {
    01780         vector3df zaxis = target - position;
    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     // Builds a right-handed look-at matrix.
    01815     template <class T>
    01816     inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixRH(
    01817                 const vector3df& position,
    01818                 const vector3df& target,
    01819                 const vector3df& upVector)
    01820     {
    01821         vector3df zaxis = position - target;
    01822         zaxis.normalize();
    01823
    01824         vector3df xaxis = upVector.crossProduct(zaxis);
    01825         xaxis.normalize();
    01826
    01827         vector3df yaxis = zaxis.crossProduct(xaxis);
    01828
    01829         M[0] = (T)xaxis.X;
    01830         M[1] = (T)yaxis.X;
    01831         M[2] = (T)zaxis.X;
    01832         M[3] = 0;
    01833
    01834         M[4] = (T)xaxis.Y;
    01835         M[5] = (T)yaxis.Y;
    01836         M[6] = (T)zaxis.Y;
    01837         M[7] = 0;
    01838
    01839         M[8] = (T)xaxis.Z;
    01840         M[9] = (T)yaxis.Z;
    01841         M[10] = (T)zaxis.Z;
    01842         M[11] = 0;
    01843
    01844         M[12] = (T)-xaxis.dotProduct(position);
    01845         M[13] = (T)-yaxis.dotProduct(position);
    01846         M[14] = (T)-zaxis.dotProduct(position);
    01847         M[15] = 1;
    01848 #if defined ( USE_MATRIX_TEST )
    01849         definitelyIdentityMatrix=false;
    01850 #endif
    01851         return *this;
    01852     }
    01853
    01854
    01855     // creates a new matrix as interpolated matrix from this and the passed one.
    01856     template <class T>
    01857     inline CMatrix4<T> CMatrix4<T>::interpolate(const core::CMatrix4<T>& b, f32 time) const
    01858     {
    01859         CMatrix4<T> mat ( EM4CONST_NOTHING );
    01860
    01861         for (u32 i=0; i < 16; i += 4)
    01862         {
    01863             mat.M[i+0] = (T)(M[i+0] + ( b.M[i+0] - M[i+0] ) * time);
    01864             mat.M[i+1] = (T)(M[i+1] + ( b.M[i+1] - M[i+1] ) * time);
    01865             mat.M[i+2] = (T)(M[i+2] + ( b.M[i+2] - M[i+2] ) * time);
    01866             mat.M[i+3] = (T)(M[i+3] + ( b.M[i+3] - M[i+3] ) * time);
    01867         }
    01868         return mat;
    01869     }
    01870
    01871
    01872     // returns transposed matrix
    01873     template <class T>
    01874     inline CMatrix4<T> CMatrix4<T>::getTransposed() const
    01875     {
    01876         CMatrix4<T> t ( EM4CONST_NOTHING );
    01877         getTransposed ( t );
    01878         return t;
    01879     }
    01880
    01881
    01882     // returns transposed matrix
    01883     template <class T>
    01884     inline void CMatrix4<T>::getTransposed( CMatrix4<T>& o ) const
    01885     {
    01886         o[ 0] = M[ 0];
    01887         o[ 1] = M[ 4];
    01888         o[ 2] = M[ 8];
    01889         o[ 3] = M[12];
    01890
    01891         o[ 4] = M[ 1];
    01892         o[ 5] = M[ 5];
    01893         o[ 6] = M[ 9];
    01894         o[ 7] = M[13];
    01895
    01896         o[ 8] = M[ 2];
    01897         o[ 9] = M[ 6];
    01898         o[10] = M[10];
    01899         o[11] = M[14];
    01900
    01901         o[12] = M[ 3];
    01902         o[13] = M[ 7];
    01903         o[14] = M[11];
    01904         o[15] = M[15];
    01905 #if defined ( USE_MATRIX_TEST )
    01906         o.definitelyIdentityMatrix=definitelyIdentityMatrix;
    01907 #endif
    01908     }
    01909
    01910
    01911     // used to scale <-1,-1><1,1> to viewport
    01912     template <class T>
    01913     inline CMatrix4<T>& CMatrix4<T>::buildNDCToDCMatrix( const core::rect<s32>& viewport, f32 zScale)
    01914     {
    01915         const f32 scaleX = (viewport.getWidth() - 0.75f ) * 0.5f;
    01916         const f32 scaleY = -(viewport.getHeight() - 0.75f ) * 0.5f;
    01917
    01918         const f32 dx = -0.5f + ( (viewport.UpperLeftCorner.X + viewport.LowerRightCorner.X ) * 0.5f );
    01919         const f32 dy = -0.5f + ( (viewport.UpperLeftCorner.Y + viewport.LowerRightCorner.Y ) * 0.5f );
    01920
    01921         makeIdentity();
    01922         M[12] = (T)dx;
    01923         M[13] = (T)dy;
    01924         return setScale(core::vector3d<T>((T)scaleX, (T)scaleY, (T)zScale));
    01925     }
    01926
    01928
    01933     template <class T>
    01934     inline CMatrix4<T>& CMatrix4<T>::buildRotateFromTo(const core::vector3df& from, const core::vector3df& to)
    01935     {
    01936         // unit vectors
    01937         core::vector3df f(from);
    01938         core::vector3df t(to);
    01939         f.normalize();
    01940         t.normalize();
    01941
    01942         // axis multiplication by sin
    01943         core::vector3df vs(t.crossProduct(f));
    01944
    01945         // axis of rotation
    01946         core::vector3df v(vs);
    01947         v.normalize();
    01948
    01949         // cosinus angle
    01950         T ca = f.dotProduct(t);
    01951
    01952         core::vector3df vt(v * (1 - ca));
    01953
    01954         M[0] = vt.X * v.X + ca;
    01955         M[5] = vt.Y * v.Y + ca;
    01956         M[10] = vt.Z * v.Z + ca;
    01957
    01958         vt.X *= v.Y;
    01959         vt.Z *= v.X;
    01960         vt.Y *= v.Z;
    01961
    01962         M[1] = vt.X - vs.Z;
    01963         M[2] = vt.Z + vs.Y;
    01964         M[3] = 0;
    01965
    01966         M[4] = vt.X + vs.Z;
    01967         M[6] = vt.Y - vs.X;
    01968         M[7] = 0;
    01969
    01970         M[8] = vt.Z - vs.Y;
    01971         M[9] = vt.Y + vs.X;
    01972         M[11] = 0;
    01973
    01974         M[12] = 0;
    01975         M[13] = 0;
    01976         M[14] = 0;
    01977         M[15] = 1;
    01978
    01979         return *this;
    01980     }
    01981
    01983
    01989     template <class T>
    01990     inline void CMatrix4<T>::buildAxisAlignedBillboard(
    01991                 const core::vector3df& camPos,
    01992                 const core::vector3df& center,
    01993                 const core::vector3df& translation,
    01994                 const core::vector3df& axis,
    01995                 const core::vector3df& from)
    01996     {
    01997         // axis of rotation
    01998         core::vector3df up = axis;
    01999         up.normalize();
    02000         const core::vector3df forward = (camPos - center).normalize();
    02001         const core::vector3df right = up.crossProduct(forward).normalize();
    02002
    02003         // correct look vector
    02004         const core::vector3df look = right.crossProduct(up);
    02005
    02006         // rotate from to
    02007         // axis multiplication by sin
    02008         const core::vector3df vs = look.crossProduct(from);
    02009
    02010         // cosinus angle
    02011         const f32 ca = from.dotProduct(look);
    02012
    02013         core::vector3df vt(up * (1.f - ca));
    02014
    02015         M[0] = static_cast<T>(vt.X * up.X + ca);
    02016         M[5] = static_cast<T>(vt.Y * up.Y + ca);
    02017         M[10] = static_cast<T>(vt.Z * up.Z + ca);
    02018
    02019         vt.X *= up.Y;
    02020         vt.Z *= up.X;
    02021         vt.Y *= up.Z;
    02022
    02023         M[1] = static_cast<T>(vt.X - vs.Z);
    02024         M[2] = static_cast<T>(vt.Z + vs.Y);
    02025         M[3] = 0;
    02026
    02027         M[4] = static_cast<T>(vt.X + vs.Z);
    02028         M[6] = static_cast<T>(vt.Y - vs.X);
    02029         M[7] = 0;
    02030
    02031         M[8] = static_cast<T>(vt.Z - vs.Y);
    02032         M[9] = static_cast<T>(vt.Y + vs.X);
    02033         M[11] = 0;
    02034
    02035         setRotationCenter(center, translation);
    02036     }
    02037
    02038
    02040     template <class T>
    02041     inline void CMatrix4<T>::setRotationCenter(const core::vector3df& center, const core::vector3df& translation)
    02042     {
    02043         M[12] = -M[0]*center.X - M[4]*center.Y - M[8]*center.Z + (center.X - translation.X );
    02044         M[13] = -M[1]*center.X - M[5]*center.Y - M[9]*center.Z + (center.Y - translation.Y );
    02045         M[14] = -M[2]*center.X - M[6]*center.Y - M[10]*center.Z + (center.Z - translation.Z );
    02046         M[15] = (T) 1.0;
    02047 #if defined ( USE_MATRIX_TEST )
    02048         definitelyIdentityMatrix=false;
    02049 #endif
    02050     }
    02051
    02064     template <class T>
    02065     inline CMatrix4<T>& CMatrix4<T>::buildTextureTransform( f32 rotateRad,
    02066             const core::vector2df &rotatecenter,
    02067             const core::vector2df &translate,
    02068             const core::vector2df &scale)
    02069     {
    02070         const f32 c = cosf(rotateRad);
    02071         const f32 s = sinf(rotateRad);
    02072
    02073         M[0] = (T)(c * scale.X);
    02074         M[1] = (T)(s * scale.Y);
    02075         M[2] = 0;
    02076         M[3] = 0;
    02077
    02078         M[4] = (T)(-s * scale.X);
    02079         M[5] = (T)(c * scale.Y);
    02080         M[6] = 0;
    02081         M[7] = 0;
    02082
    02083         M[8] = (T)(c * scale.X * rotatecenter.X + -s * rotatecenter.Y + translate.X);
    02084         M[9] = (T)(s * scale.Y * rotatecenter.X +  c * rotatecenter.Y + translate.Y);
    02085         M[10] = 1;
    02086         M[11] = 0;
    02087
    02088         M[12] = 0;
    02089         M[13] = 0;
    02090         M[14] = 0;
    02091         M[15] = 1;
    02092 #if defined ( USE_MATRIX_TEST )
    02093         definitelyIdentityMatrix=false;
    02094 #endif
    02095         return *this;
    02096     }
    02097
    02098
    02099     // rotate about z axis, center ( 0.5, 0.5 )
    02100     template <class T>
    02101     inline CMatrix4<T>& CMatrix4<T>::setTextureRotationCenter( f32 rotateRad )
    02102     {
    02103         const f32 c = cosf(rotateRad);
    02104         const f32 s = sinf(rotateRad);
    02105         M[0] = (T)c;
    02106         M[1] = (T)s;
    02107
    02108         M[4] = (T)-s;
    02109         M[5] = (T)c;
    02110
    02111         M[8] = (T)(0.5f * ( s - c) + 0.5f);
    02112         M[9] = (T)(-0.5f * ( s + c) + 0.5f);
    02113
    02114 #if defined ( USE_MATRIX_TEST )
    02115         definitelyIdentityMatrix = definitelyIdentityMatrix && (rotateRad==0.0f);
    02116 #endif
    02117         return *this;
    02118     }
    02119
    02120
    02121     template <class T>
    02122     inline CMatrix4<T>& CMatrix4<T>::setTextureTranslate ( f32 x, f32 y )
    02123     {
    02124         M[8] = (T)x;
    02125         M[9] = (T)y;
    02126
    02127 #if defined ( USE_MATRIX_TEST )
    02128         definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f);
    02129 #endif
    02130         return *this;
    02131     }
    02132
    02133
    02134     template <class T>
    02135     inline CMatrix4<T>& CMatrix4<T>::setTextureTranslateTransposed ( f32 x, f32 y )
    02136     {
    02137         M[2] = (T)x;
    02138         M[6] = (T)y;
    02139
    02140 #if defined ( USE_MATRIX_TEST )
    02141         definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f) ;
    02142 #endif
    02143         return *this;
    02144     }
    02145
    02146     template <class T>
    02147     inline CMatrix4<T>& CMatrix4<T>::setTextureScale ( f32 sx, f32 sy )
    02148     {
    02149         M[0] = (T)sx;
    02150         M[5] = (T)sy;
    02151 #if defined ( USE_MATRIX_TEST )
    02152         definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
    02153 #endif
    02154         return *this;
    02155     }
    02156
    02157
    02158     template <class T>
    02159     inline CMatrix4<T>& CMatrix4<T>::setTextureScaleCenter( f32 sx, f32 sy )
    02160     {
    02161         M[0] = (T)sx;
    02162         M[5] = (T)sy;
    02163         M[8] = (T)(0.5f - 0.5f * sx);
    02164         M[9] = (T)(0.5f - 0.5f * sy);
    02165
    02166 #if defined ( USE_MATRIX_TEST )
    02167         definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
    02168 #endif
    02169         return *this;
    02170     }
    02171
    02172
    02173     // sets all matrix data members at once
    02174     template <class T>
    02175     inline CMatrix4<T>& CMatrix4<T>::setM(const T* data)
    02176     {
    02177         memcpy(M,data, 16*sizeof(T));
    02178
    02179 #if defined ( USE_MATRIX_TEST )
    02180         definitelyIdentityMatrix=false;
    02181 #endif
    02182         return *this;
    02183     }
    02184
    02185
    02186     // sets if the matrix is definitely identity matrix
    02187     template <class T>
    02188     inline void CMatrix4<T>::setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix)
    02189     {
    02190 #if defined ( USE_MATRIX_TEST )
    02191         definitelyIdentityMatrix = isDefinitelyIdentityMatrix;
    02192 #endif
    02193     }
    02194
    02195
    02196     // gets if the matrix is definitely identity matrix
    02197     template <class T>
    02198     inline bool CMatrix4<T>::getDefinitelyIdentityMatrix() const
    02199     {
    02200 #if defined ( USE_MATRIX_TEST )
    02201         return definitelyIdentityMatrix;
    02202 #else
    02203         return false;
    02204 #endif
    02205     }
    02206
    02207
    02209     template <class T>
    02210     inline bool CMatrix4<T>::equals(const core::CMatrix4<T>& other, const T tolerance) const
    02211     {
    02212 #if defined ( USE_MATRIX_TEST )
    02213         if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
    02214             return true;
    02215 #endif
    02216         for (s32 i = 0; i < 16; ++i)
    02217             if (!core::equals(M[i],other.M[i], tolerance))
    02218                 return false;
    02219
    02220         return true;
    02221     }
    02222
    02223
    02224     // Multiply by scalar.
    02225     template <class T>
    02226     inline CMatrix4<T> operator*(const T scalar, const CMatrix4<T>& mat)
    02227     {
    02228         return mat*scalar;
    02229     }
    02230
    02231
    02233     typedef CMatrix4<f32> matrix4;
    02234
    02236     IRRLICHT_API extern const matrix4 IdentityMatrix;
    02237
    02238 } // end namespace core
    02239 } // end namespace irr
    02240
    02241 #endif
    02242