~baltix/+junk/irrlicht-test

« back to all changes in this revision

Viewing changes to include/matrix4.h

  • Committer: Mantas Kriaučiūnas
  • Date: 2011-07-18 13:06:25 UTC
  • Revision ID: mantas@akl.lt-20110718130625-c5pvifp61e7kj1ol
Included whole irrlicht SVN libraries to work around launchpad recipe issue with quilt, see https://answers.launchpad.net/launchpad/+question/165193

Show diffs side-by-side

added added

removed removed

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