Imported more code from the old engine.
[peakengine.git] / engine / include / support / matrix4.h
bloba9437599df279b0d8ce86ff49fbe9d37086b9ea2
1 // Copyright (C) 2002-2007 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
5 #ifndef __IRR_MATRIX_H_INCLUDED__
6 #define __IRR_MATRIX_H_INCLUDED__
8 #include "irrTypes.h"
9 #include "vector3d.h"
10 #include "vector2d.h"
11 #include "plane3d.h"
12 #include "aabbox3d.h"
13 #include "rect.h"
14 #include <string.h>
16 namespace irr
18 namespace core
21 //! 4x4 matrix. Mostly used as transformation matrix for 3d calculations.
22 /* Matrix4 is mainly used by the Irrlicht engine for doing transformations.
23 The matrix is a D3D style matrix, row major with translations in the 4th row.
25 template <class T>
26 class CMatrix4
28 public:
30 //! Constructor Flags
31 enum eConstructor
33 EM4CONST_NOTHING = 0,
34 EM4CONST_COPY,
35 EM4CONST_IDENTITY,
36 EM4CONST_TRANSPOSED,
37 EM4CONST_INVERSE,
38 EM4CONST_INVERSE_TRANSPOSED
41 CMatrix4( eConstructor constructor = EM4CONST_IDENTITY );
42 CMatrix4( const CMatrix4<T>& other,eConstructor constructor = EM4CONST_COPY);
44 //! Simple operator for directly accessing every element of the matrix.
45 T& operator()(const s32 row, const s32 col) { definitelyIdentityMatrix=false; return M[ row * 4 + col ]; }
47 //! Simple operator for directly accessing every element of the matrix.
48 const T& operator()(const s32 row, const s32 col) const { return M[row * 4 + col]; }
50 //! Simple operator for linearly accessing every element of the matrix.
51 T& operator[](u32 index) { definitelyIdentityMatrix=false; return M[index]; }
53 //! Simple operator for linearly accessing every element of the matrix.
54 const T& operator[](u32 index) const { return M[index]; }
56 //! Sets this matrix equal to the other matrix.
57 inline CMatrix4<T>& operator=(const CMatrix4<T> &other);
59 //! Sets all elements of this matrix to the value.
60 inline CMatrix4<T>& operator=(const T& scalar);
62 //! Returns pointer to internal array
63 const T* pointer() const { return M; }
64 T* pointer() { definitelyIdentityMatrix=false; return M; }
66 //! Returns true if other matrix is equal to this matrix.
67 bool operator==(const CMatrix4<T> &other) const;
69 //! Returns true if other matrix is not equal to this matrix.
70 bool operator!=(const CMatrix4<T> &other) const;
72 //! Add another matrix.
73 CMatrix4<T> operator+(const CMatrix4<T>& other) const;
75 //! Add another matrix.
76 CMatrix4<T>& operator+=(const CMatrix4<T>& other);
78 //! Subtract another matrix.
79 CMatrix4<T> operator-(const CMatrix4<T>& other) const;
81 //! Subtract another matrix.
82 CMatrix4<T>& operator-=(const CMatrix4<T>& other);
84 //! set this matrix to the product of two matrices
85 inline void setbyproduct(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b );
87 //! set this matrix to the product of two matrices, no logical optimation
88 //! use it if you know you never have a identity matrix
89 void setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b );
91 //! Multiply by another matrix.
92 CMatrix4<T> operator*(const CMatrix4<T>& other) const;
94 //! Multiply by another matrix.
95 CMatrix4<T>& operator*=(const CMatrix4<T>& other);
97 //! Multiply by scalar.
98 CMatrix4<T> operator*(const T& scalar) const;
100 //! Multiply by scalar.
101 CMatrix4<T>& operator*=(const T& scalar);
103 //! Set matrix to identity.
104 inline void makeIdentity();
106 //! Returns true if the matrix is the identity matrix
107 inline bool isIdentity() const;
109 //! Returns true if the matrix is the identity matrix
110 bool isIdentity_integer_base () const;
112 //! Set the translation of the current matrix. Will erase any previous values.
113 void setTranslation( const vector3d<T>& translation );
115 //! Gets the current translation
116 vector3d<T> getTranslation() const;
118 //! Set the inverse translation of the current matrix. Will erase any previous values.
119 void setInverseTranslation( const vector3d<T>& translation );
121 //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
122 inline void setRotationRadians( const vector3d<T>& rotation );
124 //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
125 void setRotationDegrees( const vector3d<T>& rotation );
127 //! Returns the rotation, as set by setRotation(). This code was orginally written by by Chev.
128 core::vector3d<T> getRotationDegrees() const;
130 //! Make an inverted rotation matrix from Euler angles. The 4th row and column are unmodified.
131 inline void setInverseRotationRadians( const vector3d<T>& rotation );
133 //! Make an inverted rotation matrix from Euler angles. The 4th row and column are unmodified.
134 void setInverseRotationDegrees( const vector3d<T>& rotation );
136 //! Set Scale
137 void setScale( const vector3d<T>& scale );
139 //! Get Scale
140 core::vector3d<T> getScale() const;
142 //! Translate a vector by the inverse of the translation part of this matrix.
143 void inverseTranslateVect( vector3df& vect ) const;
145 //! Rotate a vector by the inverse of the rotation part of this matrix.
146 void inverseRotateVect( vector3df& vect ) const;
148 //! Rotate a vector by the rotation part of this matrix.
149 void rotateVect( vector3df& vect ) const;
151 //! An alternate transform vector method, writing into a second vector
152 void rotateVect(vector3df& out,const core::vector3df& in) const;
154 //! An alternate transform vector method, writing into an array of 3 floats
155 void rotateVect(T *out,const core::vector3df &in) const;
157 //! Transforms the vector by this matrix
158 void transformVect( vector3df& vect) const;
160 //! Transforms input vector by this matrix and stores result in output vector
161 void transformVect( vector3df& out, const vector3df& in ) const;
163 //! An alternate transform vector method, writing into an array of 4 floats
164 void transformVect(T *out,const core::vector3df &in) const;
166 //! Translate a vector by the translation part of this matrix.
167 void translateVect( vector3df& vect ) const;
169 //! Transforms a plane by this matrix
170 void transformPlane( core::plane3d<f32> &plane) const;
172 //! Transforms a plane by this matrix ( some problems to solve..)
173 void transformPlane_new( core::plane3d<f32> &plane) const;
175 //! Transforms a plane by this matrix
176 void transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const;
178 //! Transforms a axis aligned bounding box
179 /** The result box of this operation may not be very accurate. For
180 accurate results, use transformBoxEx() */
181 void transformBox(core::aabbox3d<f32>& box) const;
183 //! Transforms a axis aligned bounding box more accurately than transformBox()
184 /** The result box of this operation should by quite accurate, but this operation
185 is slower than transformBox(). */
186 void transformBoxEx(core::aabbox3d<f32>& box) const;
188 //! Multiplies this matrix by a 1x4 matrix
189 void multiplyWith1x4Matrix(T* matrix) const;
191 //! Calculates inverse of matrix. Slow.
192 //! \return Returns false if there is no inverse matrix.
193 bool makeInverse();
196 //! Inverts a primitive matrix which only contains a translation and a rotation
197 //! \param out: where result matrix is written to.
198 bool getInversePrimitive ( CMatrix4<T>& out ) const;
200 //! returns the inversed matrix of this one
201 //! \param out: where result matrix is written to.
202 //! \return Returns false if there is no inverse matrix.
203 bool getInverse(CMatrix4<T>& out) const;
205 //! Builds a right-handed perspective projection matrix based on a field of view
206 void buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar);
208 //! Builds a left-handed perspective projection matrix based on a field of view
209 void buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar);
211 //! Builds a right-handed perspective projection matrix.
212 void buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar);
214 //! Builds a left-handed perspective projection matrix.
215 void buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar);
217 //! Builds a left-handed orthogonal projection matrix.
218 void buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar);
220 //! Builds a right-handed orthogonal projection matrix.
221 void buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar);
223 //! Builds a left-handed look-at matrix.
224 void buildCameraLookAtMatrixLH(const vector3df& position, const vector3df& target, const vector3df& upVector);
226 //! Builds a right-handed look-at matrix.
227 void buildCameraLookAtMatrixRH(const vector3df& position, const vector3df& target, const vector3df& upVector);
229 //! Builds a matrix that flattens geometry into a plane.
230 //! \param light: light source
231 //! \param plane: plane into which the geometry if flattened into
232 //! \param point: value between 0 and 1, describing the light source.
233 //! If this is 1, it is a point light, if it is 0, it is a directional light.
234 void buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point=1.0f);
236 //! Builds a matrix which transforms a normalized Device Coordinate to Device Coordinates.
237 /** Used to scale <-1,-1><1,1> to viewport, for example from von <-1,-1> <1,1> to the viewport <0,0><0,640> */
238 void buildNDCToDCMatrix( const core::rect<s32>& area, f32 zScale);
240 //! creates a new matrix as interpolated matrix from two other ones.
241 //! \param b: other matrix to interpolate with
242 //! \param time: Must be a value between 0 and 1.
243 CMatrix4<T> interpolate(const core::CMatrix4<T>& b, f32 time) const;
245 //! returns transposed matrix
246 CMatrix4<T> getTransposed() const;
248 //! returns transposed matrix to a plain 4x4 float matrix
249 inline void getTransposed( CMatrix4<T>& dest ) const;
252 construct 2D Texture transformations
253 rotate about center, scale, and transform.
255 void setTextureScale( f32 sx, f32 sy );
257 void setTextureRotationCenter( f32 radAngle );
258 void setTextureScaleCenter( f32 sx, f32 sy );
260 void setTextureTranslate( f32 x, f32 y );
262 void buildTextureTransform( f32 rotateRad,
263 const core::vector2df &rotatecenter,
264 const core::vector2df &translate,
265 const core::vector2df &scale);
267 //! sets all matrix data members at once
268 void setM(const T* data);
270 //! sets if the matrix is definitely identity matrix
271 void setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix);
273 //! gets if the matrix is definitely identity matrix
274 bool getDefinitelyIdentityMatrix() const;
276 private:
277 //! Matrix data, stored in row-major order
278 T M[16];
279 mutable bool definitelyIdentityMatrix;
282 template <class T>
283 inline CMatrix4<T>::CMatrix4( eConstructor constructor ) : definitelyIdentityMatrix(false)
285 switch ( constructor )
287 case EM4CONST_NOTHING:
288 case EM4CONST_COPY:
289 break;
290 case EM4CONST_IDENTITY:
291 case EM4CONST_INVERSE:
292 default:
293 makeIdentity();
294 break;
298 template <class T>
299 inline CMatrix4<T>::CMatrix4( const CMatrix4<T>& other, eConstructor constructor) : definitelyIdentityMatrix(false)
301 switch ( constructor )
303 case EM4CONST_IDENTITY:
304 makeIdentity();
305 break;
306 case EM4CONST_NOTHING:
307 break;
308 case EM4CONST_COPY:
309 *this = other;
310 break;
311 case EM4CONST_TRANSPOSED:
312 other.getTransposed(*this);
313 break;
314 case EM4CONST_INVERSE:
315 if (!other.getInverse(*this))
316 memset(M, 0, 16*sizeof(T));
317 break;
318 case EM4CONST_INVERSE_TRANSPOSED:
319 if (!other.getInverse(*this))
320 memset(M, 0, 16*sizeof(T));
321 else
322 *this=getTransposed();
323 break;
327 //! Add another matrix.
328 template <class T>
329 inline CMatrix4<T> CMatrix4<T>::operator+(const CMatrix4<T>& other) const
331 CMatrix4<T> temp ( EM4CONST_NOTHING );
333 temp[0] = M[0]+other[0];
334 temp[1] = M[1]+other[1];
335 temp[2] = M[2]+other[2];
336 temp[3] = M[3]+other[3];
337 temp[4] = M[4]+other[4];
338 temp[5] = M[5]+other[5];
339 temp[6] = M[6]+other[6];
340 temp[7] = M[7]+other[7];
341 temp[8] = M[8]+other[8];
342 temp[9] = M[9]+other[9];
343 temp[10] = M[10]+other[10];
344 temp[11] = M[11]+other[11];
345 temp[12] = M[12]+other[12];
346 temp[13] = M[13]+other[13];
347 temp[14] = M[14]+other[14];
348 temp[15] = M[15]+other[15];
350 return temp;
353 //! Add another matrix.
354 template <class T>
355 inline CMatrix4<T>& CMatrix4<T>::operator+=(const CMatrix4<T>& other)
357 M[0]+=other[0];
358 M[1]+=other[1];
359 M[2]+=other[2];
360 M[3]+=other[3];
361 M[4]+=other[4];
362 M[5]+=other[5];
363 M[6]+=other[6];
364 M[7]+=other[7];
365 M[8]+=other[8];
366 M[9]+=other[9];
367 M[10]+=other[10];
368 M[11]+=other[11];
369 M[12]+=other[12];
370 M[13]+=other[13];
371 M[14]+=other[14];
372 M[15]+=other[15];
374 return *this;
377 //! Subtract another matrix.
378 template <class T>
379 inline CMatrix4<T> CMatrix4<T>::operator-(const CMatrix4<T>& other) const
381 CMatrix4<T> temp ( EM4CONST_NOTHING );
383 temp[0] = M[0]-other[0];
384 temp[1] = M[1]-other[1];
385 temp[2] = M[2]-other[2];
386 temp[3] = M[3]-other[3];
387 temp[4] = M[4]-other[4];
388 temp[5] = M[5]-other[5];
389 temp[6] = M[6]-other[6];
390 temp[7] = M[7]-other[7];
391 temp[8] = M[8]-other[8];
392 temp[9] = M[9]-other[9];
393 temp[10] = M[10]-other[10];
394 temp[11] = M[11]-other[11];
395 temp[12] = M[12]-other[12];
396 temp[13] = M[13]-other[13];
397 temp[14] = M[14]-other[14];
398 temp[15] = M[15]-other[15];
400 return temp;
403 //! Subtract another matrix.
404 template <class T>
405 inline CMatrix4<T>& CMatrix4<T>::operator-=(const CMatrix4<T>& other)
407 M[0]-=other[0];
408 M[1]-=other[1];
409 M[2]-=other[2];
410 M[3]-=other[3];
411 M[4]-=other[4];
412 M[5]-=other[5];
413 M[6]-=other[6];
414 M[7]-=other[7];
415 M[8]-=other[8];
416 M[9]-=other[9];
417 M[10]-=other[10];
418 M[11]-=other[11];
419 M[12]-=other[12];
420 M[13]-=other[13];
421 M[14]-=other[14];
422 M[15]-=other[15];
424 return *this;
427 //! Multiply by scalar.
428 template <class T>
429 inline CMatrix4<T> CMatrix4<T>::operator*(const T& scalar) const
431 CMatrix4<T> temp ( EM4CONST_NOTHING );
433 temp[0] = M[0]*scalar;
434 temp[1] = M[1]*scalar;
435 temp[2] = M[2]*scalar;
436 temp[3] = M[3]*scalar;
437 temp[4] = M[4]*scalar;
438 temp[5] = M[5]*scalar;
439 temp[6] = M[6]*scalar;
440 temp[7] = M[7]*scalar;
441 temp[8] = M[8]*scalar;
442 temp[9] = M[9]*scalar;
443 temp[10] = M[10]*scalar;
444 temp[11] = M[11]*scalar;
445 temp[12] = M[12]*scalar;
446 temp[13] = M[13]*scalar;
447 temp[14] = M[14]*scalar;
448 temp[15] = M[15]*scalar;
450 return temp;
453 //! Multiply by scalar.
454 template <class T>
455 inline CMatrix4<T>& CMatrix4<T>::operator*=(const T& scalar)
457 M[0]*=scalar;
458 M[1]*=scalar;
459 M[2]*=scalar;
460 M[3]*=scalar;
461 M[4]*=scalar;
462 M[5]*=scalar;
463 M[6]*=scalar;
464 M[7]*=scalar;
465 M[8]*=scalar;
466 M[9]*=scalar;
467 M[10]*=scalar;
468 M[11]*=scalar;
469 M[12]*=scalar;
470 M[13]*=scalar;
471 M[14]*=scalar;
472 M[15]*=scalar;
474 return *this;
477 //! Multiply by another matrix.
478 template <class T>
479 inline CMatrix4<T>& CMatrix4<T>::operator*=(const CMatrix4<T>& other)
481 // do chacks on your own in order to avoid copy creation
482 if ( !other.isIdentity() )
484 if ( this->isIdentity() )
486 *this = other;
488 else
490 CMatrix4<T> temp ( *this );
491 setbyproduct_nocheck( temp, other );
494 return *this;
497 //! multiply by another matrix
498 // set this matrix to the product of two other matrices
499 // goal is to reduce stack use and copy
500 template <class T>
501 inline void CMatrix4<T>::setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b )
503 const T *m1 = other_a.M;
504 const T *m2 = other_b.M;
506 M[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
507 M[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
508 M[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
509 M[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
511 M[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
512 M[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
513 M[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
514 M[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
516 M[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
517 M[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
518 M[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
519 M[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
521 M[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
522 M[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
523 M[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
524 M[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
525 definitelyIdentityMatrix=false;
529 //! multiply by another matrix
530 // set this matrix to the product of two other matrices
531 // goal is to reduce stack use and copy
532 template <class T>
533 inline void CMatrix4<T>::setbyproduct(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b )
535 if ( other_a.isIdentity () )
537 *this = other_b;
538 return;
540 else
541 if ( other_b.isIdentity () )
543 *this = other_a;
544 return;
546 setbyproduct_nocheck(other_a,other_b);
549 //! multiply by another matrix
550 template <class T>
551 inline CMatrix4<T> CMatrix4<T>::operator*(const CMatrix4<T>& m2) const
553 // Testing purpose..
554 if ( this->isIdentity() )
555 return m2;
556 if ( m2.isIdentity() )
557 return *this;
559 CMatrix4<T> m3 ( EM4CONST_NOTHING );
561 const T *m1 = M;
563 m3[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
564 m3[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
565 m3[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
566 m3[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
568 m3[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
569 m3[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
570 m3[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
571 m3[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
573 m3[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
574 m3[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
575 m3[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
576 m3[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
578 m3[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
579 m3[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
580 m3[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
581 m3[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
582 return m3;
587 template <class T>
588 inline vector3d<T> CMatrix4<T>::getTranslation() const
590 return vector3d<T>(M[12], M[13], M[14]);
594 template <class T>
595 inline void CMatrix4<T>::setTranslation( const vector3d<T>& translation )
597 M[12] = translation.X;
598 M[13] = translation.Y;
599 M[14] = translation.Z;
600 definitelyIdentityMatrix=false;
603 template <class T>
604 inline void CMatrix4<T>::setInverseTranslation( const vector3d<T>& translation )
606 M[12] = -translation.X;
607 M[13] = -translation.Y;
608 M[14] = -translation.Z;
609 definitelyIdentityMatrix=false;
612 template <class T>
613 inline void CMatrix4<T>::setScale( const vector3d<T>& scale )
615 M[0] = scale.X;
616 M[5] = scale.Y;
617 M[10] = scale.Z;
618 definitelyIdentityMatrix=false;
621 template <class T>
622 inline vector3d<T> CMatrix4<T>::getScale() const
624 return vector3d<T>(M[0],M[5],M[10]);
627 template <class T>
628 inline void CMatrix4<T>::setRotationDegrees( const vector3d<T>& rotation )
630 setRotationRadians( rotation * core::DEGTORAD );
633 template <class T>
634 inline void CMatrix4<T>::setInverseRotationDegrees( const vector3d<T>& rotation )
636 setInverseRotationRadians( rotation * core::DEGTORAD );
639 template <class T>
640 inline void CMatrix4<T>::setRotationRadians( const vector3d<T>& rotation )
642 f64 cr = cos( rotation.X );
643 f64 sr = sin( rotation.X );
644 f64 cp = cos( rotation.Y );
645 f64 sp = sin( rotation.Y );
646 f64 cy = cos( rotation.Z );
647 f64 sy = sin( rotation.Z );
649 M[0] = (T)( cp*cy );
650 M[1] = (T)( cp*sy );
651 M[2] = (T)( -sp );
653 f64 srsp = sr*sp;
654 f64 crsp = cr*sp;
656 M[4] = (T)( srsp*cy-cr*sy );
657 M[5] = (T)( srsp*sy+cr*cy );
658 M[6] = (T)( sr*cp );
660 M[8] = (T)( crsp*cy+sr*sy );
661 M[9] = (T)( crsp*sy-sr*cy );
662 M[10] = (T)( cr*cp );
663 definitelyIdentityMatrix=false;
668 //! Returns the rotation, as set by setRotation(). This code was sent
669 //! in by Chev.
670 template <class T>
671 inline core::vector3d<T> CMatrix4<T>::getRotationDegrees() const
673 const CMatrix4<T> &mat = *this;
675 f64 Y = -asin(mat(0,2));
676 f64 C = cos(Y);
677 Y *= RADTODEG64;
679 f64 rotx, roty, X, Z;
681 if (fabs(C)>0.0005f)
683 rotx = mat(2,2) / C;
684 roty = mat(1,2) / C;
685 X = atan2( roty, rotx ) * RADTODEG64;
686 rotx = mat(0,0) / C;
687 roty = mat(0,1) / C;
688 Z = atan2( roty, rotx ) * RADTODEG64;
690 else
692 X = 0.0;
693 rotx = mat(1,1);
694 roty = -mat(1,0);
695 Z = atan2( roty, rotx ) * RADTODEG64;
698 // fix values that get below zero
699 // before it would set (!) values to 360
700 // that where above 360:
701 if (X < 0.0) X += 360.0;
702 if (Y < 0.0) Y += 360.0;
703 if (Z < 0.0) Z += 360.0;
705 return vector3d<T>((f32)X,(f32)Y,(f32)Z);
708 template <class T>
709 inline void CMatrix4<T>::setInverseRotationRadians( const vector3d<T>& rotation )
711 f64 cr = cos( rotation.X );
712 f64 sr = sin( rotation.X );
713 f64 cp = cos( rotation.Y );
714 f64 sp = sin( rotation.Y );
715 f64 cy = cos( rotation.Z );
716 f64 sy = sin( rotation.Z );
718 M[0] = (T)( cp*cy );
719 M[4] = (T)( cp*sy );
720 M[8] = (T)( -sp );
722 f64 srsp = sr*sp;
723 f64 crsp = cr*sp;
725 M[1] = (T)( srsp*cy-cr*sy );
726 M[5] = (T)( srsp*sy+cr*cy );
727 M[9] = (T)( sr*cp );
729 M[2] = (T)( crsp*cy+sr*sy );
730 M[6] = (T)( crsp*sy-sr*cy );
731 M[10] = (T)( cr*cp );
732 definitelyIdentityMatrix=false;
738 template <class T>
739 inline void CMatrix4<T>::makeIdentity()
741 memset(M, 0, 16*sizeof(T));
742 M[0] = M[5] = M[10] = M[15] = (T)1;
743 definitelyIdentityMatrix=true;
748 check identity with epsilon
749 solve floating range problems..
751 template <class T>
752 inline bool CMatrix4<T>::isIdentity() const
754 if (definitelyIdentityMatrix)
755 return true;
756 if ( !equals ( M[ 0], (T)1 ) ||
757 !equals ( M[ 5], (T)1 ) ||
758 !equals ( M[10], (T)1 ) ||
759 !equals ( M[15], (T)1 )
761 return false;
763 for (s32 i=0; i<4; ++i)
764 for (s32 j=0; j<4; ++j)
765 if (j != i)
766 if (!iszero((*this)(i,j)))
767 return false;
769 definitelyIdentityMatrix=true;
770 return true;
774 doesn't solve floating range problems..
775 but takes care on +/- 0 on translation because we are changing it..
776 reducing floating point branches
777 but it needs the floats in memory..
779 template <class T>
780 inline bool CMatrix4<T>::isIdentity_integer_base() const
782 if (definitelyIdentityMatrix)
783 return true;
784 if(IR(M[0])!=F32_VALUE_1) return false;
785 if(IR(M[1])!=0) return false;
786 if(IR(M[2])!=0) return false;
787 if(IR(M[3])!=0) return false;
789 if(IR(M[4])!=0) return false;
790 if(IR(M[5])!=F32_VALUE_1) return false;
791 if(IR(M[6])!=0) return false;
792 if(IR(M[7])!=0) return false;
794 if(IR(M[8])!=0) return false;
795 if(IR(M[9])!=0) return false;
796 if(IR(M[10])!=F32_VALUE_1) return false;
797 if(IR(M[11])!=0) return false;
799 if(IR(M[12])!=0) return false;
800 if(IR(M[13])!=0) return false;
801 if(IR(M[13])!=0) return false;
802 if(IR(M[15])!=F32_VALUE_1) return false;
803 definitelyIdentityMatrix=true;
804 return true;
809 template <class T>
810 inline void CMatrix4<T>::rotateVect( vector3df& vect ) const
812 vector3df tmp = vect;
813 vect.X = tmp.X*M[0] + tmp.Y*M[4] + tmp.Z*M[8];
814 vect.Y = tmp.X*M[1] + tmp.Y*M[5] + tmp.Z*M[9];
815 vect.Z = tmp.X*M[2] + tmp.Y*M[6] + tmp.Z*M[10];
818 //! An alternate transform vector method, writing into a second vector
819 template <class T>
820 inline void CMatrix4<T>::rotateVect(core::vector3df& out, const core::vector3df& in) const
822 out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
823 out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
824 out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
827 //! An alternate transform vector method, writing into an array of 3 floats
828 template <class T>
829 inline void CMatrix4<T>::rotateVect(T *out, const core::vector3df& in) const
831 out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
832 out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
833 out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
836 template <class T>
837 inline void CMatrix4<T>::inverseRotateVect( vector3df& vect ) const
839 vector3df tmp = vect;
840 vect.X = tmp.X*M[0] + tmp.Y*M[1] + tmp.Z*M[2];
841 vect.Y = tmp.X*M[4] + tmp.Y*M[5] + tmp.Z*M[6];
842 vect.Z = tmp.X*M[8] + tmp.Y*M[9] + tmp.Z*M[10];
845 template <class T>
846 inline void CMatrix4<T>::transformVect( vector3df& vect) const
848 f32 vector[3];
850 vector[0] = vect.X*M[0] + vect.Y*M[4] + vect.Z*M[8] + M[12];
851 vector[1] = vect.X*M[1] + vect.Y*M[5] + vect.Z*M[9] + M[13];
852 vector[2] = vect.X*M[2] + vect.Y*M[6] + vect.Z*M[10] + M[14];
854 vect.X = vector[0];
855 vect.Y = vector[1];
856 vect.Z = vector[2];
859 template <class T>
860 inline void CMatrix4<T>::transformVect( vector3df& out, const vector3df& in) const
862 out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
863 out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
864 out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
868 template <class T>
869 inline void CMatrix4<T>::transformVect(T *out,const vector3df &in) const
871 out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
872 out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
873 out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
874 out[3] = in.X*M[3] + in.Y*M[7] + in.Z*M[11] + M[15];
878 //! Transforms a plane by this matrix
879 template <class T>
880 inline void CMatrix4<T>::transformPlane( core::plane3d<f32> &plane) const
882 vector3df member;
883 transformVect(member, plane.getMemberPoint());
885 vector3df origin(0,0,0);
886 transformVect(plane.Normal);
887 transformVect(origin);
889 plane.Normal -= origin;
890 plane.D = - member.dotProduct(plane.Normal);
893 //! Transforms a plane by this matrix
894 template <class T>
895 inline void CMatrix4<T>::transformPlane_new( core::plane3d<f32> &plane) const
897 // rotate normal -> rotateVect ( plane.n );
898 vector3df n;
899 n.X = plane.Normal.X*M[0] + plane.Normal.Y*M[4] + plane.Normal.Z*M[8];
900 n.Y = plane.Normal.X*M[1] + plane.Normal.Y*M[5] + plane.Normal.Z*M[9];
901 n.Z = plane.Normal.X*M[2] + plane.Normal.Y*M[6] + plane.Normal.Z*M[10];
903 // compute new d. -> getTranslation(). dotproduct ( plane.n )
904 plane.D -= M[12] * n.X + M[13] * n.Y + M[14] * n.Z;
905 plane.Normal.X = n.X;
906 plane.Normal.Y = n.Y;
907 plane.Normal.Z = n.Z;
910 //! Transforms a plane by this matrix
911 template <class T>
912 inline void CMatrix4<T>::transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const
914 out = in;
915 transformPlane( out );
918 //! Transforms a axis aligned bounding box
919 template <class T>
920 inline void CMatrix4<T>::transformBox(core::aabbox3d<f32>& box) const
922 if (isIdentity() )
923 return;
925 transformVect(box.MinEdge);
926 transformVect(box.MaxEdge);
927 box.repair();
930 //! Transforms a axis aligned bounding box more accurately than transformBox()
931 template <class T>
932 inline void CMatrix4<T>::transformBoxEx(core::aabbox3d<f32>& box) const
934 f32 Amin[3];
935 f32 Amax[3];
936 f32 Bmin[3];
937 f32 Bmax[3];
939 Amin[0] = box.MinEdge.X;
940 Amin[1] = box.MinEdge.Y;
941 Amin[2] = box.MinEdge.Z;
943 Amax[0] = box.MaxEdge.X;
944 Amax[1] = box.MaxEdge.Y;
945 Amax[2] = box.MaxEdge.Z;
947 Bmin[0] = Bmax[0] = M[12];
948 Bmin[1] = Bmax[1] = M[13];
949 Bmin[2] = Bmax[2] = M[14];
951 u32 i, j;
952 const CMatrix4<T> &m = *this;
954 for (i = 0; i < 3; ++i)
956 for (j = 0; j < 3; ++j)
958 f32 a = m(j,i) * Amin[j];
959 f32 b = m(j,i) * Amax[j];
961 if (a < b)
963 Bmin[i] += a;
964 Bmax[i] += b;
966 else
968 Bmin[i] += b;
969 Bmax[i] += a;
974 box.MinEdge.X = Bmin[0];
975 box.MinEdge.Y = Bmin[1];
976 box.MinEdge.Z = Bmin[2];
978 box.MaxEdge.X = Bmax[0];
979 box.MaxEdge.Y = Bmax[1];
980 box.MaxEdge.Z = Bmax[2];
984 //! Multiplies this matrix by a 1x4 matrix
985 template <class T>
986 inline void CMatrix4<T>::multiplyWith1x4Matrix(T* matrix) const
989 0 1 2 3
990 4 5 6 7
991 8 9 10 11
992 12 13 14 15
995 T mat[4];
996 mat[0] = matrix[0];
997 mat[1] = matrix[1];
998 mat[2] = matrix[2];
999 mat[3] = matrix[3];
1001 matrix[0] = M[0]*mat[0] + M[4]*mat[1] + M[8]*mat[2] + M[12]*mat[3];
1002 matrix[1] = M[1]*mat[0] + M[5]*mat[1] + M[9]*mat[2] + M[13]*mat[3];
1003 matrix[2] = M[2]*mat[0] + M[6]*mat[1] + M[10]*mat[2] + M[14]*mat[3];
1004 matrix[3] = M[3]*mat[0] + M[7]*mat[1] + M[11]*mat[2] + M[15]*mat[3];
1007 template <class T>
1008 inline void CMatrix4<T>::inverseTranslateVect( vector3df& vect ) const
1010 vect.X = vect.X-M[12];
1011 vect.Y = vect.Y-M[13];
1012 vect.Z = vect.Z-M[14];
1015 template <class T>
1016 inline void CMatrix4<T>::translateVect( vector3df& vect ) const
1018 vect.X = vect.X+M[12];
1019 vect.Y = vect.Y+M[13];
1020 vect.Z = vect.Z+M[14];
1024 template <class T>
1025 inline bool CMatrix4<T>::getInverse(CMatrix4<T>& out) const
1027 /// Calculates the inverse of this Matrix
1028 /// The inverse is calculated using Cramers rule.
1029 /// If no inverse exists then 'false' is returned.
1031 if ( this->isIdentity() )
1033 out=*this;
1034 return true;
1037 const CMatrix4<T> &m = *this;
1039 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)) -
1040 (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) +
1041 (m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1)) +
1042 (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) -
1043 (m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) +
1044 (m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0));
1046 if( core::iszero ( d ) )
1047 return false;
1049 d = core::reciprocal ( d );
1051 out(0, 0) = d * (m(1, 1) * (m(2, 2) * m(3, 3) - m(2, 3) * m(3, 2)) + m(1, 2) * (m(2, 3) * m(3, 1) - m(2, 1) * m(3, 3)) + m(1, 3) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1)));
1052 out(0, 1) = d * (m(2, 1) * (m(0, 2) * m(3, 3) - m(0, 3) * m(3, 2)) + m(2, 2) * (m(0, 3) * m(3, 1) - m(0, 1) * m(3, 3)) + m(2, 3) * (m(0, 1) * m(3, 2) - m(0, 2) * m(3, 1)));
1053 out(0, 2) = d * (m(3, 1) * (m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) + m(3, 2) * (m(0, 3) * m(1, 1) - m(0, 1) * m(1, 3)) + m(3, 3) * (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)));
1054 out(0, 3) = d * (m(0, 1) * (m(1, 3) * m(2, 2) - m(1, 2) * m(2, 3)) + m(0, 2) * (m(1, 1) * m(2, 3) - m(1, 3) * m(2, 1)) + m(0, 3) * (m(1, 2) * m(2, 1) - m(1, 1) * m(2, 2)));
1055 out(1, 0) = d * (m(1, 2) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) + m(1, 3) * (m(2, 2) * m(3, 0) - m(2, 0) * m(3, 2)) + m(1, 0) * (m(2, 3) * m(3, 2) - m(2, 2) * m(3, 3)));
1056 out(1, 1) = d * (m(2, 2) * (m(0, 0) * m(3, 3) - m(0, 3) * m(3, 0)) + m(2, 3) * (m(0, 2) * m(3, 0) - m(0, 0) * m(3, 2)) + m(2, 0) * (m(0, 3) * m(3, 2) - m(0, 2) * m(3, 3)));
1057 out(1, 2) = d * (m(3, 2) * (m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) + m(3, 3) * (m(0, 2) * m(1, 0) - m(0, 0) * m(1, 2)) + m(3, 0) * (m(0, 3) * m(1, 2) - m(0, 2) * m(1, 3)));
1058 out(1, 3) = d * (m(0, 2) * (m(1, 3) * m(2, 0) - m(1, 0) * m(2, 3)) + m(0, 3) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) + m(0, 0) * (m(1, 2) * m(2, 3) - m(1, 3) * m(2, 2)));
1059 out(2, 0) = d * (m(1, 3) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0)) + m(1, 0) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) + m(1, 1) * (m(2, 3) * m(3, 0) - m(2, 0) * m(3, 3)));
1060 out(2, 1) = d * (m(2, 3) * (m(0, 0) * m(3, 1) - m(0, 1) * m(3, 0)) + m(2, 0) * (m(0, 1) * m(3, 3) - m(0, 3) * m(3, 1)) + m(2, 1) * (m(0, 3) * m(3, 0) - m(0, 0) * m(3, 3)));
1061 out(2, 2) = d * (m(3, 3) * (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) + m(3, 0) * (m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) + m(3, 1) * (m(0, 3) * m(1, 0) - m(0, 0) * m(1, 3)));
1062 out(2, 3) = d * (m(0, 3) * (m(1, 1) * m(2, 0) - m(1, 0) * m(2, 1)) + m(0, 0) * (m(1, 3) * m(2, 1) - m(1, 1) * m(2, 3)) + m(0, 1) * (m(1, 0) * m(2, 3) - m(1, 3) * m(2, 0)));
1063 out(3, 0) = d * (m(1, 0) * (m(2, 2) * m(3, 1) - m(2, 1) * m(3, 2)) + m(1, 1) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) + m(1, 2) * (m(2, 1) * m(3, 0) - m(2, 0) * m(3, 1)));
1064 out(3, 1) = d * (m(2, 0) * (m(0, 2) * m(3, 1) - m(0, 1) * m(3, 2)) + m(2, 1) * (m(0, 0) * m(3, 2) - m(0, 2) * m(3, 0)) + m(2, 2) * (m(0, 1) * m(3, 0) - m(0, 0) * m(3, 1)));
1065 out(3, 2) = d * (m(3, 0) * (m(0, 2) * m(1, 1) - m(0, 1) * m(1, 2)) + m(3, 1) * (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) + m(3, 2) * (m(0, 1) * m(1, 0) - m(0, 0) * m(1, 1)));
1066 out(3, 3) = d * (m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) + m(0, 1) * (m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2)) + m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0)));
1067 out.definitelyIdentityMatrix = definitelyIdentityMatrix;
1068 return true;
1072 //! Inverts a primitive matrix which only contains a translation and a rotation
1073 //! \param out: where result matrix is written to.
1074 template <class T>
1075 inline bool CMatrix4<T>::getInversePrimitive ( CMatrix4<T>& out ) const
1077 out.M[0 ] = M[0];
1078 out.M[1 ] = M[4];
1079 out.M[2 ] = M[8];
1080 out.M[3 ] = 0;
1082 out.M[4 ] = M[1];
1083 out.M[5 ] = M[5];
1084 out.M[6 ] = M[9];
1085 out.M[7 ] = 0;
1087 out.M[8 ] = M[2];
1088 out.M[9 ] = M[6];
1089 out.M[10] = M[10];
1090 out.M[11] = 0;
1092 out.M[12] = (T)-(M[12]*M[0] + M[13]*M[1] + M[14]*M[2]);
1093 out.M[13] = (T)-(M[12]*M[4] + M[13]*M[5] + M[14]*M[6]);
1094 out.M[14] = (T)-(M[12]*M[8] + M[13]*M[9] + M[14]*M[10]);
1095 out.M[15] = 1;
1096 out.definitelyIdentityMatrix = definitelyIdentityMatrix;
1097 return true;
1102 template <class T>
1103 inline bool CMatrix4<T>::makeInverse()
1105 if (definitelyIdentityMatrix)
1106 return true;
1108 CMatrix4<T> temp ( EM4CONST_NOTHING );
1110 if (getInverse(temp))
1112 *this = temp;
1113 return true;
1116 return false;
1121 template <class T>
1122 inline CMatrix4<T>& CMatrix4<T>::operator=(const CMatrix4<T> &other)
1124 if (this==&other)
1125 return *this;
1126 memcpy(M, other.M, 16*sizeof(T));
1127 definitelyIdentityMatrix=other.definitelyIdentityMatrix;
1128 return *this;
1133 template <class T>
1134 inline CMatrix4<T>& CMatrix4<T>::operator=(const T& scalar)
1136 for (s32 i = 0; i < 16; ++i)
1137 M[i]=scalar;
1138 definitelyIdentityMatrix=false;
1139 return *this;
1144 template <class T>
1145 inline bool CMatrix4<T>::operator==(const CMatrix4<T> &other) const
1147 if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
1148 return true;
1149 for (s32 i = 0; i < 16; ++i)
1150 if (M[i] != other.M[i])
1151 return false;
1153 return true;
1158 template <class T>
1159 inline bool CMatrix4<T>::operator!=(const CMatrix4<T> &other) const
1161 return !(*this == other);
1166 //! Builds a right-handed perspective projection matrix based on a field of view
1167 template <class T>
1168 inline void CMatrix4<T>::buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar)
1170 f64 h = 1.0/tan(fieldOfViewRadians/2.0);
1171 T w = h / aspectRatio;
1173 M[0] = w;
1174 M[1] = 0;
1175 M[2] = 0;
1176 M[3] = 0;
1178 M[4] = 0;
1179 M[5] = (T)h;
1180 M[6] = 0;
1181 M[7] = 0;
1183 M[8] = 0;
1184 M[9] = 0;
1185 M[10] = (T)(zFar/(zNear-zFar)); // DirectX version
1186 // M[10] = (T)(zFar+zNear/(zNear-zFar)); // OpenGL version
1187 M[11] = -1;
1189 M[12] = 0;
1190 M[13] = 0;
1191 M[14] = (T)(zNear*zFar/(zNear-zFar)); // DirectX version
1192 // M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar)); // OpenGL version
1193 M[15] = 0;
1194 definitelyIdentityMatrix=false;
1199 //! Builds a left-handed perspective projection matrix based on a field of view
1200 template <class T>
1201 inline void CMatrix4<T>::buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar)
1203 f64 h = 1.0/tan(fieldOfViewRadians/2.0);
1204 T w = (T)(h / aspectRatio);
1206 M[0] = w;
1207 M[1] = 0;
1208 M[2] = 0;
1209 M[3] = 0;
1211 M[4] = 0;
1212 M[5] = (T)h;
1213 M[6] = 0;
1214 M[7] = 0;
1216 M[8] = 0;
1217 M[9] = 0;
1218 M[10] = (T)(zFar/(zFar-zNear));
1219 M[11] = 1;
1221 M[12] = 0;
1222 M[13] = 0;
1223 M[14] = (T)(-zNear*zFar/(zFar-zNear));
1224 M[15] = 0;
1225 definitelyIdentityMatrix=false;
1230 //! Builds a left-handed orthogonal projection matrix.
1231 template <class T>
1232 inline void CMatrix4<T>::buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
1234 M[0] = (T)(2/widthOfViewVolume);
1235 M[1] = 0;
1236 M[2] = 0;
1237 M[3] = 0;
1239 M[4] = 0;
1240 M[5] = (T)(2/heightOfViewVolume);
1241 M[6] = 0;
1242 M[7] = 0;
1244 M[8] = 0;
1245 M[9] = 0;
1246 M[10] = (T)(1/(zFar-zNear));
1247 M[11] = 0;
1249 M[12] = 0;
1250 M[13] = 0;
1251 M[14] = (T)(zNear/(zNear-zFar));
1252 M[15] = 1;
1253 definitelyIdentityMatrix=false;
1258 //! Builds a right-handed orthogonal projection matrix.
1259 template <class T>
1260 inline void CMatrix4<T>::buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
1262 M[0] = (T)(2/widthOfViewVolume);
1263 M[1] = 0;
1264 M[2] = 0;
1265 M[3] = 0;
1267 M[4] = 0;
1268 M[5] = (T)(2/heightOfViewVolume);
1269 M[6] = 0;
1270 M[7] = 0;
1272 M[8] = 0;
1273 M[9] = 0;
1274 M[10] = (T)(1/(zNear-zFar));
1275 M[11] = 0;
1277 M[12] = 0;
1278 M[13] = 0;
1279 M[14] = (T)(zNear/(zNear-zFar));
1280 M[15] = -1;
1281 definitelyIdentityMatrix=false;
1285 //! Builds a right-handed perspective projection matrix.
1286 template <class T>
1287 inline void CMatrix4<T>::buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
1289 M[0] = (T)(2*zNear/widthOfViewVolume);
1290 M[1] = 0;
1291 M[2] = 0;
1292 M[3] = 0;
1294 M[4] = 0;
1295 M[5] = (T)(2*zNear/heightOfViewVolume);
1296 M[6] = 0;
1297 M[7] = 0;
1299 M[8] = 0;
1300 M[9] = 0;
1301 M[10] = (T)(zFar/(zNear-zFar));
1302 M[11] = -1;
1304 M[12] = 0;
1305 M[13] = 0;
1306 M[14] = (T)(zNear*zFar/(zNear-zFar));
1307 M[15] = 0;
1308 definitelyIdentityMatrix=false;
1312 //! Builds a left-handed perspective projection matrix.
1313 template <class T>
1314 inline void CMatrix4<T>::buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
1316 M[0] = (T)(2*zNear/widthOfViewVolume);
1317 M[1] = 0;
1318 M[2] = 0;
1319 M[3] = 0;
1321 M[4] = 0;
1322 M[5] = (T)(2*zNear/heightOfViewVolume);
1323 M[6] = 0;
1324 M[7] = 0;
1326 M[8] = 0;
1327 M[9] = 0;
1328 M[10] = (T)(zFar/(zFar-zNear));
1329 M[11] = 1;
1331 M[12] = 0;
1332 M[13] = 0;
1333 M[14] = (T)(zNear*zFar/(zNear-zFar));
1334 M[15] = 0;
1335 definitelyIdentityMatrix=false;
1339 //! Builds a matrix that flattens geometry into a plane.
1340 template <class T>
1341 inline void CMatrix4<T>::buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point)
1343 plane.Normal.normalize();
1344 f32 d = plane.Normal.dotProduct(light);
1346 M[ 0] = (T)(-plane.Normal.X * light.X + d);
1347 M[ 1] = (T)(-plane.Normal.X * light.Y);
1348 M[ 2] = (T)(-plane.Normal.X * light.Z);
1349 M[ 3] = (T)(-plane.Normal.X * point);
1351 M[ 4] = (T)(-plane.Normal.Y * light.X);
1352 M[ 5] = (T)(-plane.Normal.Y * light.Y + d);
1353 M[ 6] = (T)(-plane.Normal.Y * light.Z);
1354 M[ 7] = (T)(-plane.Normal.Y * point);
1356 M[ 8] = (T)(-plane.Normal.Z * light.X);
1357 M[ 9] = (T)(-plane.Normal.Z * light.Y);
1358 M[10] = (T)(-plane.Normal.Z * light.Z + d);
1359 M[11] = (T)(-plane.Normal.Z * point);
1361 M[12] = (T)(-plane.D * light.X);
1362 M[13] = (T)(-plane.D * light.Y);
1363 M[14] = (T)(-plane.D * light.Z);
1364 M[15] = (T)(-plane.D * point + d);
1365 definitelyIdentityMatrix=false;
1368 //! Builds a left-handed look-at matrix.
1369 template <class T>
1370 inline void CMatrix4<T>::buildCameraLookAtMatrixLH(
1371 const vector3df& position,
1372 const vector3df& target,
1373 const vector3df& upVector)
1375 vector3df zaxis = target - position;
1376 zaxis.normalize();
1378 vector3df xaxis = upVector.crossProduct(zaxis);
1379 xaxis.normalize();
1381 vector3df yaxis = zaxis.crossProduct(xaxis);
1383 M[0] = (T)xaxis.X;
1384 M[1] = (T)yaxis.X;
1385 M[2] = (T)zaxis.X;
1386 M[3] = 0;
1388 M[4] = (T)xaxis.Y;
1389 M[5] = (T)yaxis.Y;
1390 M[6] = (T)zaxis.Y;
1391 M[7] = 0;
1393 M[8] = (T)xaxis.Z;
1394 M[9] = (T)yaxis.Z;
1395 M[10] = (T)zaxis.Z;
1396 M[11] = 0;
1398 M[12] = (T)-xaxis.dotProduct(position);
1399 M[13] = (T)-yaxis.dotProduct(position);
1400 M[14] = (T)-zaxis.dotProduct(position);
1401 M[15] = 1;
1402 definitelyIdentityMatrix=false;
1407 //! Builds a right-handed look-at matrix.
1408 template <class T>
1409 inline void CMatrix4<T>::buildCameraLookAtMatrixRH(
1410 const vector3df& position,
1411 const vector3df& target,
1412 const vector3df& upVector)
1414 vector3df zaxis = position - target;
1415 zaxis.normalize();
1417 vector3df xaxis = upVector.crossProduct(zaxis);
1418 xaxis.normalize();
1420 vector3df yaxis = zaxis.crossProduct(xaxis);
1422 M[0] = (T)xaxis.X;
1423 M[1] = (T)yaxis.X;
1424 M[2] = (T)zaxis.X;
1425 M[3] = 0;
1427 M[4] = (T)xaxis.Y;
1428 M[5] = (T)yaxis.Y;
1429 M[6] = (T)zaxis.Y;
1430 M[7] = 0;
1432 M[8] = (T)xaxis.Z;
1433 M[9] = (T)yaxis.Z;
1434 M[10] = (T)zaxis.Z;
1435 M[11] = 0;
1437 M[12] = (T)-xaxis.dotProduct(position);
1438 M[13] = (T)-yaxis.dotProduct(position);
1439 M[14] = (T)-zaxis.dotProduct(position);
1440 M[15] = 1;
1441 definitelyIdentityMatrix=false;
1445 //! creates a new matrix as interpolated matrix from to other ones.
1446 //! \param time: Must be a value between 0 and 1.
1447 template <class T>
1448 inline CMatrix4<T> CMatrix4<T>::interpolate(const core::CMatrix4<T>& b, f32 time) const
1450 CMatrix4<T> mat ( EM4CONST_NOTHING );
1452 for (u32 i=0; i < 16; i += 4)
1454 mat.M[i+0] = (T)(M[i+0] + ( b.M[i+0] - M[i+0] ) * time);
1455 mat.M[i+1] = (T)(M[i+1] + ( b.M[i+1] - M[i+1] ) * time);
1456 mat.M[i+2] = (T)(M[i+2] + ( b.M[i+2] - M[i+2] ) * time);
1457 mat.M[i+3] = (T)(M[i+3] + ( b.M[i+3] - M[i+3] ) * time);
1459 return mat;
1462 //! returns transposed matrix
1463 template <class T>
1464 inline CMatrix4<T> CMatrix4<T>::getTransposed() const
1466 CMatrix4<T> t ( EM4CONST_NOTHING );
1467 getTransposed ( t );
1468 return t;
1471 //! returns transposed matrix
1472 template <class T>
1473 inline void CMatrix4<T>::getTransposed( CMatrix4<T>& o ) const
1475 o[ 0] = M[ 0];
1476 o[ 1] = M[ 4];
1477 o[ 2] = M[ 8];
1478 o[ 3] = M[12];
1480 o[ 4] = M[ 1];
1481 o[ 5] = M[ 5];
1482 o[ 6] = M[ 9];
1483 o[ 7] = M[13];
1485 o[ 8] = M[ 2];
1486 o[ 9] = M[ 6];
1487 o[10] = M[10];
1488 o[11] = M[14];
1490 o[12] = M[ 3];
1491 o[13] = M[ 7];
1492 o[14] = M[11];
1493 o[15] = M[15];
1494 o.definitelyIdentityMatrix=definitelyIdentityMatrix;
1498 // used to scale <-1,-1><1,1> to viewport
1499 template <class T>
1500 inline void CMatrix4<T>::buildNDCToDCMatrix( const core::rect<s32>& viewport, f32 zScale)
1502 f32 scaleX = (viewport.getWidth() - 0.75f ) / 2.0f;
1503 f32 scaleY = -(viewport.getHeight() - 0.75f ) / 2.0f;
1505 f32 dx = -0.5f + ( (viewport.UpperLeftCorner.X + viewport.LowerRightCorner.X ) / 2.0f );
1506 f32 dy = -0.5f + ( (viewport.UpperLeftCorner.Y + viewport.LowerRightCorner.Y ) / 2.0f );
1508 makeIdentity();
1509 M[0] = (T)scaleX;
1510 M[5] = (T)scaleY;
1511 M[10] = (T)zScale;
1512 M[12] = (T)dx;
1513 M[13] = (T)dy;
1514 definitelyIdentityMatrix=false;
1518 Generate texture coordinates as linear functions so that:
1519 u = Ux*x + Uy*y + Uz*z + Uw
1520 v = Vx*x + Vy*y + Vz*z + Vw
1521 The matrix M for this case is:
1522 Ux Vx 0 0
1523 Uy Vy 0 0
1524 Uz Vz 0 0
1525 Uw Vw 0 0
1528 template <class T>
1529 inline void CMatrix4<T>::buildTextureTransform( f32 rotateRad,
1530 const core::vector2df &rotatecenter,
1531 const core::vector2df &translate,
1532 const core::vector2df &scale)
1534 const f32 c = cosf(rotateRad);
1535 const f32 s = sinf(rotateRad);
1537 M[0] = (T)(c * scale.X);
1538 M[1] = (T)(s * scale.Y);
1539 M[2] = 0;
1540 M[3] = 0;
1542 M[4] = (T)(-s * scale.X);
1543 M[5] = (T)(c * scale.Y);
1544 M[6] = 0;
1545 M[7] = 0;
1547 M[8] = (T)(c * scale.X * rotatecenter.X + -s * rotatecenter.Y + translate.X);
1548 M[9] = (T)(s * scale.Y * rotatecenter.X + c * rotatecenter.Y + translate.Y);
1549 M[10] = 1;
1550 M[11] = 0;
1552 M[12] = 0;
1553 M[13] = 0;
1554 M[14] = 0;
1555 M[15] = 1;
1556 definitelyIdentityMatrix=false;
1559 //! rotate about z axis, center ( 0.5, 0.5 )
1560 template <class T>
1561 inline void CMatrix4<T>::setTextureRotationCenter( f32 rotateRad )
1563 const f32 c = cosf(rotateRad);
1564 const f32 s = sinf(rotateRad);
1565 M[0] = (T)c;
1566 M[1] = (T)s;
1567 M[2] = (T)(-0.5f * ( c + s) + 0.5f);
1569 M[4] = (T)-s;
1570 M[5] = (T)c;
1571 M[6] = (T)(-0.5f * (-s + c) + 0.5f);
1572 definitelyIdentityMatrix=false;
1575 template <class T>
1576 inline void CMatrix4<T>::setTextureTranslate ( f32 x, f32 y )
1578 M[8] = (T)x;
1579 M[9] = (T)y;
1580 definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f) ;
1583 template <class T>
1584 inline void CMatrix4<T>::setTextureScale ( f32 sx, f32 sy )
1586 M[0] = (T)sx;
1587 M[5] = (T)sy;
1588 definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f) ;
1591 template <class T>
1592 inline void CMatrix4<T>::setTextureScaleCenter( f32 sx, f32 sy )
1594 M[0] = (T)sx;
1595 M[2] = (T)(-0.5f * sx + 0.5f);
1596 M[5] = (T)sy;
1597 M[6] = (T)(-0.5f * sy + 0.5f);
1598 definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f) ;
1601 //! sets all matrix data members at once
1602 template <class T>
1603 inline void CMatrix4<T>::setM(const T* data)
1605 for (u32 i = 0; i < 16; ++i)
1606 M[i] = data[i];
1608 definitelyIdentityMatrix = false;
1611 //! sets if the matrix is definitely identity matrix
1612 template <class T>
1613 inline void CMatrix4<T>::setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix)
1615 definitelyIdentityMatrix = isDefinitelyIdentityMatrix;
1618 //! gets if the matrix is definitely identity matrix
1619 template <class T>
1620 inline bool CMatrix4<T>::getDefinitelyIdentityMatrix() const
1622 return definitelyIdentityMatrix;
1625 //! Multiply by scalar.
1626 template <class T>
1627 inline CMatrix4<T> operator*(const T scalar, const CMatrix4<T>& mat)
1629 return mat*scalar;
1632 typedef CMatrix4<f32> matrix4;
1633 const matrix4 IdentityMatrix(matrix4::EM4CONST_IDENTITY);
1635 } // end namespace core
1636 } // end namespace irr
1638 #endif