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