| 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