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

The Irrlicht Engine
The Irrlicht Engine Documentation © 2003-2010 by Nikolaus Gebhardt. Generated on Fri Mar 21 2014 04:40:17 by Doxygen (1.8.1.2)