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
5
#ifndef __IRR_MATRIX_H_INCLUDED__
6
#define __IRR_MATRIX_H_INCLUDED__
14
#include "irrString.h"
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
21
// this is only for debugging purposes
22
//#define USE_MATRIX_TEST_DEBUG
24
#if defined( USE_MATRIX_TEST_DEBUG )
28
MatrixTest () : ID(0), Calls(0) {}
33
static MatrixTest MTest;
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. */
57
EM4CONST_INVERSE_TRANSPOSED
60
//! Default constructor
61
/** \param constructor Choose the initialization style */
62
CMatrix4( eConstructor constructor = EM4CONST_IDENTITY );
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);
68
//! Simple operator for directly accessing every element of the matrix.
69
T& operator()(const s32 row, const s32 col)
71
#if defined ( USE_MATRIX_TEST )
72
definitelyIdentityMatrix=false;
74
return M[ row * 4 + col ];
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]; }
80
//! Simple operator for linearly accessing every element of the matrix.
81
T& operator[](u32 index)
83
#if defined ( USE_MATRIX_TEST )
84
definitelyIdentityMatrix=false;
89
//! Simple operator for linearly accessing every element of the matrix.
90
const T& operator[](u32 index) const { return M[index]; }
92
//! Sets this matrix equal to the other matrix.
93
inline CMatrix4<T>& operator=(const CMatrix4<T> &other);
95
//! Sets all elements of this matrix to the value.
96
inline CMatrix4<T>& operator=(const T& scalar);
98
//! Returns pointer to internal array
99
const T* pointer() const { return M; }
102
#if defined ( USE_MATRIX_TEST )
103
definitelyIdentityMatrix=false;
108
//! Returns true if other matrix is equal to this matrix.
109
bool operator==(const CMatrix4<T> &other) const;
111
//! Returns true if other matrix is not equal to this matrix.
112
bool operator!=(const CMatrix4<T> &other) const;
114
//! Add another matrix.
115
CMatrix4<T> operator+(const CMatrix4<T>& other) const;
117
//! Add another matrix.
118
CMatrix4<T>& operator+=(const CMatrix4<T>& other);
120
//! Subtract another matrix.
121
CMatrix4<T> operator-(const CMatrix4<T>& other) const;
123
//! Subtract another matrix.
124
CMatrix4<T>& operator-=(const CMatrix4<T>& other);
126
//! set this matrix to the product of two matrices
128
inline CMatrix4<T>& setbyproduct(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b );
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 );
135
//! Multiply by another matrix.
136
/** Calculate other*this */
137
CMatrix4<T> operator*(const CMatrix4<T>& other) const;
139
//! Multiply by another matrix.
140
/** Calculate and return other*this */
141
CMatrix4<T>& operator*=(const CMatrix4<T>& other);
143
//! Multiply by scalar.
144
CMatrix4<T> operator*(const T& scalar) const;
146
//! Multiply by scalar.
147
CMatrix4<T>& operator*=(const T& scalar);
149
//! Set matrix to identity.
150
inline CMatrix4<T>& makeIdentity();
152
//! Returns true if the matrix is the identity matrix
153
inline bool isIdentity() const;
155
//! Returns true if the matrix is orthogonal
156
inline bool isOrthogonal() const;
158
//! Returns true if the matrix is the identity matrix
159
bool isIdentity_integer_base () const;
161
//! Set the translation of the current matrix. Will erase any previous values.
162
CMatrix4<T>& setTranslation( const vector3d<T>& translation );
164
//! Gets the current translation
165
vector3d<T> getTranslation() const;
167
//! Set the inverse translation of the current matrix. Will erase any previous values.
168
CMatrix4<T>& setInverseTranslation( const vector3d<T>& translation );
170
//! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
171
inline CMatrix4<T>& setRotationRadians( const vector3d<T>& rotation );
173
//! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
174
CMatrix4<T>& setRotationDegrees( const vector3d<T>& rotation );
176
//! Returns the rotation, as set by setRotation().
177
/** This code was orginally written by by Chev. */
178
core::vector3d<T> getRotationDegrees() const;
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 );
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 );
189
CMatrix4<T>& setScale( const vector3d<T>& scale );
192
CMatrix4<T>& setScale( const T scale ) { return setScale(core::vector3d<T>(scale,scale,scale)); }
195
core::vector3d<T> getScale() const;
197
//! Translate a vector by the inverse of the translation part of this matrix.
198
void inverseTranslateVect( vector3df& vect ) const;
200
//! Rotate a vector by the inverse of the rotation part of this matrix.
201
void inverseRotateVect( vector3df& vect ) const;
203
//! Rotate a vector by the rotation part of this matrix.
204
void rotateVect( vector3df& vect ) const;
206
//! An alternate transform vector method, writing into a second vector
207
void rotateVect(core::vector3df& out, const core::vector3df& in) const;
209
//! An alternate transform vector method, writing into an array of 3 floats
210
void rotateVect(T *out,const core::vector3df &in) const;
212
//! Transforms the vector by this matrix
213
void transformVect( vector3df& vect) const;
215
//! Transforms input vector by this matrix and stores result in output vector
216
void transformVect( vector3df& out, const vector3df& in ) const;
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;
222
//! Translate a vector by the translation part of this matrix.
223
void translateVect( vector3df& vect ) const;
225
//! Transforms a plane by this matrix
226
void transformPlane( core::plane3d<f32> &plane) const;
228
//! Transforms a plane by this matrix
229
void transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const;
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;
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;
241
//! Multiplies this matrix by a 1x4 matrix
242
void multiplyWith1x4Matrix(T* matrix) const;
244
//! Calculates inverse of matrix. Slow.
245
/** \return Returns false if there is no inverse matrix.*/
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;
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;
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);
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);
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);
267
//! Builds a right-handed perspective projection matrix.
268
CMatrix4<T>& buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar);
270
//! Builds a left-handed perspective projection matrix.
271
CMatrix4<T>& buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar);
273
//! Builds a left-handed orthogonal projection matrix.
274
CMatrix4<T>& buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar);
276
//! Builds a right-handed orthogonal projection matrix.
277
CMatrix4<T>& buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar);
279
//! Builds a left-handed look-at matrix.
280
CMatrix4<T>& buildCameraLookAtMatrixLH(
281
const vector3df& position,
282
const vector3df& target,
283
const vector3df& upVector);
285
//! Builds a right-handed look-at matrix.
286
CMatrix4<T>& buildCameraLookAtMatrixRH(
287
const vector3df& position,
288
const vector3df& target,
289
const vector3df& upVector);
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);
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);
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;
307
//! Gets transposed matrix
308
CMatrix4<T> getTransposed() const;
310
//! Gets transposed matrix
311
inline void getTransposed( CMatrix4<T>& dest ) const;
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
317
CMatrix4<T>& buildRotateFromTo(const core::vector3df& from, const core::vector3df& to);
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
323
void setRotationCenter(const core::vector3df& center, const core::vector3df& translate);
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
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);
339
construct 2D Texture transformations
340
rotate about center, scale, and transform.
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);
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 );
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 );
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 );
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 );
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 );
383
//! Sets all matrix data members at once
384
CMatrix4<T>& setM(const T* data);
386
//! Sets if the matrix is definitely identity matrix
387
void setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix);
389
//! Gets if the matrix is definitely identity matrix
390
bool getDefinitelyIdentityMatrix() const;
392
//! Compare two matrices using the equal method
393
bool equals(const core::CMatrix4<T>& other, const T tolerance=(T)ROUNDING_ERROR_f64) const;
396
//! Matrix data, stored in row-major order
398
#if defined ( USE_MATRIX_TEST )
399
//! Flag is this matrix is identity matrix
400
mutable u32 definitelyIdentityMatrix;
402
#if defined ( USE_MATRIX_TEST_DEBUG )
409
// Default constructor
411
inline CMatrix4<T>::CMatrix4( eConstructor constructor )
412
#if defined ( USE_MATRIX_TEST )
413
: definitelyIdentityMatrix(BIT_UNTESTED)
415
#if defined ( USE_MATRIX_TEST_DEBUG )
416
,id ( MTest.ID++), calls ( 0 )
419
switch ( constructor )
421
case EM4CONST_NOTHING:
424
case EM4CONST_IDENTITY:
425
case EM4CONST_INVERSE:
434
inline CMatrix4<T>::CMatrix4( const CMatrix4<T>& other, eConstructor constructor)
435
#if defined ( USE_MATRIX_TEST )
436
: definitelyIdentityMatrix(BIT_UNTESTED)
438
#if defined ( USE_MATRIX_TEST_DEBUG )
439
,id ( MTest.ID++), calls ( 0 )
442
switch ( constructor )
444
case EM4CONST_IDENTITY:
447
case EM4CONST_NOTHING:
452
case EM4CONST_TRANSPOSED:
453
other.getTransposed(*this);
455
case EM4CONST_INVERSE:
456
if (!other.getInverse(*this))
457
memset(M, 0, 16*sizeof(T));
459
case EM4CONST_INVERSE_TRANSPOSED:
460
if (!other.getInverse(*this))
461
memset(M, 0, 16*sizeof(T));
463
*this=getTransposed();
468
//! Add another matrix.
470
inline CMatrix4<T> CMatrix4<T>::operator+(const CMatrix4<T>& other) const
472
CMatrix4<T> temp ( EM4CONST_NOTHING );
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];
494
//! Add another matrix.
496
inline CMatrix4<T>& CMatrix4<T>::operator+=(const CMatrix4<T>& other)
518
//! Subtract another matrix.
520
inline CMatrix4<T> CMatrix4<T>::operator-(const CMatrix4<T>& other) const
522
CMatrix4<T> temp ( EM4CONST_NOTHING );
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];
544
//! Subtract another matrix.
546
inline CMatrix4<T>& CMatrix4<T>::operator-=(const CMatrix4<T>& other)
568
//! Multiply by scalar.
570
inline CMatrix4<T> CMatrix4<T>::operator*(const T& scalar) const
572
CMatrix4<T> temp ( EM4CONST_NOTHING );
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;
594
//! Multiply by scalar.
596
inline CMatrix4<T>& CMatrix4<T>::operator*=(const T& scalar)
618
//! Multiply by another matrix.
620
inline CMatrix4<T>& CMatrix4<T>::operator*=(const CMatrix4<T>& other)
622
#if defined ( USE_MATRIX_TEST )
623
// do checks on your own in order to avoid copy creation
624
if ( !other.isIdentity() )
626
if ( this->isIdentity() )
628
return (*this = other);
632
CMatrix4<T> temp ( *this );
633
return setbyproduct_nocheck( temp, other );
638
CMatrix4<T> temp ( *this );
639
return setbyproduct_nocheck( temp, other );
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
647
inline CMatrix4<T>& CMatrix4<T>::setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b )
649
const T *m1 = other_a.M;
650
const T *m2 = other_b.M;
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];
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];
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];
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;
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
682
inline CMatrix4<T>& CMatrix4<T>::setbyproduct(const CMatrix4<T>& other_a, const CMatrix4<T>& other_b )
684
#if defined ( USE_MATRIX_TEST )
685
if ( other_a.isIdentity () )
686
return (*this = other_b);
688
if ( other_b.isIdentity () )
689
return (*this = other_a);
691
return setbyproduct_nocheck(other_a,other_b);
693
return setbyproduct_nocheck(other_a,other_b);
697
//! multiply by another matrix
699
inline CMatrix4<T> CMatrix4<T>::operator*(const CMatrix4<T>& m2) const
701
#if defined ( USE_MATRIX_TEST )
703
if ( this->isIdentity() )
705
if ( m2.isIdentity() )
709
CMatrix4<T> m3 ( EM4CONST_NOTHING );
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];
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];
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];
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];
738
inline vector3d<T> CMatrix4<T>::getTranslation() const
740
return vector3d<T>(M[12], M[13], M[14]);
745
inline CMatrix4<T>& CMatrix4<T>::setTranslation( const vector3d<T>& translation )
747
M[12] = translation.X;
748
M[13] = translation.Y;
749
M[14] = translation.Z;
750
#if defined ( USE_MATRIX_TEST )
751
definitelyIdentityMatrix=false;
757
inline CMatrix4<T>& CMatrix4<T>::setInverseTranslation( const vector3d<T>& translation )
759
M[12] = -translation.X;
760
M[13] = -translation.Y;
761
M[14] = -translation.Z;
762
#if defined ( USE_MATRIX_TEST )
763
definitelyIdentityMatrix=false;
769
inline CMatrix4<T>& CMatrix4<T>::setScale( const vector3d<T>& scale )
774
#if defined ( USE_MATRIX_TEST )
775
definitelyIdentityMatrix=false;
780
//! Returns the absolute values of the scales of the matrix.
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.
789
inline vector3d<T> CMatrix4<T>::getScale() const
791
// See http://www.robertblum.com/articles/2005/02/14/decomposing-matrices
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]);
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]));
807
inline CMatrix4<T>& CMatrix4<T>::setRotationDegrees( const vector3d<T>& rotation )
809
return setRotationRadians( rotation * core::DEGTORAD );
813
inline CMatrix4<T>& CMatrix4<T>::setInverseRotationDegrees( const vector3d<T>& rotation )
815
return setInverseRotationRadians( rotation * core::DEGTORAD );
819
inline CMatrix4<T>& CMatrix4<T>::setRotationRadians( const vector3d<T>& rotation )
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 );
832
const f64 srsp = sr*sp;
833
const f64 crsp = cr*sp;
835
M[4] = (T)( srsp*cy-cr*sy );
836
M[5] = (T)( srsp*sy+cr*cy );
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;
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. */
854
inline core::vector3d<T> CMatrix4<T>::getRotationDegrees() const
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)
864
else if (scale.X<0 && scale.Z<0)
869
else if (scale.X<0 && scale.Y<0)
874
const core::vector3d<f64> invScale(core::reciprocal(scale.X),core::reciprocal(scale.Y),core::reciprocal(scale.Z));
876
f64 Y = -asin(core::clamp(mat[2]*invScale.X, -1.0, 1.0));
877
const f64 C = cos(Y);
880
f64 rotx, roty, X, Z;
882
if (!core::iszero(C))
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;
895
rotx = mat[5] * invScale.Y;
896
roty = -mat[4] * invScale.Y;
897
Z = atan2( roty, rotx ) * RADTODEG64;
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;
905
return vector3d<T>((T)X,(T)Y,(T)Z);
910
inline CMatrix4<T>& CMatrix4<T>::setInverseRotationRadians( const vector3d<T>& rotation )
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 );
926
M[1] = (T)( srsp*cy-cr*sy );
927
M[5] = (T)( srsp*sy+cr*cy );
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;
943
inline CMatrix4<T>& CMatrix4<T>::makeIdentity()
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;
955
check identity with epsilon
956
solve floating range problems..
959
inline bool CMatrix4<T>::isIdentity() const
961
#if defined ( USE_MATRIX_TEST )
962
if (definitelyIdentityMatrix)
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 ))
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 ))
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 ))
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 ))
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 ))
983
for (s32 i=0; i<4; ++i)
984
for (s32 j=0; j<4; ++j)
985
if ((j != i) && (!iszero((*this)(i,j))))
988
#if defined ( USE_MATRIX_TEST )
989
definitelyIdentityMatrix=true;
995
/* Check orthogonality of matrix. */
997
inline bool CMatrix4<T>::isOrthogonal() const
999
T dp=M[0] * M[4 ] + M[1] * M[5 ] + M[2 ] * M[6 ] + M[3 ] * M[7 ];
1002
dp = M[0] * M[8 ] + M[1] * M[9 ] + M[2 ] * M[10] + M[3 ] * M[11];
1005
dp = M[0] * M[12] + M[1] * M[13] + M[2 ] * M[14] + M[3 ] * M[15];
1008
dp = M[4] * M[8 ] + M[5] * M[9 ] + M[6 ] * M[10] + M[7 ] * M[11];
1011
dp = M[4] * M[12] + M[5] * M[13] + M[6 ] * M[14] + M[7 ] * M[15];
1014
dp = M[8] * M[12] + M[9] * M[13] + M[10] * M[14] + M[11] * M[15];
1015
return (iszero(dp));
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..
1026
inline bool CMatrix4<T>::isIdentity_integer_base() const
1028
#if defined ( USE_MATRIX_TEST )
1029
if (definitelyIdentityMatrix)
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;
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;
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;
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;
1052
#if defined ( USE_MATRIX_TEST )
1053
definitelyIdentityMatrix=true;
1060
inline void CMatrix4<T>::rotateVect( vector3df& vect ) const
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];
1068
//! An alternate transform vector method, writing into a second vector
1070
inline void CMatrix4<T>::rotateVect(core::vector3df& out, const core::vector3df& in) const
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];
1077
//! An alternate transform vector method, writing into an array of 3 floats
1079
inline void CMatrix4<T>::rotateVect(T *out, const core::vector3df& in) const
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];
1087
inline void CMatrix4<T>::inverseRotateVect( vector3df& vect ) const
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];
1096
inline void CMatrix4<T>::transformVect( vector3df& vect) const
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];
1110
inline void CMatrix4<T>::transformVect( vector3df& out, const vector3df& in) const
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];
1119
inline void CMatrix4<T>::transformVect(T *out, const core::vector3df &in) const
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];
1128
inline void CMatrix4<T>::transformVec3(T *out, const T * in) const
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];
1136
//! Transforms a plane by this matrix
1138
inline void CMatrix4<T>::transformPlane( core::plane3d<f32> &plane) const
1141
// Transform the plane member point, i.e. rotate, translate and scale it.
1142
transformVect(member, plane.getMemberPoint());
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);
1149
plane.setPlane(member, normal);
1152
//! Transforms a plane by this matrix
1154
inline void CMatrix4<T>::transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const
1157
transformPlane( out );
1160
//! Transforms a axis aligned bounding box
1162
inline void CMatrix4<T>::transformBox(core::aabbox3d<f32>& box) const
1164
#if defined ( USE_MATRIX_TEST )
1169
transformVect(box.MinEdge);
1170
transformVect(box.MaxEdge);
1174
//! Transforms a axis aligned bounding box more accurately than transformBox()
1176
inline void CMatrix4<T>::transformBoxEx(core::aabbox3d<f32>& box) const
1178
#if defined ( USE_MATRIX_TEST )
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};
1189
Bmin[0] = Bmax[0] = M[12];
1190
Bmin[1] = Bmax[1] = M[13];
1191
Bmin[2] = Bmax[2] = M[14];
1193
const CMatrix4<T> &m = *this;
1195
for (u32 i = 0; i < 3; ++i)
1197
for (u32 j = 0; j < 3; ++j)
1199
const f32 a = m(j,i) * Amin[j];
1200
const f32 b = m(j,i) * Amax[j];
1215
box.MinEdge.X = Bmin[0];
1216
box.MinEdge.Y = Bmin[1];
1217
box.MinEdge.Z = Bmin[2];
1219
box.MaxEdge.X = Bmax[0];
1220
box.MaxEdge.Y = Bmax[1];
1221
box.MaxEdge.Z = Bmax[2];
1225
//! Multiplies this matrix by a 1x4 matrix
1227
inline void CMatrix4<T>::multiplyWith1x4Matrix(T* matrix) const
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];
1249
inline void CMatrix4<T>::inverseTranslateVect( vector3df& vect ) const
1251
vect.X = vect.X-M[12];
1252
vect.Y = vect.Y-M[13];
1253
vect.Z = vect.Z-M[14];
1257
inline void CMatrix4<T>::translateVect( vector3df& vect ) const
1259
vect.X = vect.X+M[12];
1260
vect.Y = vect.Y+M[13];
1261
vect.Z = vect.Z+M[14];
1266
inline bool CMatrix4<T>::getInverse(CMatrix4<T>& out) const
1268
/// Calculates the inverse of this Matrix
1269
/// The inverse is calculated using Cramers rule.
1270
/// If no inverse exists then 'false' is returned.
1272
#if defined ( USE_MATRIX_TEST )
1273
if ( this->isIdentity() )
1279
const CMatrix4<T> &m = *this;
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));
1288
if( core::iszero ( d ) )
1291
d = core::reciprocal ( d );
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)));
1342
#if defined ( USE_MATRIX_TEST )
1343
out.definitelyIdentityMatrix = definitelyIdentityMatrix;
1349
//! Inverts a primitive matrix which only contains a translation and a rotation
1350
//! \param out: where result matrix is written to.
1352
inline bool CMatrix4<T>::getInversePrimitive ( CMatrix4<T>& out ) const
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]);
1374
#if defined ( USE_MATRIX_TEST )
1375
out.definitelyIdentityMatrix = definitelyIdentityMatrix;
1383
inline bool CMatrix4<T>::makeInverse()
1385
#if defined ( USE_MATRIX_TEST )
1386
if (definitelyIdentityMatrix)
1389
CMatrix4<T> temp ( EM4CONST_NOTHING );
1391
if (getInverse(temp))
1402
inline CMatrix4<T>& CMatrix4<T>::operator=(const CMatrix4<T> &other)
1406
memcpy(M, other.M, 16*sizeof(T));
1407
#if defined ( USE_MATRIX_TEST )
1408
definitelyIdentityMatrix=other.definitelyIdentityMatrix;
1415
inline CMatrix4<T>& CMatrix4<T>::operator=(const T& scalar)
1417
for (s32 i = 0; i < 16; ++i)
1420
#if defined ( USE_MATRIX_TEST )
1421
definitelyIdentityMatrix=false;
1428
inline bool CMatrix4<T>::operator==(const CMatrix4<T> &other) const
1430
#if defined ( USE_MATRIX_TEST )
1431
if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
1434
for (s32 i = 0; i < 16; ++i)
1435
if (M[i] != other.M[i])
1443
inline bool CMatrix4<T>::operator!=(const CMatrix4<T> &other) const
1445
return !(*this == other);
1449
// Builds a right-handed perspective projection matrix based on a field of view
1451
inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovRH(
1452
f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar)
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);
1458
_IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
1471
M[10] = (T)(zFar/(zNear-zFar)); // DirectX version
1472
// M[10] = (T)(zFar+zNear/(zNear-zFar)); // OpenGL version
1477
M[14] = (T)(zNear*zFar/(zNear-zFar)); // DirectX version
1478
// M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar)); // OpenGL version
1481
#if defined ( USE_MATRIX_TEST )
1482
definitelyIdentityMatrix=false;
1488
// Builds a left-handed perspective projection matrix based on a field of view
1490
inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovLH(
1491
f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar)
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);
1497
_IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
1510
M[10] = (T)(zFar/(zFar-zNear));
1515
M[14] = (T)(-zNear*zFar/(zFar-zNear));
1518
#if defined ( USE_MATRIX_TEST )
1519
definitelyIdentityMatrix=false;
1525
// Builds a left-handed perspective projection matrix based on a field of view, with far plane culling at infinity
1527
inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovInfinityLH(
1528
f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon)
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);
1546
M[10] = (T)(1.f-epsilon);
1551
M[14] = (T)(zNear*(epsilon-1.f));
1554
#if defined ( USE_MATRIX_TEST )
1555
definitelyIdentityMatrix=false;
1561
// Builds a left-handed orthogonal projection matrix.
1563
inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoLH(
1564
f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
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);
1575
M[5] = (T)(2/heightOfViewVolume);
1581
M[10] = (T)(1/(zFar-zNear));
1586
M[14] = (T)(zNear/(zNear-zFar));
1589
#if defined ( USE_MATRIX_TEST )
1590
definitelyIdentityMatrix=false;
1596
// Builds a right-handed orthogonal projection matrix.
1598
inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoRH(
1599
f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
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);
1610
M[5] = (T)(2/heightOfViewVolume);
1616
M[10] = (T)(1/(zNear-zFar));
1621
M[14] = (T)(zNear/(zNear-zFar));
1624
#if defined ( USE_MATRIX_TEST )
1625
definitelyIdentityMatrix=false;
1631
// Builds a right-handed perspective projection matrix.
1633
inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveRH(
1634
f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
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);
1645
M[5] = (T)(2*zNear/heightOfViewVolume);
1651
M[10] = (T)(zFar/(zNear-zFar));
1656
M[14] = (T)(zNear*zFar/(zNear-zFar));
1659
#if defined ( USE_MATRIX_TEST )
1660
definitelyIdentityMatrix=false;
1666
// Builds a left-handed perspective projection matrix.
1668
inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveLH(
1669
f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
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);
1680
M[5] = (T)(2*zNear/heightOfViewVolume);
1686
M[10] = (T)(zFar/(zFar-zNear));
1691
M[14] = (T)(zNear*zFar/(zNear-zFar));
1693
#if defined ( USE_MATRIX_TEST )
1694
definitelyIdentityMatrix=false;
1700
// Builds a matrix that flattens geometry into a plane.
1702
inline CMatrix4<T>& CMatrix4<T>::buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point)
1704
plane.Normal.normalize();
1705
const f32 d = plane.Normal.dotProduct(light);
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);
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);
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);
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;
1732
// Builds a left-handed look-at matrix.
1734
inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixLH(
1735
const vector3df& position,
1736
const vector3df& target,
1737
const vector3df& upVector)
1739
vector3df zaxis = target - position;
1742
vector3df xaxis = upVector.crossProduct(zaxis);
1745
vector3df yaxis = zaxis.crossProduct(xaxis);
1762
M[12] = (T)-xaxis.dotProduct(position);
1763
M[13] = (T)-yaxis.dotProduct(position);
1764
M[14] = (T)-zaxis.dotProduct(position);
1766
#if defined ( USE_MATRIX_TEST )
1767
definitelyIdentityMatrix=false;
1773
// Builds a right-handed look-at matrix.
1775
inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixRH(
1776
const vector3df& position,
1777
const vector3df& target,
1778
const vector3df& upVector)
1780
vector3df zaxis = position - target;
1783
vector3df xaxis = upVector.crossProduct(zaxis);
1786
vector3df yaxis = zaxis.crossProduct(xaxis);
1803
M[12] = (T)-xaxis.dotProduct(position);
1804
M[13] = (T)-yaxis.dotProduct(position);
1805
M[14] = (T)-zaxis.dotProduct(position);
1807
#if defined ( USE_MATRIX_TEST )
1808
definitelyIdentityMatrix=false;
1814
// creates a new matrix as interpolated matrix from this and the passed one.
1816
inline CMatrix4<T> CMatrix4<T>::interpolate(const core::CMatrix4<T>& b, f32 time) const
1818
CMatrix4<T> mat ( EM4CONST_NOTHING );
1820
for (u32 i=0; i < 16; i += 4)
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);
1831
// returns transposed matrix
1833
inline CMatrix4<T> CMatrix4<T>::getTransposed() const
1835
CMatrix4<T> t ( EM4CONST_NOTHING );
1836
getTransposed ( t );
1841
// returns transposed matrix
1843
inline void CMatrix4<T>::getTransposed( CMatrix4<T>& o ) const
1864
#if defined ( USE_MATRIX_TEST )
1865
o.definitelyIdentityMatrix=definitelyIdentityMatrix;
1870
// used to scale <-1,-1><1,1> to viewport
1872
inline CMatrix4<T>& CMatrix4<T>::buildNDCToDCMatrix( const core::rect<s32>& viewport, f32 zScale)
1874
const f32 scaleX = (viewport.getWidth() - 0.75f ) * 0.5f;
1875
const f32 scaleY = -(viewport.getHeight() - 0.75f ) * 0.5f;
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 );
1883
return setScale(core::vector3d<T>((T)scaleX, (T)scaleY, (T)zScale));
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
1890
http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/index.htm
1893
inline CMatrix4<T>& CMatrix4<T>::buildRotateFromTo(const core::vector3df& from, const core::vector3df& to)
1896
core::vector3df f(from);
1897
core::vector3df t(to);
1901
// axis multiplication by sin
1902
core::vector3df vs(t.crossProduct(f));
1905
core::vector3df v(vs);
1909
T ca = f.dotProduct(t);
1911
core::vector3df vt(v * (1 - ca));
1913
M[0] = vt.X * v.X + ca;
1914
M[5] = vt.Y * v.Y + ca;
1915
M[10] = vt.Z * v.Z + ca;
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
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)
1957
core::vector3df up = axis;
1959
const core::vector3df forward = (camPos - center).normalize();
1960
const core::vector3df right = up.crossProduct(forward).normalize();
1962
// correct look vector
1963
const core::vector3df look = right.crossProduct(up);
1966
// axis multiplication by sin
1967
const core::vector3df vs = look.crossProduct(from);
1970
const f32 ca = from.dotProduct(look);
1972
core::vector3df vt(up * (1.f - ca));
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);
1982
M[1] = static_cast<T>(vt.X - vs.Z);
1983
M[2] = static_cast<T>(vt.Z + vs.Y);
1986
M[4] = static_cast<T>(vt.X + vs.Z);
1987
M[6] = static_cast<T>(vt.Y - vs.X);
1990
M[8] = static_cast<T>(vt.Z - vs.Y);
1991
M[9] = static_cast<T>(vt.Y + vs.X);
1994
setRotationCenter(center, translation);
1998
//! Builds a combined matrix which translate to a center before rotation and translate afterwards
2000
inline void CMatrix4<T>::setRotationCenter(const core::vector3df& center, const core::vector3df& translation)
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 );
2006
#if defined ( USE_MATRIX_TEST )
2007
definitelyIdentityMatrix=false;
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:
2024
inline CMatrix4<T>& CMatrix4<T>::buildTextureTransform( f32 rotateRad,
2025
const core::vector2df &rotatecenter,
2026
const core::vector2df &translate,
2027
const core::vector2df &scale)
2029
const f32 c = cosf(rotateRad);
2030
const f32 s = sinf(rotateRad);
2032
M[0] = (T)(c * scale.X);
2033
M[1] = (T)(s * scale.Y);
2037
M[4] = (T)(-s * scale.X);
2038
M[5] = (T)(c * scale.Y);
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);
2051
#if defined ( USE_MATRIX_TEST )
2052
definitelyIdentityMatrix=false;
2058
// rotate about z axis, center ( 0.5, 0.5 )
2060
inline CMatrix4<T>& CMatrix4<T>::setTextureRotationCenter( f32 rotateRad )
2062
const f32 c = cosf(rotateRad);
2063
const f32 s = sinf(rotateRad);
2070
M[8] = (T)(0.5f * ( s - c) + 0.5f);
2071
M[9] = (T)(-0.5f * ( s + c) + 0.5f);
2073
#if defined ( USE_MATRIX_TEST )
2074
definitelyIdentityMatrix = definitelyIdentityMatrix && (rotateRad==0.0f);
2081
inline CMatrix4<T>& CMatrix4<T>::setTextureTranslate ( f32 x, f32 y )
2086
#if defined ( USE_MATRIX_TEST )
2087
definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f);
2094
inline CMatrix4<T>& CMatrix4<T>::setTextureTranslateTransposed ( f32 x, f32 y )
2099
#if defined ( USE_MATRIX_TEST )
2100
definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f) ;
2106
inline CMatrix4<T>& CMatrix4<T>::setTextureScale ( f32 sx, f32 sy )
2110
#if defined ( USE_MATRIX_TEST )
2111
definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
2118
inline CMatrix4<T>& CMatrix4<T>::setTextureScaleCenter( f32 sx, f32 sy )
2122
M[8] = (T)(0.5f - 0.5f * sx);
2123
M[9] = (T)(0.5f - 0.5f * sy);
2125
#if defined ( USE_MATRIX_TEST )
2126
definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
2132
// sets all matrix data members at once
2134
inline CMatrix4<T>& CMatrix4<T>::setM(const T* data)
2136
memcpy(M,data, 16*sizeof(T));
2138
#if defined ( USE_MATRIX_TEST )
2139
definitelyIdentityMatrix=false;
2145
// sets if the matrix is definitely identity matrix
2147
inline void CMatrix4<T>::setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix)
2149
#if defined ( USE_MATRIX_TEST )
2150
definitelyIdentityMatrix = isDefinitelyIdentityMatrix;
2155
// gets if the matrix is definitely identity matrix
2157
inline bool CMatrix4<T>::getDefinitelyIdentityMatrix() const
2159
#if defined ( USE_MATRIX_TEST )
2160
return definitelyIdentityMatrix;
2167
//! Compare two matrices using the equal method
2169
inline bool CMatrix4<T>::equals(const core::CMatrix4<T>& other, const T tolerance) const
2171
#if defined ( USE_MATRIX_TEST )
2172
if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
2175
for (s32 i = 0; i < 16; ++i)
2176
if (!core::equals(M[i],other.M[i], tolerance))
2183
// Multiply by scalar.
2185
inline CMatrix4<T> operator*(const T scalar, const CMatrix4<T>& mat)
2191
//! Typedef for f32 matrix
2192
typedef CMatrix4<f32> matrix4;
2194
//! global const identity matrix
2195
IRRLICHT_API extern const matrix4 IdentityMatrix;
2197
} // end namespace core
2198
} // end namespace irr