Irrlicht 3D Engine
matrix4.h
Go to the documentation of this file.
1 // Copyright (C) 2002-2012 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 seldom 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 
43 
44  template <class T>
45  class CMatrix4
46  {
47  public:
48 
51  {
58  };
59 
61 
62  CMatrix4( eConstructor constructor = EM4CONST_IDENTITY );
63 
65  CMatrix4(const T& r0c0, const T& r0c1, const T& r0c2, const T& r0c3,
66  const T& r1c0, const T& r1c1, const T& r1c2, const T& r1c3,
67  const T& r2c0, const T& r2c1, const T& r2c2, const T& r2c3,
68  const T& r3c0, const T& r3c1, const T& r3c2, const T& r3c3)
69  {
70  M[0] = r0c0; M[1] = r0c1; M[2] = r0c2; M[3] = r0c3;
71  M[4] = r1c0; M[5] = r1c1; M[6] = r1c2; M[7] = r1c3;
72  M[8] = r2c0; M[9] = r2c1; M[10] = r2c2; M[11] = r2c3;
73  M[12] = r3c0; M[13] = r3c1; M[14] = r3c2; M[15] = r3c3;
74  }
75 
77 
79  CMatrix4(const CMatrix4<T>& other, eConstructor constructor = EM4CONST_COPY);
80 
82  T& operator()(const s32 row, const s32 col)
83  {
84 #if defined ( USE_MATRIX_TEST )
85  definitelyIdentityMatrix=false;
86 #endif
87  return M[ row * 4 + col ];
88  }
89 
91  const T& operator()(const s32 row, const s32 col) const { return M[row * 4 + col]; }
92 
94  T& operator[](u32 index)
95  {
96 #if defined ( USE_MATRIX_TEST )
97  definitelyIdentityMatrix=false;
98 #endif
99  return M[index];
100  }
101 
103  const T& operator[](u32 index) const { return M[index]; }
104 
106  inline CMatrix4<T>& operator=(const CMatrix4<T> &other);
107 
109  inline CMatrix4<T>& operator=(const T& scalar);
110 
112  const T* pointer() const { return M; }
113  T* pointer()
114  {
115 #if defined ( USE_MATRIX_TEST )
116  definitelyIdentityMatrix=false;
117 #endif
118  return M;
119  }
120 
122  bool operator==(const CMatrix4<T> &other) const;
123 
125  bool operator!=(const CMatrix4<T> &other) const;
126 
128  CMatrix4<T> operator+(const CMatrix4<T>& other) const;
129 
131  CMatrix4<T>& operator+=(const CMatrix4<T>& other);
132 
134  CMatrix4<T> operator-(const CMatrix4<T>& other) const;
135 
137  CMatrix4<T>& operator-=(const CMatrix4<T>& other);
138 
140 
141  inline CMatrix4<T>& setbyproduct(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b );
142 
144 
146  CMatrix4<T>& setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b );
147 
149 
150  CMatrix4<T> operator*(const CMatrix4<T>& other) const;
151 
153 
154  CMatrix4<T>& operator*=(const CMatrix4<T>& other);
155 
157  CMatrix4<T> operator*(const T& scalar) const;
158 
160  CMatrix4<T>& operator*=(const T& scalar);
161 
163  inline CMatrix4<T>& makeIdentity();
164 
166  inline bool isIdentity() const;
167 
169  inline bool isOrthogonal() const;
170 
172  bool isIdentity_integer_base () const;
173 
175  CMatrix4<T>& setTranslation( const vector3d<T>& translation );
176 
178  vector3d<T> getTranslation() const;
179 
181  CMatrix4<T>& setInverseTranslation( const vector3d<T>& translation );
182 
184  inline CMatrix4<T>& setRotationRadians( const vector3d<T>& rotation );
185 
187  CMatrix4<T>& setRotationDegrees( const vector3d<T>& rotation );
188 
190 
194 
196 
199 
201 
202  inline CMatrix4<T>& setInverseRotationRadians( const vector3d<T>& rotation );
203 
205 
206  inline CMatrix4<T>& setInverseRotationDegrees( const vector3d<T>& rotation );
207 
209 
210  inline CMatrix4<T>& setRotationAxisRadians(const T& angle, const vector3d<T>& axis);
211 
213  CMatrix4<T>& setScale( const vector3d<T>& scale );
214 
216  CMatrix4<T>& setScale( const T scale ) { return setScale(core::vector3d<T>(scale,scale,scale)); }
217 
219  core::vector3d<T> getScale() const;
220 
222  void inverseTranslateVect( vector3df& vect ) const;
223 
225  void inverseRotateVect( vector3df& vect ) const;
226 
228  void rotateVect( vector3df& vect ) const;
229 
231  void rotateVect(core::vector3df& out, const core::vector3df& in) const;
232 
234  void rotateVect(T *out,const core::vector3df &in) const;
235 
237 
238  void transformVect( vector3df& vect) const;
239 
241 
242  void transformVect( vector3df& out, const vector3df& in ) const;
243 
245 
247  void transformVect(T *out,const core::vector3df &in) const;
248 
250 
252  void transformVec3(T *out, const T * in) const;
253 
255  void transformVec4(T *out, const T * in) const;
256 
258 
259  void translateVect( vector3df& vect ) const;
260 
262  void transformPlane( core::plane3d<f32> &plane) const;
263 
265  void transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const;
266 
268 
270  void transformBox(core::aabbox3d<f32>& box) const;
271 
273 
275  void transformBoxEx(core::aabbox3d<f32>& box) const;
276 
278  void multiplyWith1x4Matrix(T* matrix) const;
279 
281 
282  bool makeInverse();
283 
284 
286 
287  bool getInversePrimitive ( CMatrix4<T>& out ) const;
288 
290 
292  bool getInverse(CMatrix4<T>& out) const;
293 
295  //\param zClipFromZero: Clipping of z can be projected from 0 to w when true (D3D style) and from -w to w when false (OGL style).
296  CMatrix4<T>& buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero=true);
297 
299  CMatrix4<T>& buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero=true);
300 
302  CMatrix4<T>& buildProjectionMatrixPerspectiveFovInfinityLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon=0);
303 
305  CMatrix4<T>& buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
306 
308  CMatrix4<T>& buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
309 
311  //\param zClipFromZero: Clipping of z can be projected from 0 to 1 when true (D3D style) and from -1 to 1 when false (OGL style).
312  CMatrix4<T>& buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
313 
315  CMatrix4<T>& buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
316 
319  const vector3df& position,
320  const vector3df& target,
321  const vector3df& upVector);
322 
325  const vector3df& position,
326  const vector3df& target,
327  const vector3df& upVector);
328 
330 
334  CMatrix4<T>& buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point=1.0f);
335 
337 
338  CMatrix4<T>& buildNDCToDCMatrix( const core::rect<s32>& area, f32 zScale);
339 
341 
343  CMatrix4<T> interpolate(const core::CMatrix4<T>& b, f32 time) const;
344 
346  CMatrix4<T> getTransposed() const;
347 
349  inline void getTransposed( CMatrix4<T>& dest ) const;
350 
352 
356 
358 
361  void setRotationCenter(const core::vector3df& center, const core::vector3df& translate);
362 
364 
370  void buildAxisAlignedBillboard(const core::vector3df& camPos,
371  const core::vector3df& center,
372  const core::vector3df& translation,
373  const core::vector3df& axis,
374  const core::vector3df& from);
375 
376  /*
377  construct 2D Texture transformations
378  rotate about center, scale, and transform.
379  */
382  const core::vector2df &rotatecenter,
383  const core::vector2df &translate,
384  const core::vector2df &scale);
385 
387 
392 
394 
399 
401 
403  void getTextureTranslate( f32& x, f32& y ) const;
404 
406 
411 
413 
417  CMatrix4<T>& setTextureScale( f32 sx, f32 sy );
418 
420 
422  void getTextureScale( f32& sx, f32& sy ) const;
423 
425 
430 
432  CMatrix4<T>& setM(const T* data);
433 
435  void setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix);
436 
438  bool getDefinitelyIdentityMatrix() const;
439 
441  bool equals(const core::CMatrix4<T>& other, const T tolerance=(T)ROUNDING_ERROR_f64) const;
442 
443  private:
445  T M[16];
446 #if defined ( USE_MATRIX_TEST )
447  mutable u32 definitelyIdentityMatrix;
449 #endif
450 #if defined ( USE_MATRIX_TEST_DEBUG )
451  u32 id;
452  mutable u32 calls;
453 #endif
454 
455  };
456 
457  // Default constructor
458  template <class T>
459  inline CMatrix4<T>::CMatrix4( eConstructor constructor )
460 #if defined ( USE_MATRIX_TEST )
461  : definitelyIdentityMatrix(BIT_UNTESTED)
462 #endif
463 #if defined ( USE_MATRIX_TEST_DEBUG )
464  ,id ( MTest.ID++), calls ( 0 )
465 #endif
466  {
467  switch ( constructor )
468  {
469  case EM4CONST_NOTHING:
470  case EM4CONST_COPY:
471  break;
472  case EM4CONST_IDENTITY:
473  case EM4CONST_INVERSE:
474  default:
475  makeIdentity();
476  break;
477  }
478  }
479 
480  // Copy constructor
481  template <class T>
482  inline CMatrix4<T>::CMatrix4( const CMatrix4<T>& other, eConstructor constructor)
483 #if defined ( USE_MATRIX_TEST )
484  : definitelyIdentityMatrix(BIT_UNTESTED)
485 #endif
486 #if defined ( USE_MATRIX_TEST_DEBUG )
487  ,id ( MTest.ID++), calls ( 0 )
488 #endif
489  {
490  switch ( constructor )
491  {
492  case EM4CONST_IDENTITY:
493  makeIdentity();
494  break;
495  case EM4CONST_NOTHING:
496  break;
497  case EM4CONST_COPY:
498  *this = other;
499  break;
500  case EM4CONST_TRANSPOSED:
501  other.getTransposed(*this);
502  break;
503  case EM4CONST_INVERSE:
504  if (!other.getInverse(*this))
505  memset(M, 0, 16*sizeof(T));
506  break;
507  case EM4CONST_INVERSE_TRANSPOSED:
508  if (!other.getInverse(*this))
509  memset(M, 0, 16*sizeof(T));
510  else
511  *this=getTransposed();
512  break;
513  }
514  }
515 
517  template <class T>
518  inline CMatrix4<T> CMatrix4<T>::operator+(const CMatrix4<T>& other) const
519  {
520  CMatrix4<T> temp ( EM4CONST_NOTHING );
521 
522  temp[0] = M[0]+other[0];
523  temp[1] = M[1]+other[1];
524  temp[2] = M[2]+other[2];
525  temp[3] = M[3]+other[3];
526  temp[4] = M[4]+other[4];
527  temp[5] = M[5]+other[5];
528  temp[6] = M[6]+other[6];
529  temp[7] = M[7]+other[7];
530  temp[8] = M[8]+other[8];
531  temp[9] = M[9]+other[9];
532  temp[10] = M[10]+other[10];
533  temp[11] = M[11]+other[11];
534  temp[12] = M[12]+other[12];
535  temp[13] = M[13]+other[13];
536  temp[14] = M[14]+other[14];
537  temp[15] = M[15]+other[15];
538 
539  return temp;
540  }
541 
543  template <class T>
545  {
546  M[0]+=other[0];
547  M[1]+=other[1];
548  M[2]+=other[2];
549  M[3]+=other[3];
550  M[4]+=other[4];
551  M[5]+=other[5];
552  M[6]+=other[6];
553  M[7]+=other[7];
554  M[8]+=other[8];
555  M[9]+=other[9];
556  M[10]+=other[10];
557  M[11]+=other[11];
558  M[12]+=other[12];
559  M[13]+=other[13];
560  M[14]+=other[14];
561  M[15]+=other[15];
562 
563  return *this;
564  }
565 
567  template <class T>
568  inline CMatrix4<T> CMatrix4<T>::operator-(const CMatrix4<T>& other) const
569  {
570  CMatrix4<T> temp ( EM4CONST_NOTHING );
571 
572  temp[0] = M[0]-other[0];
573  temp[1] = M[1]-other[1];
574  temp[2] = M[2]-other[2];
575  temp[3] = M[3]-other[3];
576  temp[4] = M[4]-other[4];
577  temp[5] = M[5]-other[5];
578  temp[6] = M[6]-other[6];
579  temp[7] = M[7]-other[7];
580  temp[8] = M[8]-other[8];
581  temp[9] = M[9]-other[9];
582  temp[10] = M[10]-other[10];
583  temp[11] = M[11]-other[11];
584  temp[12] = M[12]-other[12];
585  temp[13] = M[13]-other[13];
586  temp[14] = M[14]-other[14];
587  temp[15] = M[15]-other[15];
588 
589  return temp;
590  }
591 
593  template <class T>
595  {
596  M[0]-=other[0];
597  M[1]-=other[1];
598  M[2]-=other[2];
599  M[3]-=other[3];
600  M[4]-=other[4];
601  M[5]-=other[5];
602  M[6]-=other[6];
603  M[7]-=other[7];
604  M[8]-=other[8];
605  M[9]-=other[9];
606  M[10]-=other[10];
607  M[11]-=other[11];
608  M[12]-=other[12];
609  M[13]-=other[13];
610  M[14]-=other[14];
611  M[15]-=other[15];
612 
613  return *this;
614  }
615 
617  template <class T>
618  inline CMatrix4<T> CMatrix4<T>::operator*(const T& scalar) const
619  {
620  CMatrix4<T> temp ( EM4CONST_NOTHING );
621 
622  temp[0] = M[0]*scalar;
623  temp[1] = M[1]*scalar;
624  temp[2] = M[2]*scalar;
625  temp[3] = M[3]*scalar;
626  temp[4] = M[4]*scalar;
627  temp[5] = M[5]*scalar;
628  temp[6] = M[6]*scalar;
629  temp[7] = M[7]*scalar;
630  temp[8] = M[8]*scalar;
631  temp[9] = M[9]*scalar;
632  temp[10] = M[10]*scalar;
633  temp[11] = M[11]*scalar;
634  temp[12] = M[12]*scalar;
635  temp[13] = M[13]*scalar;
636  temp[14] = M[14]*scalar;
637  temp[15] = M[15]*scalar;
638 
639  return temp;
640  }
641 
643  template <class T>
644  inline CMatrix4<T>& CMatrix4<T>::operator*=(const T& scalar)
645  {
646  M[0]*=scalar;
647  M[1]*=scalar;
648  M[2]*=scalar;
649  M[3]*=scalar;
650  M[4]*=scalar;
651  M[5]*=scalar;
652  M[6]*=scalar;
653  M[7]*=scalar;
654  M[8]*=scalar;
655  M[9]*=scalar;
656  M[10]*=scalar;
657  M[11]*=scalar;
658  M[12]*=scalar;
659  M[13]*=scalar;
660  M[14]*=scalar;
661  M[15]*=scalar;
662 
663  return *this;
664  }
665 
667  template <class T>
669  {
670 #if defined ( USE_MATRIX_TEST )
671  // do checks on your own in order to avoid copy creation
672  if ( !other.isIdentity() )
673  {
674  if ( this->isIdentity() )
675  {
676  return (*this = other);
677  }
678  else
679  {
680  CMatrix4<T> temp ( *this );
681  return setbyproduct_nocheck( temp, other );
682  }
683  }
684  return *this;
685 #else
686  CMatrix4<T> temp ( *this );
687  return setbyproduct_nocheck( temp, other );
688 #endif
689  }
690 
692  // set this matrix to the product of two other matrices
693  // goal is to reduce stack use and copy
694  template <class T>
696  {
697  const T *m1 = other_a.M;
698  const T *m2 = other_b.M;
699 
700  M[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
701  M[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
702  M[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
703  M[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
704 
705  M[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
706  M[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
707  M[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
708  M[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
709 
710  M[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
711  M[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
712  M[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
713  M[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
714 
715  M[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
716  M[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
717  M[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
718  M[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
719 #if defined ( USE_MATRIX_TEST )
720  definitelyIdentityMatrix=false;
721 #endif
722  return *this;
723  }
724 
725 
727  // set this matrix to the product of two other matrices
728  // goal is to reduce stack use and copy
729  template <class T>
730  inline CMatrix4<T>& CMatrix4<T>::setbyproduct(const CMatrix4<T>& other_a, const CMatrix4<T>& other_b )
731  {
732 #if defined ( USE_MATRIX_TEST )
733  if ( other_a.isIdentity () )
734  return (*this = other_b);
735  else
736  if ( other_b.isIdentity () )
737  return (*this = other_a);
738  else
739  return setbyproduct_nocheck(other_a,other_b);
740 #else
741  return setbyproduct_nocheck(other_a,other_b);
742 #endif
743  }
744 
746  template <class T>
748  {
749 #if defined ( USE_MATRIX_TEST )
750  // Testing purpose..
751  if ( this->isIdentity() )
752  return m2;
753  if ( m2.isIdentity() )
754  return *this;
755 #endif
756 
757  CMatrix4<T> m3 ( EM4CONST_NOTHING );
758 
759  const T *m1 = M;
760 
761  m3[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
762  m3[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
763  m3[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
764  m3[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
765 
766  m3[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
767  m3[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
768  m3[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
769  m3[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
770 
771  m3[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
772  m3[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
773  m3[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
774  m3[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
775 
776  m3[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
777  m3[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
778  m3[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
779  m3[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
780  return m3;
781  }
782 
783 
784 
785  template <class T>
787  {
788  return vector3d<T>(M[12], M[13], M[14]);
789  }
790 
791 
792  template <class T>
794  {
795  M[12] = translation.X;
796  M[13] = translation.Y;
797  M[14] = translation.Z;
798 #if defined ( USE_MATRIX_TEST )
799  definitelyIdentityMatrix=false;
800 #endif
801  return *this;
802  }
803 
804  template <class T>
806  {
807  M[12] = -translation.X;
808  M[13] = -translation.Y;
809  M[14] = -translation.Z;
810 #if defined ( USE_MATRIX_TEST )
811  definitelyIdentityMatrix=false;
812 #endif
813  return *this;
814  }
815 
816  template <class T>
818  {
819  M[0] = scale.X;
820  M[5] = scale.Y;
821  M[10] = scale.Z;
822 #if defined ( USE_MATRIX_TEST )
823  definitelyIdentityMatrix=false;
824 #endif
825  return *this;
826  }
827 
829 
836  template <class T>
838  {
839  // See http://www.robertblum.com/articles/2005/02/14/decomposing-matrices
840 
841  // Deal with the 0 rotation case first
842  // Prior to Irrlicht 1.6, we always returned this value.
843  if(core::iszero(M[1]) && core::iszero(M[2]) &&
844  core::iszero(M[4]) && core::iszero(M[6]) &&
845  core::iszero(M[8]) && core::iszero(M[9]))
846  return vector3d<T>(M[0], M[5], M[10]);
847 
848  // We have to do the full calculation.
849  return vector3d<T>(sqrtf(M[0] * M[0] + M[1] * M[1] + M[2] * M[2]),
850  sqrtf(M[4] * M[4] + M[5] * M[5] + M[6] * M[6]),
851  sqrtf(M[8] * M[8] + M[9] * M[9] + M[10] * M[10]));
852  }
853 
854  template <class T>
856  {
857  return setRotationRadians( rotation * core::DEGTORAD );
858  }
859 
860  template <class T>
862  {
863  return setInverseRotationRadians( rotation * core::DEGTORAD );
864  }
865 
866  template <class T>
868  {
869  const f64 cr = cos( rotation.X );
870  const f64 sr = sin( rotation.X );
871  const f64 cp = cos( rotation.Y );
872  const f64 sp = sin( rotation.Y );
873  const f64 cy = cos( rotation.Z );
874  const f64 sy = sin( rotation.Z );
875 
876  M[0] = (T)( cp*cy );
877  M[1] = (T)( cp*sy );
878  M[2] = (T)( -sp );
879 
880  const f64 srsp = sr*sp;
881  const f64 crsp = cr*sp;
882 
883  M[4] = (T)( srsp*cy-cr*sy );
884  M[5] = (T)( srsp*sy+cr*cy );
885  M[6] = (T)( sr*cp );
886 
887  M[8] = (T)( crsp*cy+sr*sy );
888  M[9] = (T)( crsp*sy-sr*cy );
889  M[10] = (T)( cr*cp );
890 #if defined ( USE_MATRIX_TEST )
891  definitelyIdentityMatrix=false;
892 #endif
893  return *this;
894  }
895 
896 
898 
903  template <class T>
905  {
906  const CMatrix4<T> &mat = *this;
907  core::vector3d<T> scale(scale_);
908  // we need to check for negative scale on to axes, which would bring up wrong results
909  if (scale.Y<0 && scale.Z<0)
910  {
911  scale.Y =-scale.Y;
912  scale.Z =-scale.Z;
913  }
914  else if (scale.X<0 && scale.Z<0)
915  {
916  scale.X =-scale.X;
917  scale.Z =-scale.Z;
918  }
919  else if (scale.X<0 && scale.Y<0)
920  {
921  scale.X =-scale.X;
922  scale.Y =-scale.Y;
923  }
924  const core::vector3d<f64> invScale(core::reciprocal(scale.X),core::reciprocal(scale.Y),core::reciprocal(scale.Z));
925 
926  f64 Y = -asin(core::clamp(mat[2]*invScale.X, -1.0, 1.0));
927  const f64 C = cos(Y);
928  Y *= RADTODEG64;
929 
930  f64 rotx, roty, X, Z;
931 
932  if (!core::iszero(C))
933  {
934  const f64 invC = core::reciprocal(C);
935  rotx = mat[10] * invC * invScale.Z;
936  roty = mat[6] * invC * invScale.Y;
937  X = atan2( roty, rotx ) * RADTODEG64;
938  rotx = mat[0] * invC * invScale.X;
939  roty = mat[1] * invC * invScale.X;
940  Z = atan2( roty, rotx ) * RADTODEG64;
941  }
942  else
943  {
944  X = 0.0;
945  rotx = mat[5] * invScale.Y;
946  roty = -mat[4] * invScale.Y;
947  Z = atan2( roty, rotx ) * RADTODEG64;
948  }
949 
950  // fix values that get below zero
951  if (X < 0.0) X += 360.0;
952  if (Y < 0.0) Y += 360.0;
953  if (Z < 0.0) Z += 360.0;
954 
955  return vector3d<T>((T)X,(T)Y,(T)Z);
956  }
957 
959 
963  template <class T>
965  {
966  return getRotationDegrees(getScale());
967  }
968 
969 
971  template <class T>
973  {
974  f64 cr = cos( rotation.X );
975  f64 sr = sin( rotation.X );
976  f64 cp = cos( rotation.Y );
977  f64 sp = sin( rotation.Y );
978  f64 cy = cos( rotation.Z );
979  f64 sy = sin( rotation.Z );
980 
981  M[0] = (T)( cp*cy );
982  M[4] = (T)( cp*sy );
983  M[8] = (T)( -sp );
984 
985  f64 srsp = sr*sp;
986  f64 crsp = cr*sp;
987 
988  M[1] = (T)( srsp*cy-cr*sy );
989  M[5] = (T)( srsp*sy+cr*cy );
990  M[9] = (T)( sr*cp );
991 
992  M[2] = (T)( crsp*cy+sr*sy );
993  M[6] = (T)( crsp*sy-sr*cy );
994  M[10] = (T)( cr*cp );
995 #if defined ( USE_MATRIX_TEST )
996  definitelyIdentityMatrix=false;
997 #endif
998  return *this;
999  }
1000 
1002  template <class T>
1003  inline CMatrix4<T>& CMatrix4<T>::setRotationAxisRadians( const T& angle, const vector3d<T>& axis )
1004  {
1005  const f64 c = cos(angle);
1006  const f64 s = sin(angle);
1007  const f64 t = 1.0 - c;
1008 
1009  const f64 tx = t * axis.X;
1010  const f64 ty = t * axis.Y;
1011  const f64 tz = t * axis.Z;
1012 
1013  const f64 sx = s * axis.X;
1014  const f64 sy = s * axis.Y;
1015  const f64 sz = s * axis.Z;
1016 
1017  M[0] = (T)(tx * axis.X + c);
1018  M[1] = (T)(tx * axis.Y + sz);
1019  M[2] = (T)(tx * axis.Z - sy);
1020 
1021  M[4] = (T)(ty * axis.X - sz);
1022  M[5] = (T)(ty * axis.Y + c);
1023  M[6] = (T)(ty * axis.Z + sx);
1024 
1025  M[8] = (T)(tz * axis.X + sy);
1026  M[9] = (T)(tz * axis.Y - sx);
1027  M[10] = (T)(tz * axis.Z + c);
1028 
1029 #if defined ( USE_MATRIX_TEST )
1030  definitelyIdentityMatrix=false;
1031 #endif
1032  return *this;
1033  }
1034 
1035 
1038  template <class T>
1040  {
1041  memset(M, 0, 16*sizeof(T));
1042  M[0] = M[5] = M[10] = M[15] = (T)1;
1043 #if defined ( USE_MATRIX_TEST )
1044  definitelyIdentityMatrix=true;
1045 #endif
1046  return *this;
1047  }
1048 
1049 
1050  /*
1051  check identity with epsilon
1052  solve floating range problems..
1053  */
1054  template <class T>
1055  inline bool CMatrix4<T>::isIdentity() const
1056  {
1057 #if defined ( USE_MATRIX_TEST )
1058  if (definitelyIdentityMatrix)
1059  return true;
1060 #endif
1061  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 ))
1062  return false;
1063 
1064  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 ))
1065  return false;
1066 
1067  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 ))
1068  return false;
1069 
1070  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 ))
1071  return false;
1072 /*
1073  if (!core::equals( M[ 0], (T)1 ) ||
1074  !core::equals( M[ 5], (T)1 ) ||
1075  !core::equals( M[10], (T)1 ) ||
1076  !core::equals( M[15], (T)1 ))
1077  return false;
1078 
1079  for (s32 i=0; i<4; ++i)
1080  for (s32 j=0; j<4; ++j)
1081  if ((j != i) && (!iszero((*this)(i,j))))
1082  return false;
1083 */
1084 #if defined ( USE_MATRIX_TEST )
1085  definitelyIdentityMatrix=true;
1086 #endif
1087  return true;
1088  }
1089 
1090 
1091  /* Check orthogonality of matrix. */
1092  template <class T>
1093  inline bool CMatrix4<T>::isOrthogonal() const
1094  {
1095  T dp=M[0] * M[4 ] + M[1] * M[5 ] + M[2 ] * M[6 ] + M[3 ] * M[7 ];
1096  if (!iszero(dp))
1097  return false;
1098  dp = M[0] * M[8 ] + M[1] * M[9 ] + M[2 ] * M[10] + M[3 ] * M[11];
1099  if (!iszero(dp))
1100  return false;
1101  dp = M[0] * M[12] + M[1] * M[13] + M[2 ] * M[14] + M[3 ] * M[15];
1102  if (!iszero(dp))
1103  return false;
1104  dp = M[4] * M[8 ] + M[5] * M[9 ] + M[6 ] * M[10] + M[7 ] * M[11];
1105  if (!iszero(dp))
1106  return false;
1107  dp = M[4] * M[12] + M[5] * M[13] + M[6 ] * M[14] + M[7 ] * M[15];
1108  if (!iszero(dp))
1109  return false;
1110  dp = M[8] * M[12] + M[9] * M[13] + M[10] * M[14] + M[11] * M[15];
1111  return (iszero(dp));
1112  }
1113 
1114 
1115  /*
1116  doesn't solve floating range problems..
1117  but takes care on +/- 0 on translation because we are changing it..
1118  reducing floating point branches
1119  but it needs the floats in memory..
1120  */
1121  template <class T>
1123  {
1124 #if defined ( USE_MATRIX_TEST )
1125  if (definitelyIdentityMatrix)
1126  return true;
1127 #endif
1128  if(IR(M[0])!=F32_VALUE_1) return false;
1129  if(IR(M[1])!=0) return false;
1130  if(IR(M[2])!=0) return false;
1131  if(IR(M[3])!=0) return false;
1132 
1133  if(IR(M[4])!=0) return false;
1134  if(IR(M[5])!=F32_VALUE_1) return false;
1135  if(IR(M[6])!=0) return false;
1136  if(IR(M[7])!=0) return false;
1137 
1138  if(IR(M[8])!=0) return false;
1139  if(IR(M[9])!=0) return false;
1140  if(IR(M[10])!=F32_VALUE_1) return false;
1141  if(IR(M[11])!=0) return false;
1142 
1143  if(IR(M[12])!=0) return false;
1144  if(IR(M[13])!=0) return false;
1145  if(IR(M[13])!=0) return false;
1146  if(IR(M[15])!=F32_VALUE_1) return false;
1147 
1148 #if defined ( USE_MATRIX_TEST )
1149  definitelyIdentityMatrix=true;
1150 #endif
1151  return true;
1152  }
1153 
1154 
1155  template <class T>
1156  inline void CMatrix4<T>::rotateVect( vector3df& vect ) const
1157  {
1158  vector3df tmp = vect;
1159  vect.X = tmp.X*M[0] + tmp.Y*M[4] + tmp.Z*M[8];
1160  vect.Y = tmp.X*M[1] + tmp.Y*M[5] + tmp.Z*M[9];
1161  vect.Z = tmp.X*M[2] + tmp.Y*M[6] + tmp.Z*M[10];
1162  }
1163 
1165  template <class T>
1166  inline void CMatrix4<T>::rotateVect(core::vector3df& out, const core::vector3df& in) const
1167  {
1168  out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
1169  out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
1170  out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
1171  }
1172 
1174  template <class T>
1175  inline void CMatrix4<T>::rotateVect(T *out, const core::vector3df& in) const
1176  {
1177  out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
1178  out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
1179  out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
1180  }
1181 
1182  template <class T>
1183  inline void CMatrix4<T>::inverseRotateVect( vector3df& vect ) const
1184  {
1185  vector3df tmp = vect;
1186  vect.X = tmp.X*M[0] + tmp.Y*M[1] + tmp.Z*M[2];
1187  vect.Y = tmp.X*M[4] + tmp.Y*M[5] + tmp.Z*M[6];
1188  vect.Z = tmp.X*M[8] + tmp.Y*M[9] + tmp.Z*M[10];
1189  }
1190 
1191  template <class T>
1192  inline void CMatrix4<T>::transformVect( vector3df& vect) const
1193  {
1194  f32 vector[3];
1195 
1196  vector[0] = vect.X*M[0] + vect.Y*M[4] + vect.Z*M[8] + M[12];
1197  vector[1] = vect.X*M[1] + vect.Y*M[5] + vect.Z*M[9] + M[13];
1198  vector[2] = vect.X*M[2] + vect.Y*M[6] + vect.Z*M[10] + M[14];
1199 
1200  vect.X = vector[0];
1201  vect.Y = vector[1];
1202  vect.Z = vector[2];
1203  }
1204 
1205  template <class T>
1206  inline void CMatrix4<T>::transformVect( vector3df& out, const vector3df& in) const
1207  {
1208  out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
1209  out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
1210  out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
1211  }
1212 
1213 
1214  template <class T>
1215  inline void CMatrix4<T>::transformVect(T *out, const core::vector3df &in) const
1216  {
1217  out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
1218  out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
1219  out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
1220  out[3] = in.X*M[3] + in.Y*M[7] + in.Z*M[11] + M[15];
1221  }
1222 
1223  template <class T>
1224  inline void CMatrix4<T>::transformVec3(T *out, const T * in) const
1225  {
1226  out[0] = in[0]*M[0] + in[1]*M[4] + in[2]*M[8] + M[12];
1227  out[1] = in[0]*M[1] + in[1]*M[5] + in[2]*M[9] + M[13];
1228  out[2] = in[0]*M[2] + in[1]*M[6] + in[2]*M[10] + M[14];
1229  }
1230 
1231  template <class T>
1232  inline void CMatrix4<T>::transformVec4(T *out, const T * in) const
1233  {
1234  out[0] = in[0]*M[0] + in[1]*M[4] + in[2]*M[8] + in[3]*M[12];
1235  out[1] = in[0]*M[1] + in[1]*M[5] + in[2]*M[9] + in[3]*M[13];
1236  out[2] = in[0]*M[2] + in[1]*M[6] + in[2]*M[10] + in[3]*M[14];
1237  out[3] = in[0]*M[3] + in[1]*M[7] + in[2]*M[11] + in[3]*M[16];
1238  }
1239 
1240 
1242  template <class T>
1244  {
1245  vector3df member;
1246  // Transform the plane member point, i.e. rotate, translate and scale it.
1247  transformVect(member, plane.getMemberPoint());
1248 
1249  // Transform the normal by the transposed inverse of the matrix
1250  CMatrix4<T> transposedInverse(*this, EM4CONST_INVERSE_TRANSPOSED);
1251  vector3df normal = plane.Normal;
1252  transposedInverse.rotateVect(normal);
1253  plane.setPlane(member, normal.normalize());
1254  }
1255 
1257  template <class T>
1259  {
1260  out = in;
1261  transformPlane( out );
1262  }
1263 
1267  template <class T>
1269  {
1270 #if defined ( USE_MATRIX_TEST )
1271  if (isIdentity())
1272  return;
1273 #endif
1274 
1275  transformVect(box.MinEdge);
1276  transformVect(box.MaxEdge);
1277  box.repair();
1278  }
1279 
1281  template <class T>
1283  {
1284 #if defined ( USE_MATRIX_TEST )
1285  if (isIdentity())
1286  return;
1287 #endif
1288 
1289  const f32 Amin[3] = {box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z};
1290  const f32 Amax[3] = {box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z};
1291 
1292  f32 Bmin[3];
1293  f32 Bmax[3];
1294 
1295  Bmin[0] = Bmax[0] = M[12];
1296  Bmin[1] = Bmax[1] = M[13];
1297  Bmin[2] = Bmax[2] = M[14];
1298 
1299  const CMatrix4<T> &m = *this;
1300 
1301  for (u32 i = 0; i < 3; ++i)
1302  {
1303  for (u32 j = 0; j < 3; ++j)
1304  {
1305  const f32 a = m(j,i) * Amin[j];
1306  const f32 b = m(j,i) * Amax[j];
1307 
1308  if (a < b)
1309  {
1310  Bmin[i] += a;
1311  Bmax[i] += b;
1312  }
1313  else
1314  {
1315  Bmin[i] += b;
1316  Bmax[i] += a;
1317  }
1318  }
1319  }
1320 
1321  box.MinEdge.X = Bmin[0];
1322  box.MinEdge.Y = Bmin[1];
1323  box.MinEdge.Z = Bmin[2];
1324 
1325  box.MaxEdge.X = Bmax[0];
1326  box.MaxEdge.Y = Bmax[1];
1327  box.MaxEdge.Z = Bmax[2];
1328  }
1329 
1330 
1332  template <class T>
1333  inline void CMatrix4<T>::multiplyWith1x4Matrix(T* matrix) const
1334  {
1335  /*
1336  0 1 2 3
1337  4 5 6 7
1338  8 9 10 11
1339  12 13 14 15
1340  */
1341 
1342  T mat[4];
1343  mat[0] = matrix[0];
1344  mat[1] = matrix[1];
1345  mat[2] = matrix[2];
1346  mat[3] = matrix[3];
1347 
1348  matrix[0] = M[0]*mat[0] + M[4]*mat[1] + M[8]*mat[2] + M[12]*mat[3];
1349  matrix[1] = M[1]*mat[0] + M[5]*mat[1] + M[9]*mat[2] + M[13]*mat[3];
1350  matrix[2] = M[2]*mat[0] + M[6]*mat[1] + M[10]*mat[2] + M[14]*mat[3];
1351  matrix[3] = M[3]*mat[0] + M[7]*mat[1] + M[11]*mat[2] + M[15]*mat[3];
1352  }
1353 
1354  template <class T>
1356  {
1357  vect.X = vect.X-M[12];
1358  vect.Y = vect.Y-M[13];
1359  vect.Z = vect.Z-M[14];
1360  }
1361 
1362  template <class T>
1363  inline void CMatrix4<T>::translateVect( vector3df& vect ) const
1364  {
1365  vect.X = vect.X+M[12];
1366  vect.Y = vect.Y+M[13];
1367  vect.Z = vect.Z+M[14];
1368  }
1369 
1370 
1371  template <class T>
1372  inline bool CMatrix4<T>::getInverse(CMatrix4<T>& out) const
1373  {
1377 
1378 #if defined ( USE_MATRIX_TEST )
1379  if ( this->isIdentity() )
1380  {
1381  out=*this;
1382  return true;
1383  }
1384 #endif
1385  const CMatrix4<T> &m = *this;
1386 
1387  f32 d = (m[0] * m[5] - m[1] * m[4]) * (m[10] * m[15] - m[11] * m[14]) -
1388  (m[0] * m[6] - m[2] * m[4]) * (m[9] * m[15] - m[11] * m[13]) +
1389  (m[0] * m[7] - m[3] * m[4]) * (m[9] * m[14] - m[10] * m[13]) +
1390  (m[1] * m[6] - m[2] * m[5]) * (m[8] * m[15] - m[11] * m[12]) -
1391  (m[1] * m[7] - m[3] * m[5]) * (m[8] * m[14] - m[10] * m[12]) +
1392  (m[2] * m[7] - m[3] * m[6]) * (m[8] * m[13] - m[9] * m[12]);
1393 
1394  if( core::iszero ( d, FLT_MIN ) )
1395  return false;
1396 
1397  d = core::reciprocal ( d );
1398 
1399  out[0] = d * (m[5] * (m[10] * m[15] - m[11] * m[14]) +
1400  m[6] * (m[11] * m[13] - m[9] * m[15]) +
1401  m[7] * (m[9] * m[14] - m[10] * m[13]));
1402  out[1] = d * (m[9] * (m[2] * m[15] - m[3] * m[14]) +
1403  m[10] * (m[3] * m[13] - m[1] * m[15]) +
1404  m[11] * (m[1] * m[14] - m[2] * m[13]));
1405  out[2] = d * (m[13] * (m[2] * m[7] - m[3] * m[6]) +
1406  m[14] * (m[3] * m[5] - m[1] * m[7]) +
1407  m[15] * (m[1] * m[6] - m[2] * m[5]));
1408  out[3] = d * (m[1] * (m[7] * m[10] - m[6] * m[11]) +
1409  m[2] * (m[5] * m[11] - m[7] * m[9]) +
1410  m[3] * (m[6] * m[9] - m[5] * m[10]));
1411  out[4] = d * (m[6] * (m[8] * m[15] - m[11] * m[12]) +
1412  m[7] * (m[10] * m[12] - m[8] * m[14]) +
1413  m[4] * (m[11] * m[14] - m[10] * m[15]));
1414  out[5] = d * (m[10] * (m[0] * m[15] - m[3] * m[12]) +
1415  m[11] * (m[2] * m[12] - m[0] * m[14]) +
1416  m[8] * (m[3] * m[14] - m[2] * m[15]));
1417  out[6] = d * (m[14] * (m[0] * m[7] - m[3] * m[4]) +
1418  m[15] * (m[2] * m[4] - m[0] * m[6]) +
1419  m[12] * (m[3] * m[6] - m[2] * m[7]));
1420  out[7] = d * (m[2] * (m[7] * m[8] - m[4] * m[11]) +
1421  m[3] * (m[4] * m[10] - m[6] * m[8]) +
1422  m[0] * (m[6] * m[11] - m[7] * m[10]));
1423  out[8] = d * (m[7] * (m[8] * m[13] - m[9] * m[12]) +
1424  m[4] * (m[9] * m[15] - m[11] * m[13]) +
1425  m[5] * (m[11] * m[12] - m[8] * m[15]));
1426  out[9] = d * (m[11] * (m[0] * m[13] - m[1] * m[12]) +
1427  m[8] * (m[1] * m[15] - m[3] * m[13]) +
1428  m[9] * (m[3] * m[12] - m[0] * m[15]));
1429  out[10] = d * (m[15] * (m[0] * m[5] - m[1] * m[4]) +
1430  m[12] * (m[1] * m[7] - m[3] * m[5]) +
1431  m[13] * (m[3] * m[4] - m[0] * m[7]));
1432  out[11] = d * (m[3] * (m[5] * m[8] - m[4] * m[9]) +
1433  m[0] * (m[7] * m[9] - m[5] * m[11]) +
1434  m[1] * (m[4] * m[11] - m[7] * m[8]));
1435  out[12] = d * (m[4] * (m[10] * m[13] - m[9] * m[14]) +
1436  m[5] * (m[8] * m[14] - m[10] * m[12]) +
1437  m[6] * (m[9] * m[12] - m[8] * m[13]));
1438  out[13] = d * (m[8] * (m[2] * m[13] - m[1] * m[14]) +
1439  m[9] * (m[0] * m[14] - m[2] * m[12]) +
1440  m[10] * (m[1] * m[12] - m[0] * m[13]));
1441  out[14] = d * (m[12] * (m[2] * m[5] - m[1] * m[6]) +
1442  m[13] * (m[0] * m[6] - m[2] * m[4]) +
1443  m[14] * (m[1] * m[4] - m[0] * m[5]));
1444  out[15] = d * (m[0] * (m[5] * m[10] - m[6] * m[9]) +
1445  m[1] * (m[6] * m[8] - m[4] * m[10]) +
1446  m[2] * (m[4] * m[9] - m[5] * m[8]));
1447 
1448 #if defined ( USE_MATRIX_TEST )
1449  out.definitelyIdentityMatrix = definitelyIdentityMatrix;
1450 #endif
1451  return true;
1452  }
1453 
1454 
1457  template <class T>
1459  {
1460  out.M[0 ] = M[0];
1461  out.M[1 ] = M[4];
1462  out.M[2 ] = M[8];
1463  out.M[3 ] = 0;
1464 
1465  out.M[4 ] = M[1];
1466  out.M[5 ] = M[5];
1467  out.M[6 ] = M[9];
1468  out.M[7 ] = 0;
1469 
1470  out.M[8 ] = M[2];
1471  out.M[9 ] = M[6];
1472  out.M[10] = M[10];
1473  out.M[11] = 0;
1474 
1475  out.M[12] = (T)-(M[12]*M[0] + M[13]*M[1] + M[14]*M[2]);
1476  out.M[13] = (T)-(M[12]*M[4] + M[13]*M[5] + M[14]*M[6]);
1477  out.M[14] = (T)-(M[12]*M[8] + M[13]*M[9] + M[14]*M[10]);
1478  out.M[15] = 1;
1479 
1480 #if defined ( USE_MATRIX_TEST )
1481  out.definitelyIdentityMatrix = definitelyIdentityMatrix;
1482 #endif
1483  return true;
1484  }
1485 
1488  template <class T>
1490  {
1491 #if defined ( USE_MATRIX_TEST )
1492  if (definitelyIdentityMatrix)
1493  return true;
1494 #endif
1495  CMatrix4<T> temp ( EM4CONST_NOTHING );
1496 
1497  if (getInverse(temp))
1498  {
1499  *this = temp;
1500  return true;
1501  }
1502 
1503  return false;
1504  }
1505 
1506 
1507  template <class T>
1509  {
1510  if (this==&other)
1511  return *this;
1512  memcpy(M, other.M, 16*sizeof(T));
1513 #if defined ( USE_MATRIX_TEST )
1514  definitelyIdentityMatrix=other.definitelyIdentityMatrix;
1515 #endif
1516  return *this;
1517  }
1518 
1519 
1520  template <class T>
1521  inline CMatrix4<T>& CMatrix4<T>::operator=(const T& scalar)
1522  {
1523  for (s32 i = 0; i < 16; ++i)
1524  M[i]=scalar;
1525 
1526 #if defined ( USE_MATRIX_TEST )
1527  definitelyIdentityMatrix=false;
1528 #endif
1529  return *this;
1530  }
1531 
1532 
1533  template <class T>
1534  inline bool CMatrix4<T>::operator==(const CMatrix4<T> &other) const
1535  {
1536 #if defined ( USE_MATRIX_TEST )
1537  if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
1538  return true;
1539 #endif
1540  for (s32 i = 0; i < 16; ++i)
1541  if (M[i] != other.M[i])
1542  return false;
1543 
1544  return true;
1545  }
1546 
1547 
1548  template <class T>
1549  inline bool CMatrix4<T>::operator!=(const CMatrix4<T> &other) const
1550  {
1551  return !(*this == other);
1552  }
1553 
1554 
1555  // Builds a right-handed perspective projection matrix based on a field of view
1556  template <class T>
1558  f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero)
1559  {
1560  const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
1561  _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
1562  const T w = static_cast<T>(h / aspectRatio);
1563 
1564  _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
1565  M[0] = w;
1566  M[1] = 0;
1567  M[2] = 0;
1568  M[3] = 0;
1569 
1570  M[4] = 0;
1571  M[5] = (T)h;
1572  M[6] = 0;
1573  M[7] = 0;
1574 
1575  M[8] = 0;
1576  M[9] = 0;
1577  //M[10]
1578  M[11] = -1;
1579 
1580  M[12] = 0;
1581  M[13] = 0;
1582  //M[14]
1583  M[15] = 0;
1584 
1585  if ( zClipFromZero ) // DirectX version
1586  {
1587  M[10] = (T)(zFar/(zNear-zFar));
1588  M[14] = (T)(zNear*zFar/(zNear-zFar));
1589  }
1590  else // OpenGL version
1591  {
1592  M[10] = (T)((zFar+zNear)/(zNear-zFar));
1593  M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
1594  }
1595 
1596 #if defined ( USE_MATRIX_TEST )
1597  definitelyIdentityMatrix=false;
1598 #endif
1599  return *this;
1600  }
1601 
1602 
1603  // Builds a left-handed perspective projection matrix based on a field of view
1604  template <class T>
1606  f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero)
1607  {
1608  const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
1609  _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
1610  const T w = static_cast<T>(h / aspectRatio);
1611 
1612  _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
1613  M[0] = w;
1614  M[1] = 0;
1615  M[2] = 0;
1616  M[3] = 0;
1617 
1618  M[4] = 0;
1619  M[5] = (T)h;
1620  M[6] = 0;
1621  M[7] = 0;
1622 
1623  M[8] = 0;
1624  M[9] = 0;
1625  //M[10]
1626  M[11] = 1;
1627 
1628  M[12] = 0;
1629  M[13] = 0;
1630  //M[14]
1631  M[15] = 0;
1632 
1633  if ( zClipFromZero ) // DirectX version
1634  {
1635  M[10] = (T)(zFar/(zFar-zNear));
1636  M[14] = (T)(-zNear*zFar/(zFar-zNear));
1637  }
1638  else // OpenGL version
1639  {
1640  M[10] = (T)((zFar+zNear)/(zFar-zNear));
1641  M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
1642  }
1643 
1644 #if defined ( USE_MATRIX_TEST )
1645  definitelyIdentityMatrix=false;
1646 #endif
1647  return *this;
1648  }
1649 
1650 
1651  // Builds a left-handed perspective projection matrix based on a field of view, with far plane culling at infinity
1652  template <class T>
1654  f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon)
1655  {
1656  const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
1657  _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
1658  const T w = static_cast<T>(h / aspectRatio);
1659 
1660  M[0] = w;
1661  M[1] = 0;
1662  M[2] = 0;
1663  M[3] = 0;
1664 
1665  M[4] = 0;
1666  M[5] = (T)h;
1667  M[6] = 0;
1668  M[7] = 0;
1669 
1670  M[8] = 0;
1671  M[9] = 0;
1672  M[10] = (T)(1.f-epsilon);
1673  M[11] = 1;
1674 
1675  M[12] = 0;
1676  M[13] = 0;
1677  M[14] = (T)(zNear*(epsilon-1.f));
1678  M[15] = 0;
1679 
1680 #if defined ( USE_MATRIX_TEST )
1681  definitelyIdentityMatrix=false;
1682 #endif
1683  return *this;
1684  }
1685 
1686 
1687  // Builds a left-handed orthogonal projection matrix.
1688  template <class T>
1690  f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
1691  {
1692  _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
1693  _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
1694  _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
1695  M[0] = (T)(2/widthOfViewVolume);
1696  M[1] = 0;
1697  M[2] = 0;
1698  M[3] = 0;
1699 
1700  M[4] = 0;
1701  M[5] = (T)(2/heightOfViewVolume);
1702  M[6] = 0;
1703  M[7] = 0;
1704 
1705  M[8] = 0;
1706  M[9] = 0;
1707  // M[10]
1708  M[11] = 0;
1709 
1710  M[12] = 0;
1711  M[13] = 0;
1712  // M[14]
1713  M[15] = 1;
1714 
1715  if ( zClipFromZero )
1716  {
1717  M[10] = (T)(1/(zFar-zNear));
1718  M[14] = (T)(zNear/(zNear-zFar));
1719  }
1720  else
1721  {
1722  M[10] = (T)(2/(zFar-zNear));
1723  M[14] = (T)-(zFar+zNear)/(zFar-zNear);
1724  }
1725 
1726 #if defined ( USE_MATRIX_TEST )
1727  definitelyIdentityMatrix=false;
1728 #endif
1729  return *this;
1730  }
1731 
1732 
1733  // Builds a right-handed orthogonal projection matrix.
1734  template <class T>
1736  f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
1737  {
1738  _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
1739  _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
1740  _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
1741  M[0] = (T)(2/widthOfViewVolume);
1742  M[1] = 0;
1743  M[2] = 0;
1744  M[3] = 0;
1745 
1746  M[4] = 0;
1747  M[5] = (T)(2/heightOfViewVolume);
1748  M[6] = 0;
1749  M[7] = 0;
1750 
1751  M[8] = 0;
1752  M[9] = 0;
1753  // M[10]
1754  M[11] = 0;
1755 
1756  M[12] = 0;
1757  M[13] = 0;
1758  // M[14]
1759  M[15] = 1;
1760 
1761  if ( zClipFromZero )
1762  {
1763  M[10] = (T)(1/(zNear-zFar));
1764  M[14] = (T)(zNear/(zNear-zFar));
1765  }
1766  else
1767  {
1768  M[10] = (T)(2/(zNear-zFar));
1769  M[14] = (T)-(zFar+zNear)/(zFar-zNear);
1770  }
1771 
1772 #if defined ( USE_MATRIX_TEST )
1773  definitelyIdentityMatrix=false;
1774 #endif
1775  return *this;
1776  }
1777 
1778 
1779  // Builds a right-handed perspective projection matrix.
1780  template <class T>
1782  f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
1783  {
1784  _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
1785  _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
1786  _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
1787  M[0] = (T)(2*zNear/widthOfViewVolume);
1788  M[1] = 0;
1789  M[2] = 0;
1790  M[3] = 0;
1791 
1792  M[4] = 0;
1793  M[5] = (T)(2*zNear/heightOfViewVolume);
1794  M[6] = 0;
1795  M[7] = 0;
1796 
1797  M[8] = 0;
1798  M[9] = 0;
1799  //M[10]
1800  M[11] = -1;
1801 
1802  M[12] = 0;
1803  M[13] = 0;
1804  //M[14]
1805  M[15] = 0;
1806 
1807  if ( zClipFromZero ) // DirectX version
1808  {
1809  M[10] = (T)(zFar/(zNear-zFar));
1810  M[14] = (T)(zNear*zFar/(zNear-zFar));
1811  }
1812  else // OpenGL version
1813  {
1814  M[10] = (T)((zFar+zNear)/(zNear-zFar));
1815  M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
1816  }
1817 
1818 #if defined ( USE_MATRIX_TEST )
1819  definitelyIdentityMatrix=false;
1820 #endif
1821  return *this;
1822  }
1823 
1824 
1825  // Builds a left-handed perspective projection matrix.
1826  template <class T>
1828  f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
1829  {
1830  _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
1831  _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
1832  _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
1833  M[0] = (T)(2*zNear/widthOfViewVolume);
1834  M[1] = 0;
1835  M[2] = 0;
1836  M[3] = 0;
1837 
1838  M[4] = 0;
1839  M[5] = (T)(2*zNear/heightOfViewVolume);
1840  M[6] = 0;
1841  M[7] = 0;
1842 
1843  M[8] = 0;
1844  M[9] = 0;
1845  //M[10]
1846  M[11] = 1;
1847 
1848  M[12] = 0;
1849  M[13] = 0;
1850  //M[14] = (T)(zNear*zFar/(zNear-zFar));
1851  M[15] = 0;
1852 
1853  if ( zClipFromZero ) // DirectX version
1854  {
1855  M[10] = (T)(zFar/(zFar-zNear));
1856  M[14] = (T)(zNear*zFar/(zNear-zFar));
1857  }
1858  else // OpenGL version
1859  {
1860  M[10] = (T)((zFar+zNear)/(zFar-zNear));
1861  M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
1862  }
1863 
1864 #if defined ( USE_MATRIX_TEST )
1865  definitelyIdentityMatrix=false;
1866 #endif
1867  return *this;
1868  }
1869 
1870 
1871  // Builds a matrix that flattens geometry into a plane.
1872  template <class T>
1874  {
1875  plane.Normal.normalize();
1876  const f32 d = plane.Normal.dotProduct(light);
1877 
1878  M[ 0] = (T)(-plane.Normal.X * light.X + d);
1879  M[ 1] = (T)(-plane.Normal.X * light.Y);
1880  M[ 2] = (T)(-plane.Normal.X * light.Z);
1881  M[ 3] = (T)(-plane.Normal.X * point);
1882 
1883  M[ 4] = (T)(-plane.Normal.Y * light.X);
1884  M[ 5] = (T)(-plane.Normal.Y * light.Y + d);
1885  M[ 6] = (T)(-plane.Normal.Y * light.Z);
1886  M[ 7] = (T)(-plane.Normal.Y * point);
1887 
1888  M[ 8] = (T)(-plane.Normal.Z * light.X);
1889  M[ 9] = (T)(-plane.Normal.Z * light.Y);
1890  M[10] = (T)(-plane.Normal.Z * light.Z + d);
1891  M[11] = (T)(-plane.Normal.Z * point);
1892 
1893  M[12] = (T)(-plane.D * light.X);
1894  M[13] = (T)(-plane.D * light.Y);
1895  M[14] = (T)(-plane.D * light.Z);
1896  M[15] = (T)(-plane.D * point + d);
1897 #if defined ( USE_MATRIX_TEST )
1898  definitelyIdentityMatrix=false;
1899 #endif
1900  return *this;
1901  }
1902 
1903  // Builds a left-handed look-at matrix.
1904  template <class T>
1906  const vector3df& position,
1907  const vector3df& target,
1908  const vector3df& upVector)
1909  {
1910  vector3df zaxis = target - position;
1911  zaxis.normalize();
1912 
1913  vector3df xaxis = upVector.crossProduct(zaxis);
1914  xaxis.normalize();
1915 
1916  vector3df yaxis = zaxis.crossProduct(xaxis);
1917 
1918  M[0] = (T)xaxis.X;
1919  M[1] = (T)yaxis.X;
1920  M[2] = (T)zaxis.X;
1921  M[3] = 0;
1922 
1923  M[4] = (T)xaxis.Y;
1924  M[5] = (T)yaxis.Y;
1925  M[6] = (T)zaxis.Y;
1926  M[7] = 0;
1927 
1928  M[8] = (T)xaxis.Z;
1929  M[9] = (T)yaxis.Z;
1930  M[10] = (T)zaxis.Z;
1931  M[11] = 0;
1932 
1933  M[12] = (T)-xaxis.dotProduct(position);
1934  M[13] = (T)-yaxis.dotProduct(position);
1935  M[14] = (T)-zaxis.dotProduct(position);
1936  M[15] = 1;
1937 #if defined ( USE_MATRIX_TEST )
1938  definitelyIdentityMatrix=false;
1939 #endif
1940  return *this;
1941  }
1942 
1943 
1944  // Builds a right-handed look-at matrix.
1945  template <class T>
1947  const vector3df& position,
1948  const vector3df& target,
1949  const vector3df& upVector)
1950  {
1951  vector3df zaxis = position - target;
1952  zaxis.normalize();
1953 
1954  vector3df xaxis = upVector.crossProduct(zaxis);
1955  xaxis.normalize();
1956 
1957  vector3df yaxis = zaxis.crossProduct(xaxis);
1958 
1959  M[0] = (T)xaxis.X;
1960  M[1] = (T)yaxis.X;
1961  M[2] = (T)zaxis.X;
1962  M[3] = 0;
1963 
1964  M[4] = (T)xaxis.Y;
1965  M[5] = (T)yaxis.Y;
1966  M[6] = (T)zaxis.Y;
1967  M[7] = 0;
1968 
1969  M[8] = (T)xaxis.Z;
1970  M[9] = (T)yaxis.Z;
1971  M[10] = (T)zaxis.Z;
1972  M[11] = 0;
1973 
1974  M[12] = (T)-xaxis.dotProduct(position);
1975  M[13] = (T)-yaxis.dotProduct(position);
1976  M[14] = (T)-zaxis.dotProduct(position);
1977  M[15] = 1;
1978 #if defined ( USE_MATRIX_TEST )
1979  definitelyIdentityMatrix=false;
1980 #endif
1981  return *this;
1982  }
1983 
1984 
1985  // creates a new matrix as interpolated matrix from this and the passed one.
1986  template <class T>
1988  {
1989  CMatrix4<T> mat ( EM4CONST_NOTHING );
1990 
1991  for (u32 i=0; i < 16; i += 4)
1992  {
1993  mat.M[i+0] = (T)(M[i+0] + ( b.M[i+0] - M[i+0] ) * time);
1994  mat.M[i+1] = (T)(M[i+1] + ( b.M[i+1] - M[i+1] ) * time);
1995  mat.M[i+2] = (T)(M[i+2] + ( b.M[i+2] - M[i+2] ) * time);
1996  mat.M[i+3] = (T)(M[i+3] + ( b.M[i+3] - M[i+3] ) * time);
1997  }
1998  return mat;
1999  }
2000 
2001 
2002  // returns transposed matrix
2003  template <class T>
2005  {
2006  CMatrix4<T> t ( EM4CONST_NOTHING );
2007  getTransposed ( t );
2008  return t;
2009  }
2010 
2011 
2012  // returns transposed matrix
2013  template <class T>
2014  inline void CMatrix4<T>::getTransposed( CMatrix4<T>& o ) const
2015  {
2016  o[ 0] = M[ 0];
2017  o[ 1] = M[ 4];
2018  o[ 2] = M[ 8];
2019  o[ 3] = M[12];
2020 
2021  o[ 4] = M[ 1];
2022  o[ 5] = M[ 5];
2023  o[ 6] = M[ 9];
2024  o[ 7] = M[13];
2025 
2026  o[ 8] = M[ 2];
2027  o[ 9] = M[ 6];
2028  o[10] = M[10];
2029  o[11] = M[14];
2030 
2031  o[12] = M[ 3];
2032  o[13] = M[ 7];
2033  o[14] = M[11];
2034  o[15] = M[15];
2035 #if defined ( USE_MATRIX_TEST )
2036  o.definitelyIdentityMatrix=definitelyIdentityMatrix;
2037 #endif
2038  }
2039 
2040 
2041  // used to scale <-1,-1><1,1> to viewport
2042  template <class T>
2044  {
2045  const f32 scaleX = (viewport.getWidth() - 0.75f ) * 0.5f;
2046  const f32 scaleY = -(viewport.getHeight() - 0.75f ) * 0.5f;
2047 
2048  const f32 dx = -0.5f + ( (viewport.UpperLeftCorner.X + viewport.LowerRightCorner.X ) * 0.5f );
2049  const f32 dy = -0.5f + ( (viewport.UpperLeftCorner.Y + viewport.LowerRightCorner.Y ) * 0.5f );
2050 
2051  makeIdentity();
2052  M[12] = (T)dx;
2053  M[13] = (T)dy;
2054  return setScale(core::vector3d<T>((T)scaleX, (T)scaleY, (T)zScale));
2055  }
2056 
2058 
2063  template <class T>
2065  {
2066  // unit vectors
2067  core::vector3df f(from);
2068  core::vector3df t(to);
2069  f.normalize();
2070  t.normalize();
2071 
2072  // axis multiplication by sin
2073  core::vector3df vs(t.crossProduct(f));
2074 
2075  // axis of rotation
2076  core::vector3df v(vs);
2077  v.normalize();
2078 
2079  // cosinus angle
2080  T ca = f.dotProduct(t);
2081 
2082  core::vector3df vt(v * (1 - ca));
2083 
2084  M[0] = vt.X * v.X + ca;
2085  M[5] = vt.Y * v.Y + ca;
2086  M[10] = vt.Z * v.Z + ca;
2087 
2088  vt.X *= v.Y;
2089  vt.Z *= v.X;
2090  vt.Y *= v.Z;
2091 
2092  M[1] = vt.X - vs.Z;
2093  M[2] = vt.Z + vs.Y;
2094  M[3] = 0;
2095 
2096  M[4] = vt.X + vs.Z;
2097  M[6] = vt.Y - vs.X;
2098  M[7] = 0;
2099 
2100  M[8] = vt.Z - vs.Y;
2101  M[9] = vt.Y + vs.X;
2102  M[11] = 0;
2103 
2104  M[12] = 0;
2105  M[13] = 0;
2106  M[14] = 0;
2107  M[15] = 1;
2108 
2109  return *this;
2110  }
2111 
2113 
2119  template <class T>
2121  const core::vector3df& camPos,
2122  const core::vector3df& center,
2123  const core::vector3df& translation,
2124  const core::vector3df& axis,
2125  const core::vector3df& from)
2126  {
2127  // axis of rotation
2128  core::vector3df up = axis;
2129  up.normalize();
2130  const core::vector3df forward = (camPos - center).normalize();
2131  const core::vector3df right = up.crossProduct(forward).normalize();
2132 
2133  // correct look vector
2134  const core::vector3df look = right.crossProduct(up);
2135 
2136  // rotate from to
2137  // axis multiplication by sin
2138  const core::vector3df vs = look.crossProduct(from);
2139 
2140  // cosinus angle
2141  const f32 ca = from.dotProduct(look);
2142 
2143  core::vector3df vt(up * (1.f - ca));
2144 
2145  M[0] = static_cast<T>(vt.X * up.X + ca);
2146  M[5] = static_cast<T>(vt.Y * up.Y + ca);
2147  M[10] = static_cast<T>(vt.Z * up.Z + ca);
2148 
2149  vt.X *= up.Y;
2150  vt.Z *= up.X;
2151  vt.Y *= up.Z;
2152 
2153  M[1] = static_cast<T>(vt.X - vs.Z);
2154  M[2] = static_cast<T>(vt.Z + vs.Y);
2155  M[3] = 0;
2156 
2157  M[4] = static_cast<T>(vt.X + vs.Z);
2158  M[6] = static_cast<T>(vt.Y - vs.X);
2159  M[7] = 0;
2160 
2161  M[8] = static_cast<T>(vt.Z - vs.Y);
2162  M[9] = static_cast<T>(vt.Y + vs.X);
2163  M[11] = 0;
2164 
2165  setRotationCenter(center, translation);
2166  }
2167 
2168 
2170  template <class T>
2171  inline void CMatrix4<T>::setRotationCenter(const core::vector3df& center, const core::vector3df& translation)
2172  {
2173  M[12] = -M[0]*center.X - M[4]*center.Y - M[8]*center.Z + (center.X - translation.X );
2174  M[13] = -M[1]*center.X - M[5]*center.Y - M[9]*center.Z + (center.Y - translation.Y );
2175  M[14] = -M[2]*center.X - M[6]*center.Y - M[10]*center.Z + (center.Z - translation.Z );
2176  M[15] = (T) 1.0;
2177 #if defined ( USE_MATRIX_TEST )
2178  definitelyIdentityMatrix=false;
2179 #endif
2180  }
2181 
2194  template <class T>
2196  const core::vector2df &rotatecenter,
2197  const core::vector2df &translate,
2198  const core::vector2df &scale)
2199  {
2200  const f32 c = cosf(rotateRad);
2201  const f32 s = sinf(rotateRad);
2202 
2203  M[0] = (T)(c * scale.X);
2204  M[1] = (T)(s * scale.Y);
2205  M[2] = 0;
2206  M[3] = 0;
2207 
2208  M[4] = (T)(-s * scale.X);
2209  M[5] = (T)(c * scale.Y);
2210  M[6] = 0;
2211  M[7] = 0;
2212 
2213  M[8] = (T)(c * scale.X * rotatecenter.X + -s * rotatecenter.Y + translate.X);
2214  M[9] = (T)(s * scale.Y * rotatecenter.X + c * rotatecenter.Y + translate.Y);
2215  M[10] = 1;
2216  M[11] = 0;
2217 
2218  M[12] = 0;
2219  M[13] = 0;
2220  M[14] = 0;
2221  M[15] = 1;
2222 #if defined ( USE_MATRIX_TEST )
2223  definitelyIdentityMatrix=false;
2224 #endif
2225  return *this;
2226  }
2227 
2228 
2229  // rotate about z axis, center ( 0.5, 0.5 )
2230  template <class T>
2232  {
2233  const f32 c = cosf(rotateRad);
2234  const f32 s = sinf(rotateRad);
2235  M[0] = (T)c;
2236  M[1] = (T)s;
2237 
2238  M[4] = (T)-s;
2239  M[5] = (T)c;
2240 
2241  M[8] = (T)(0.5f * ( s - c) + 0.5f);
2242  M[9] = (T)(-0.5f * ( s + c) + 0.5f);
2243 
2244 #if defined ( USE_MATRIX_TEST )
2245  definitelyIdentityMatrix = definitelyIdentityMatrix && (rotateRad==0.0f);
2246 #endif
2247  return *this;
2248  }
2249 
2250 
2251  template <class T>
2253  {
2254  M[8] = (T)x;
2255  M[9] = (T)y;
2256 
2257 #if defined ( USE_MATRIX_TEST )
2258  definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f);
2259 #endif
2260  return *this;
2261  }
2262 
2263  template <class T>
2264  inline void CMatrix4<T>::getTextureTranslate(f32& x, f32& y) const
2265  {
2266  x = (f32)M[8];
2267  y = (f32)M[9];
2268  }
2269 
2270  template <class T>
2272  {
2273  M[2] = (T)x;
2274  M[6] = (T)y;
2275 
2276 #if defined ( USE_MATRIX_TEST )
2277  definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f);
2278 #endif
2279  return *this;
2280  }
2281 
2282  template <class T>
2284  {
2285  M[0] = (T)sx;
2286  M[5] = (T)sy;
2287 #if defined ( USE_MATRIX_TEST )
2288  definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
2289 #endif
2290  return *this;
2291  }
2292 
2293  template <class T>
2294  inline void CMatrix4<T>::getTextureScale ( f32& sx, f32& sy ) const
2295  {
2296  sx = (f32)M[0];
2297  sy = (f32)M[5];
2298  }
2299 
2300  template <class T>
2302  {
2303  M[0] = (T)sx;
2304  M[5] = (T)sy;
2305  M[8] = (T)(0.5f - 0.5f * sx);
2306  M[9] = (T)(0.5f - 0.5f * sy);
2307 
2308 #if defined ( USE_MATRIX_TEST )
2309  definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
2310 #endif
2311  return *this;
2312  }
2313 
2314 
2315  // sets all matrix data members at once
2316  template <class T>
2317  inline CMatrix4<T>& CMatrix4<T>::setM(const T* data)
2318  {
2319  memcpy(M,data, 16*sizeof(T));
2320 
2321 #if defined ( USE_MATRIX_TEST )
2322  definitelyIdentityMatrix=false;
2323 #endif
2324  return *this;
2325  }
2326 
2327 
2328  // sets if the matrix is definitely identity matrix
2329  template <class T>
2330  inline void CMatrix4<T>::setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix)
2331  {
2332 #if defined ( USE_MATRIX_TEST )
2333  definitelyIdentityMatrix = isDefinitelyIdentityMatrix;
2334 #else
2335  (void)isDefinitelyIdentityMatrix; // prevent compiler warning
2336 #endif
2337  }
2338 
2339 
2340  // gets if the matrix is definitely identity matrix
2341  template <class T>
2343  {
2344 #if defined ( USE_MATRIX_TEST )
2345  return definitelyIdentityMatrix;
2346 #else
2347  return false;
2348 #endif
2349  }
2350 
2351 
2353  template <class T>
2354  inline bool CMatrix4<T>::equals(const core::CMatrix4<T>& other, const T tolerance) const
2355  {
2356 #if defined ( USE_MATRIX_TEST )
2357  if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
2358  return true;
2359 #endif
2360  for (s32 i = 0; i < 16; ++i)
2361  if (!core::equals(M[i],other.M[i], tolerance))
2362  return false;
2363 
2364  return true;
2365  }
2366 
2367 
2368  // Multiply by scalar.
2369  template <class T>
2370  inline CMatrix4<T> operator*(const T scalar, const CMatrix4<T>& mat)
2371  {
2372  return mat*scalar;
2373  }
2374 
2375 
2378 
2380  IRRLICHT_API extern const matrix4 IdentityMatrix;
2381 
2382 } // end namespace core
2383 } // end namespace irr
2384 
2385 #endif
2386 
CMatrix4< T > & buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true)
Builds a right-handed perspective projection matrix.
Definition: matrix4.h:1781
bool equals(const core::CMatrix4< T > &other, const T tolerance=(T) ROUNDING_ERROR_f64) const
Compare two matrices using the equal method.
Definition: matrix4.h:2354
const f64 RADTODEG64
64bit constant for converting from radians to degrees
Definition: irrMath.h:84
vector3d< T > crossProduct(const vector3d< T > &p) const
Calculates the cross product with another vector.
Definition: vector3d.h:147
T D
Distance from origin.
Definition: plane3d.h:231
CMatrix4< T > & buildCameraLookAtMatrixLH(const vector3df &position, const vector3df &target, const vector3df &upVector)
Builds a left-handed look-at matrix.
Definition: matrix4.h:1905
vector3d< T > MaxEdge
The far edge.
Definition: aabbox3d.h:357
T Y
Y coordinate of the vector.
Definition: vector3d.h:413
bool iszero(const f64 a, const f64 tolerance=ROUNDING_ERROR_f64)
returns if a equals zero, taking rounding errors into account
Definition: irrMath.h:307
vector3d< T > getMemberPoint() const
Gets a member point of the plane.
Definition: plane3d.h:155
#define _IRR_DEPRECATED_
Defines a deprecated macro which generates a warning at compile time.
Definition: irrTypes.h:202
IRRLICHT_API const matrix4 IdentityMatrix
global const identity matrix
void setDefinitelyIdentityMatrix(bool isDefinitelyIdentityMatrix)
Sets if the matrix is definitely identity matrix.
Definition: matrix4.h:2330
void multiplyWith1x4Matrix(T *matrix) const
Multiplies this matrix by a 1x4 matrix.
Definition: matrix4.h:1333
CMatrix4< T > & setTextureTranslateTransposed(f32 x, f32 y)
Set texture transformation translation, using a transposed representation.
Definition: matrix4.h:2271
u32 IR(f32 x)
Definition: irrMath.h:390
CMatrix4< T > getTransposed() const
Gets transposed matrix.
Definition: matrix4.h:2004
float f32
32 bit floating point variable.
Definition: irrTypes.h:108
CMatrix4< T > & setTextureTranslate(f32 x, f32 y)
Set texture transformation translation.
Definition: matrix4.h:2252
CMatrix4< T > & setScale(const T scale)
Set Scale.
Definition: matrix4.h:216
void transformPlane(core::plane3d< f32 > &plane) const
Transforms a plane by this matrix.
Definition: matrix4.h:1243
vector3d< T > Normal
Normal vector of the plane.
Definition: plane3d.h:228
core::vector3d< T > getScale() const
Get Scale.
Definition: matrix4.h:837
position2d< T > UpperLeftCorner
Upper left corner.
Definition: rect.h:270
const T & operator[](u32 index) const
Simple operator for linearly accessing every element of the matrix.
Definition: matrix4.h:103
CMatrix4< T > & buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero=true)
Builds a right-handed perspective projection matrix based on a field of view.
Definition: matrix4.h:1557
CMatrix4< T > & operator+=(const CMatrix4< T > &other)
Add another matrix.
Definition: matrix4.h:544
bool isIdentity() const
Returns true if the matrix is the identity matrix.
Definition: matrix4.h:1055
T Y
Y coordinate of vector.
Definition: vector2d.h:385
void setRotationCenter(const core::vector3df &center, const core::vector3df &translate)
Builds a combined matrix which translates to a center before rotation and translates from origin afte...
Definition: matrix4.h:2171
#define IRRLICHT_API
Set FPU settings.
T X
X coordinate of the vector.
Definition: vector3d.h:410
CMatrix4< T > & setRotationAxisRadians(const T &angle, const vector3d< T > &axis)
Make a rotation matrix from angle and axis, assuming left handed rotation.
Definition: matrix4.h:1003
CMatrix4< T > & buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true)
Builds a left-handed orthogonal projection matrix.
Definition: matrix4.h:1689
CMatrix4< T > & setInverseRotationRadians(const vector3d< T > &rotation)
Make an inverted rotation matrix from Euler angles.
Definition: matrix4.h:972
Everything in the Irrlicht Engine can be found in this namespace.
Definition: aabbox3d.h:12
3d vector template class with lots of operators and methods.
Definition: vector3d.h:22
CMatrix4(const T &r0c0, const T &r0c1, const T &r0c2, const T &r0c3, const T &r1c0, const T &r1c1, const T &r1c2, const T &r1c3, const T &r2c0, const T &r2c1, const T &r2c2, const T &r2c3, const T &r3c0, const T &r3c1, const T &r3c2, const T &r3c3)
Constructor with value initialization.
Definition: matrix4.h:65
CMatrix4< T > & setTextureRotationCenter(f32 radAngle)
Set texture transformation rotation.
Definition: matrix4.h:2231
CMatrix4< T > & buildNDCToDCMatrix(const core::rect< s32 > &area, f32 zScale)
Builds a matrix which transforms a normalized Device Coordinate to Device Coordinates.
Definition: matrix4.h:2043
double f64
64 bit floating point variable.
Definition: irrTypes.h:112
void rotateVect(vector3df &vect) const
Rotate a vector by the rotation part of this matrix.
Definition: matrix4.h:1156
bool operator!=(const CMatrix4< T > &other) const
Returns true if other matrix is not equal to this matrix.
Definition: matrix4.h:1549
position2d< T > LowerRightCorner
Lower right corner.
Definition: rect.h:272
CMatrix4< T > & buildTextureTransform(f32 rotateRad, const core::vector2df &rotatecenter, const core::vector2df &translate, const core::vector2df &scale)
Set to a texture transformation matrix with the given parameters.
Definition: matrix4.h:2195
CMatrix4< T > operator *(const T scalar, const CMatrix4< T > &mat)
Definition: matrix4.h:2370
void transformBox(core::aabbox3d< f32 > &box) const
Transforms a axis aligned bounding box.
Definition: matrix4.h:1268
CMatrix4< T > & setbyproduct_nocheck(const CMatrix4< T > &other_a, const CMatrix4< T > &other_b)
Set this matrix to the product of two matrices.
Definition: matrix4.h:695
void inverseTranslateVect(vector3df &vect) const
Translate a vector by the inverse of the translation part of this matrix.
Definition: matrix4.h:1355
CMatrix4< T > & setInverseRotationDegrees(const vector3d< T > &rotation)
Make an inverted rotation matrix from Euler angles.
Definition: matrix4.h:861
bool equals(const T a, const T b, const T tolerance=roundingError< T >())
returns if a equals b, taking possible rounding errors into account
Definition: irrMath.h:246
CMatrix4< T > & setScale(const vector3d< T > &scale)
Set Scale.
Definition: matrix4.h:817
CMatrix4< T > & setbyproduct(const CMatrix4< T > &other_a, const CMatrix4< T > &other_b)
set this matrix to the product of two matrices
Definition: matrix4.h:730
vector3d< T > getTranslation() const
Gets the current translation.
Definition: matrix4.h:786
void getTextureTranslate(f32 &x, f32 &y) const
Get texture transformation translation.
Definition: matrix4.h:2264
const f64 ROUNDING_ERROR_f64
Definition: irrMath.h:51
signed int s32
32 bit signed variable.
Definition: irrTypes.h:70
CMatrix4< T > & buildCameraLookAtMatrixRH(const vector3df &position, const vector3df &target, const vector3df &upVector)
Builds a right-handed look-at matrix.
Definition: matrix4.h:1946
REALINLINE f32 reciprocal(const f32 f)
Definition: irrMath.h:570
void setPlane(const vector3d< T > &point, const vector3d< T > &nvector)
Definition: plane3d.h:58
CMatrix4< T > & setTextureScale(f32 sx, f32 sy)
Set texture transformation scale.
Definition: matrix4.h:2283
CMatrix4< T > & buildRotateFromTo(const core::vector3df &from, const core::vector3df &to)
Builds a matrix that rotates from one vector to another.
Definition: matrix4.h:2064
#define F32_VALUE_1
Definition: irrMath.h:381
CMatrix4< T > & setRotationDegrees(const vector3d< T > &rotation)
Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
Definition: matrix4.h:855
bool getDefinitelyIdentityMatrix() const
Gets if the matrix is definitely identity matrix.
Definition: matrix4.h:2342
unsigned int u32
32 bit unsigned variable.
Definition: irrTypes.h:62
T getHeight() const
Get height of rectangle.
Definition: rect.h:195
CMatrix4< T > operator *(const CMatrix4< T > &other) const
Multiply by another matrix.
Definition: matrix4.h:747
bool isOrthogonal() const
Returns true if the matrix is orthogonal.
Definition: matrix4.h:1093
CMatrix4< T > & buildShadowMatrix(const core::vector3df &light, core::plane3df plane, f32 point=1.0f)
Builds a matrix that flattens geometry into a plane.
Definition: matrix4.h:1873
CMatrix4(eConstructor constructor=EM4CONST_IDENTITY)
Default constructor.
Definition: matrix4.h:459
void transformVect(vector3df &vect) const
Transforms the vector by this matrix.
Definition: matrix4.h:1192
#define _IRR_DEBUG_BREAK_IF(_CONDITION_)
define a break macro for debugging.
Definition: irrTypes.h:185
CMatrix4< T > & operator=(const CMatrix4< T > &other)
Sets this matrix equal to the other matrix.
Definition: matrix4.h:1508
CMatrix4< T > & setInverseTranslation(const vector3d< T > &translation)
Set the inverse translation of the current matrix. Will erase any previous values.
Definition: matrix4.h:805
T getWidth() const
Get width of rectangle.
Definition: rect.h:189
const f32 DEGTORAD
32bit Constant for converting from degrees to radians
Definition: irrMath.h:75
const T * pointer() const
Returns pointer to internal array.
Definition: matrix4.h:112
void inverseRotateVect(vector3df &vect) const
Rotate a vector by the inverse of the rotation part of this matrix.
Definition: matrix4.h:1183
CMatrix4< T > & buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero=true)
Builds a left-handed perspective projection matrix based on a field of view.
Definition: matrix4.h:1605
vector3d< T > & normalize()
Normalizes the vector.
Definition: vector3d.h:168
const T & operator()(const s32 row, const s32 col) const
Simple operator for directly accessing every element of the matrix.
Definition: matrix4.h:91
CMatrix4< T > & operator *=(const CMatrix4< T > &other)
Multiply by another matrix.
Definition: matrix4.h:668
vector3d< T > MinEdge
The near edge.
Definition: aabbox3d.h:354
CMatrix4< T > & buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true)
Builds a right-handed orthogonal projection matrix.
Definition: matrix4.h:1735
4x4 matrix. Mostly used as transformation matrix for 3d calculations.
Definition: matrix4.h:45
T dotProduct(const vector3d< T > &other) const
Get the dot product with another vector.
Definition: vector3d.h:125
void transformVec4(T *out, const T *in) const
An alternate transform vector method, reading from and writing to an array of 4 floats.
Definition: matrix4.h:1232
CMatrix4< T > & setTranslation(const vector3d< T > &translation)
Set the translation of the current matrix. Will erase any previous values.
Definition: matrix4.h:793
void transformVec3(T *out, const T *in) const
An alternate transform vector method, reading from and writing to an array of 3 floats.
Definition: matrix4.h:1224
bool makeInverse()
Calculates inverse of matrix. Slow.
Definition: matrix4.h:1489
CMatrix4< T > & setTextureScaleCenter(f32 sx, f32 sy)
Set texture transformation scale, and recenter at (0.5,0.5)
Definition: matrix4.h:2301
CMatrix4< T > & buildProjectionMatrixPerspectiveFovInfinityLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon=0)
Builds a left-handed perspective projection matrix based on a field of view, with far plane at infini...
Definition: matrix4.h:1653
void buildAxisAlignedBillboard(const core::vector3df &camPos, const core::vector3df &center, const core::vector3df &translation, const core::vector3df &axis, const core::vector3df &from)
Builds a matrix which rotates a source vector to a look vector over an arbitrary axis.
Definition: matrix4.h:2120
T & operator[](u32 index)
Simple operator for linearly accessing every element of the matrix.
Definition: matrix4.h:94
T Z
Z coordinate of the vector.
Definition: vector3d.h:416
void translateVect(vector3df &vect) const
Translate a vector by the translation part of this matrix.
Definition: matrix4.h:1363
CMatrix4< T > operator+(const CMatrix4< T > &other) const
Add another matrix.
Definition: matrix4.h:518
#define FLT_MIN
Definition: irrMath.h:35
CMatrix4< T > operator-(const CMatrix4< T > &other) const
Subtract another matrix.
Definition: matrix4.h:568
bool isIdentity_integer_base() const
Returns true if the matrix is the identity matrix.
Definition: matrix4.h:1122
bool getInverse(CMatrix4< T > &out) const
Gets the inverse matrix of this one.
Definition: matrix4.h:1372
CMatrix4< f32 > matrix4
Typedef for f32 matrix.
Definition: matrix4.h:2377
eConstructor
Constructor Flags.
Definition: matrix4.h:50
void repair()
Repairs the box.
Definition: aabbox3d.h:180
void getTextureScale(f32 &sx, f32 &sy) const
Get texture transformation scale.
Definition: matrix4.h:2294
CMatrix4< T > & setRotationRadians(const vector3d< T > &rotation)
Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
Definition: matrix4.h:867
CMatrix4< T > & setM(const T *data)
Sets all matrix data members at once.
Definition: matrix4.h:2317
CMatrix4< T > interpolate(const core::CMatrix4< T > &b, f32 time) const
Creates a new matrix as interpolated matrix from two other ones.
Definition: matrix4.h:1987
CMatrix4< T > & buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true)
Builds a left-handed perspective projection matrix.
Definition: matrix4.h:1827
core::vector3d< T > getRotationDegrees() const
Returns the rotation, as set by setRotation().
Definition: matrix4.h:964
CMatrix4< T > & makeIdentity()
Set matrix to identity.
Definition: matrix4.h:1039
T & operator()(const s32 row, const s32 col)
Simple operator for directly accessing every element of the matrix.
Definition: matrix4.h:82
bool operator==(const CMatrix4< T > &other) const
Returns true if other matrix is equal to this matrix.
Definition: matrix4.h:1534
const T clamp(const T &value, const T &low, const T &high)
clamps a value between low and high
Definition: irrMath.h:167
CMatrix4< T > & operator-=(const CMatrix4< T > &other)
Subtract another matrix.
Definition: matrix4.h:594
void transformBoxEx(core::aabbox3d< f32 > &box) const
Transforms a axis aligned bounding box.
Definition: matrix4.h:1282
T X
X coordinate of vector.
Definition: vector2d.h:382
bool getInversePrimitive(CMatrix4< T > &out) const
Inverts a primitive matrix which only contains a translation and a rotation.
Definition: matrix4.h:1458