Line data Source code
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 :
26 : struct MatrixTest
27 : {
28 : MatrixTest () : ID(0), Calls(0) {}
29 : char buf[256];
30 : int Calls;
31 : int ID;
32 : };
33 : static MatrixTest MTest;
34 :
35 : #endif
36 :
37 : namespace irr
38 : {
39 : namespace core
40 : {
41 :
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 22819888 : T& operator()(const s32 row, const s32 col)
70 : {
71 : #if defined ( USE_MATRIX_TEST )
72 : definitelyIdentityMatrix=false;
73 : #endif
74 22819888 : return M[ row * 4 + col ];
75 : }
76 :
77 : //! Simple operator for directly accessing every element of the matrix.
78 410758920 : 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 30090608 : T& operator[](u32 index)
82 : {
83 : #if defined ( USE_MATRIX_TEST )
84 : definitelyIdentityMatrix=false;
85 : #endif
86 30090608 : return M[index];
87 : }
88 :
89 : //! Simple operator for linearly accessing every element of the matrix.
90 29093440 : 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 5704312 : T* pointer()
101 : {
102 : #if defined ( USE_MATRIX_TEST )
103 : definitelyIdentityMatrix=false;
104 : #endif
105 5704312 : 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 5271019 : 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 5271019 : switch ( constructor )
426 : {
427 : case EM4CONST_NOTHING:
428 : case EM4CONST_COPY:
429 3306741 : break;
430 : case EM4CONST_IDENTITY:
431 : case EM4CONST_INVERSE:
432 : default:
433 1964278 : makeIdentity();
434 1964278 : break;
435 : }
436 5271019 : }
437 :
438 : // Copy constructor
439 : template <class T>
440 7252520 : 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 7252520 : switch ( constructor )
449 : {
450 : case EM4CONST_IDENTITY:
451 0 : makeIdentity();
452 0 : break;
453 : case EM4CONST_NOTHING:
454 0 : break;
455 : case EM4CONST_COPY:
456 7252520 : *this = other;
457 7252520 : break;
458 : case EM4CONST_TRANSPOSED:
459 0 : other.getTransposed(*this);
460 0 : break;
461 : case EM4CONST_INVERSE:
462 0 : if (!other.getInverse(*this))
463 0 : memset(M, 0, 16*sizeof(T));
464 0 : break;
465 : case EM4CONST_INVERSE_TRANSPOSED:
466 0 : if (!other.getInverse(*this))
467 0 : memset(M, 0, 16*sizeof(T));
468 : else
469 0 : *this=getTransposed();
470 0 : break;
471 : }
472 7252520 : }
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 2970788 : 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 2970788 : CMatrix4<T> temp ( *this );
645 2970788 : 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 2970788 : inline CMatrix4<T>& CMatrix4<T>::setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b )
654 : {
655 2970788 : const T *m1 = other_a.M;
656 2970788 : const T *m2 = other_b.M;
657 :
658 2970788 : M[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
659 2970788 : M[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
660 2970788 : M[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
661 2970788 : M[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
662 :
663 2970788 : M[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
664 2970788 : M[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
665 2970788 : M[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
666 2970788 : M[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
667 :
668 2970788 : M[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
669 2970788 : M[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
670 2970788 : M[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
671 2970788 : M[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
672 :
673 2970788 : M[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
674 2970788 : M[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
675 2970788 : M[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
676 2970788 : 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 2970788 : 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 454585 : 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 454585 : CMatrix4<T> m3 ( EM4CONST_NOTHING );
716 :
717 454585 : const T *m1 = M;
718 :
719 454585 : m3[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
720 454585 : m3[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
721 454585 : m3[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
722 454585 : m3[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
723 :
724 454585 : m3[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
725 454585 : m3[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
726 454585 : m3[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
727 454585 : m3[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
728 :
729 454585 : m3[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
730 454585 : m3[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
731 454585 : m3[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
732 454585 : m3[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
733 :
734 454585 : m3[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
735 454585 : m3[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
736 454585 : m3[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
737 454585 : m3[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
738 454585 : return m3;
739 : }
740 :
741 :
742 :
743 : template <class T>
744 18647 : inline vector3d<T> CMatrix4<T>::getTranslation() const
745 : {
746 18647 : return vector3d<T>(M[12], M[13], M[14]);
747 : }
748 :
749 :
750 : template <class T>
751 362692 : inline CMatrix4<T>& CMatrix4<T>::setTranslation( const vector3d<T>& translation )
752 : {
753 362692 : M[12] = translation.X;
754 362692 : M[13] = translation.Y;
755 362692 : M[14] = translation.Z;
756 : #if defined ( USE_MATRIX_TEST )
757 : definitelyIdentityMatrix=false;
758 : #endif
759 362692 : 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 119798 : inline CMatrix4<T>& CMatrix4<T>::setScale( const vector3d<T>& scale )
776 : {
777 119798 : M[0] = scale.X;
778 119798 : M[5] = scale.Y;
779 119798 : M[10] = scale.Z;
780 : #if defined ( USE_MATRIX_TEST )
781 : definitelyIdentityMatrix=false;
782 : #endif
783 119798 : 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 361526 : inline CMatrix4<T>& CMatrix4<T>::setRotationDegrees( const vector3d<T>& rotation )
814 : {
815 361526 : 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 361526 : inline CMatrix4<T>& CMatrix4<T>::setRotationRadians( const vector3d<T>& rotation )
826 : {
827 361526 : const f64 cr = cos( rotation.X );
828 361526 : const f64 sr = sin( rotation.X );
829 361526 : const f64 cp = cos( rotation.Y );
830 361526 : const f64 sp = sin( rotation.Y );
831 361526 : const f64 cy = cos( rotation.Z );
832 361526 : const f64 sy = sin( rotation.Z );
833 :
834 361526 : M[0] = (T)( cp*cy );
835 361526 : M[1] = (T)( cp*sy );
836 361526 : M[2] = (T)( -sp );
837 :
838 361526 : const f64 srsp = sr*sp;
839 361526 : const f64 crsp = cr*sp;
840 :
841 361526 : M[4] = (T)( srsp*cy-cr*sy );
842 361526 : M[5] = (T)( srsp*sy+cr*cy );
843 361526 : M[6] = (T)( sr*cp );
844 :
845 361526 : M[8] = (T)( crsp*cy+sr*sy );
846 361526 : M[9] = (T)( crsp*sy-sr*cy );
847 361526 : M[10] = (T)( cr*cp );
848 : #if defined ( USE_MATRIX_TEST )
849 : definitelyIdentityMatrix=false;
850 : #endif
851 361526 : 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 1965444 : inline CMatrix4<T>& CMatrix4<T>::makeIdentity()
985 : {
986 1965444 : memset(M, 0, 16*sizeof(T));
987 1965444 : M[0] = M[5] = M[10] = M[15] = (T)1;
988 : #if defined ( USE_MATRIX_TEST )
989 : definitelyIdentityMatrix=true;
990 : #endif
991 1965444 : 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 53120 : inline void CMatrix4<T>::rotateVect( vector3df& vect ) const
1102 : {
1103 53120 : vector3df tmp = vect;
1104 53120 : vect.X = tmp.X*M[0] + tmp.Y*M[4] + tmp.Z*M[8];
1105 53120 : vect.Y = tmp.X*M[1] + tmp.Y*M[5] + tmp.Z*M[9];
1106 53120 : vect.Z = tmp.X*M[2] + tmp.Y*M[6] + tmp.Z*M[10];
1107 53120 : }
1108 :
1109 : //! An alternate transform vector method, writing into a second vector
1110 : template <class T>
1111 2332 : inline void CMatrix4<T>::rotateVect(core::vector3df& out, const core::vector3df& in) const
1112 : {
1113 2332 : out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
1114 2332 : out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
1115 2332 : out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
1116 2332 : }
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 1166 : inline void CMatrix4<T>::transformVect( vector3df& out, const vector3df& in) const
1152 : {
1153 1166 : out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
1154 1166 : out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
1155 1166 : out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
1156 1166 : }
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 52 : 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 52 : const f32 Amin[3] = {box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z};
1225 52 : const f32 Amax[3] = {box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z};
1226 :
1227 : f32 Bmin[3];
1228 : f32 Bmax[3];
1229 :
1230 52 : Bmin[0] = Bmax[0] = M[12];
1231 52 : Bmin[1] = Bmax[1] = M[13];
1232 52 : Bmin[2] = Bmax[2] = M[14];
1233 :
1234 52 : const CMatrix4<T> &m = *this;
1235 :
1236 208 : for (u32 i = 0; i < 3; ++i)
1237 : {
1238 624 : for (u32 j = 0; j < 3; ++j)
1239 : {
1240 468 : const f32 a = m(j,i) * Amin[j];
1241 468 : const f32 b = m(j,i) * Amax[j];
1242 :
1243 468 : if (a < b)
1244 : {
1245 154 : Bmin[i] += a;
1246 154 : Bmax[i] += b;
1247 : }
1248 : else
1249 : {
1250 314 : Bmin[i] += b;
1251 314 : Bmax[i] += a;
1252 : }
1253 : }
1254 : }
1255 :
1256 52 : box.MinEdge.X = Bmin[0];
1257 52 : box.MinEdge.Y = Bmin[1];
1258 52 : box.MinEdge.Z = Bmin[2];
1259 :
1260 52 : box.MaxEdge.X = Bmax[0];
1261 52 : box.MaxEdge.Y = Bmax[1];
1262 52 : box.MaxEdge.Z = Bmax[2];
1263 52 : }
1264 :
1265 :
1266 : //! Multiplies this matrix by a 1x4 matrix
1267 : template <class T>
1268 0 : 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 0 : mat[0] = matrix[0];
1279 0 : mat[1] = matrix[1];
1280 0 : mat[2] = matrix[2];
1281 0 : mat[3] = matrix[3];
1282 :
1283 0 : matrix[0] = M[0]*mat[0] + M[4]*mat[1] + M[8]*mat[2] + M[12]*mat[3];
1284 0 : matrix[1] = M[1]*mat[0] + M[5]*mat[1] + M[9]*mat[2] + M[13]*mat[3];
1285 0 : matrix[2] = M[2]*mat[0] + M[6]*mat[1] + M[10]*mat[2] + M[14]*mat[3];
1286 0 : matrix[3] = M[3]*mat[0] + M[7]*mat[1] + M[11]*mat[2] + M[15]*mat[3];
1287 0 : }
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 1426243 : 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 1426243 : const CMatrix4<T> &m = *this;
1321 :
1322 11409944 : 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 11409944 : (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 11409944 : (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 11409944 : (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 11409944 : (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 57049720 : (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 1426243 : if( core::iszero ( d, FLT_MIN ) )
1330 0 : return false;
1331 :
1332 1426243 : d = core::reciprocal ( d );
1333 :
1334 15688673 : out(0, 0) = d * (m(1, 1) * (m(2, 2) * m(3, 3) - m(2, 3) * m(3, 2)) +
1335 7131215 : m(1, 2) * (m(2, 3) * m(3, 1) - m(2, 1) * m(3, 3)) +
1336 7131215 : m(1, 3) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1)));
1337 15688673 : out(0, 1) = d * (m(2, 1) * (m(0, 2) * m(3, 3) - m(0, 3) * m(3, 2)) +
1338 7131215 : m(2, 2) * (m(0, 3) * m(3, 1) - m(0, 1) * m(3, 3)) +
1339 7131215 : m(2, 3) * (m(0, 1) * m(3, 2) - m(0, 2) * m(3, 1)));
1340 15688673 : out(0, 2) = d * (m(3, 1) * (m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) +
1341 7131215 : m(3, 2) * (m(0, 3) * m(1, 1) - m(0, 1) * m(1, 3)) +
1342 7131215 : m(3, 3) * (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)));
1343 15688673 : out(0, 3) = d * (m(0, 1) * (m(1, 3) * m(2, 2) - m(1, 2) * m(2, 3)) +
1344 7131215 : m(0, 2) * (m(1, 1) * m(2, 3) - m(1, 3) * m(2, 1)) +
1345 7131215 : m(0, 3) * (m(1, 2) * m(2, 1) - m(1, 1) * m(2, 2)));
1346 15688673 : out(1, 0) = d * (m(1, 2) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) +
1347 7131215 : m(1, 3) * (m(2, 2) * m(3, 0) - m(2, 0) * m(3, 2)) +
1348 7131215 : m(1, 0) * (m(2, 3) * m(3, 2) - m(2, 2) * m(3, 3)));
1349 15688673 : out(1, 1) = d * (m(2, 2) * (m(0, 0) * m(3, 3) - m(0, 3) * m(3, 0)) +
1350 7131215 : m(2, 3) * (m(0, 2) * m(3, 0) - m(0, 0) * m(3, 2)) +
1351 7131215 : m(2, 0) * (m(0, 3) * m(3, 2) - m(0, 2) * m(3, 3)));
1352 15688673 : out(1, 2) = d * (m(3, 2) * (m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) +
1353 7131215 : m(3, 3) * (m(0, 2) * m(1, 0) - m(0, 0) * m(1, 2)) +
1354 7131215 : m(3, 0) * (m(0, 3) * m(1, 2) - m(0, 2) * m(1, 3)));
1355 15688673 : out(1, 3) = d * (m(0, 2) * (m(1, 3) * m(2, 0) - m(1, 0) * m(2, 3)) +
1356 7131215 : m(0, 3) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) +
1357 7131215 : m(0, 0) * (m(1, 2) * m(2, 3) - m(1, 3) * m(2, 2)));
1358 15688673 : out(2, 0) = d * (m(1, 3) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0)) +
1359 7131215 : m(1, 0) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) +
1360 7131215 : m(1, 1) * (m(2, 3) * m(3, 0) - m(2, 0) * m(3, 3)));
1361 15688673 : out(2, 1) = d * (m(2, 3) * (m(0, 0) * m(3, 1) - m(0, 1) * m(3, 0)) +
1362 7131215 : m(2, 0) * (m(0, 1) * m(3, 3) - m(0, 3) * m(3, 1)) +
1363 7131215 : m(2, 1) * (m(0, 3) * m(3, 0) - m(0, 0) * m(3, 3)));
1364 15688673 : out(2, 2) = d * (m(3, 3) * (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) +
1365 7131215 : m(3, 0) * (m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) +
1366 7131215 : m(3, 1) * (m(0, 3) * m(1, 0) - m(0, 0) * m(1, 3)));
1367 15688673 : out(2, 3) = d * (m(0, 3) * (m(1, 1) * m(2, 0) - m(1, 0) * m(2, 1)) +
1368 7131215 : m(0, 0) * (m(1, 3) * m(2, 1) - m(1, 1) * m(2, 3)) +
1369 7131215 : m(0, 1) * (m(1, 0) * m(2, 3) - m(1, 3) * m(2, 0)));
1370 15688673 : out(3, 0) = d * (m(1, 0) * (m(2, 2) * m(3, 1) - m(2, 1) * m(3, 2)) +
1371 7131215 : m(1, 1) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) +
1372 7131215 : m(1, 2) * (m(2, 1) * m(3, 0) - m(2, 0) * m(3, 1)));
1373 15688673 : out(3, 1) = d * (m(2, 0) * (m(0, 2) * m(3, 1) - m(0, 1) * m(3, 2)) +
1374 7131215 : m(2, 1) * (m(0, 0) * m(3, 2) - m(0, 2) * m(3, 0)) +
1375 7131215 : m(2, 2) * (m(0, 1) * m(3, 0) - m(0, 0) * m(3, 1)));
1376 15688673 : out(3, 2) = d * (m(3, 0) * (m(0, 2) * m(1, 1) - m(0, 1) * m(1, 2)) +
1377 7131215 : m(3, 1) * (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) +
1378 7131215 : m(3, 2) * (m(0, 1) * m(1, 0) - m(0, 0) * m(1, 1)));
1379 15688673 : out(3, 3) = d * (m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) +
1380 7131215 : m(0, 1) * (m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2)) +
1381 7131215 : 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 1426243 : 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 1426078 : inline bool CMatrix4<T>::makeInverse()
1425 : {
1426 : #if defined ( USE_MATRIX_TEST )
1427 : if (definitelyIdentityMatrix)
1428 : return true;
1429 : #endif
1430 1426078 : CMatrix4<T> temp ( EM4CONST_NOTHING );
1431 :
1432 1426078 : if (getInverse(temp))
1433 : {
1434 1426078 : *this = temp;
1435 1426078 : return true;
1436 : }
1437 :
1438 0 : return false;
1439 : }
1440 :
1441 :
1442 : template <class T>
1443 11892038 : inline CMatrix4<T>& CMatrix4<T>::operator=(const CMatrix4<T> &other)
1444 : {
1445 11892038 : if (this==&other)
1446 0 : return *this;
1447 11892038 : memcpy(M, other.M, 16*sizeof(T));
1448 : #if defined ( USE_MATRIX_TEST )
1449 : definitelyIdentityMatrix=other.definitelyIdentityMatrix;
1450 : #endif
1451 11892038 : 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 0 : 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 0 : for (s32 i = 0; i < 16; ++i)
1476 0 : if (M[i] != other.M[i])
1477 0 : return false;
1478 :
1479 0 : return true;
1480 : }
1481 :
1482 :
1483 : template <class T>
1484 0 : inline bool CMatrix4<T>::operator!=(const CMatrix4<T> &other) const
1485 : {
1486 0 : 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 1 : 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 1 : M[0] = (T)(2/widthOfViewVolume);
1611 1 : M[1] = 0;
1612 1 : M[2] = 0;
1613 1 : M[3] = 0;
1614 :
1615 1 : M[4] = 0;
1616 1 : M[5] = (T)(2/heightOfViewVolume);
1617 1 : M[6] = 0;
1618 1 : M[7] = 0;
1619 :
1620 1 : M[8] = 0;
1621 1 : M[9] = 0;
1622 1 : M[10] = (T)(1/(zFar-zNear));
1623 1 : M[11] = 0;
1624 :
1625 1 : M[12] = 0;
1626 1 : M[13] = 0;
1627 1 : M[14] = (T)(zNear/(zNear-zFar));
1628 1 : M[15] = 1;
1629 :
1630 : #if defined ( USE_MATRIX_TEST )
1631 : definitelyIdentityMatrix=false;
1632 : #endif
1633 1 : 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 1426078 : inline CMatrix4<T> CMatrix4<T>::getTransposed() const
1875 : {
1876 1426078 : CMatrix4<T> t ( EM4CONST_NOTHING );
1877 1426078 : getTransposed ( t );
1878 1426078 : return t;
1879 : }
1880 :
1881 :
1882 : // returns transposed matrix
1883 : template <class T>
1884 1426078 : inline void CMatrix4<T>::getTransposed( CMatrix4<T>& o ) const
1885 : {
1886 1426078 : o[ 0] = M[ 0];
1887 1426078 : o[ 1] = M[ 4];
1888 1426078 : o[ 2] = M[ 8];
1889 1426078 : o[ 3] = M[12];
1890 :
1891 1426078 : o[ 4] = M[ 1];
1892 1426078 : o[ 5] = M[ 5];
1893 1426078 : o[ 6] = M[ 9];
1894 1426078 : o[ 7] = M[13];
1895 :
1896 1426078 : o[ 8] = M[ 2];
1897 1426078 : o[ 9] = M[ 6];
1898 1426078 : o[10] = M[10];
1899 1426078 : o[11] = M[14];
1900 :
1901 1426078 : o[12] = M[ 3];
1902 1426078 : o[13] = M[ 7];
1903 1426078 : o[14] = M[11];
1904 1426078 : o[15] = M[15];
1905 : #if defined ( USE_MATRIX_TEST )
1906 : o.definitelyIdentityMatrix=definitelyIdentityMatrix;
1907 : #endif
1908 1426078 : }
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 53120 : inline CMatrix4<T>& CMatrix4<T>::buildRotateFromTo(const core::vector3df& from, const core::vector3df& to)
1935 : {
1936 : // unit vectors
1937 53120 : core::vector3df f(from);
1938 53120 : core::vector3df t(to);
1939 53120 : f.normalize();
1940 53120 : t.normalize();
1941 :
1942 : // axis multiplication by sin
1943 53120 : core::vector3df vs(t.crossProduct(f));
1944 :
1945 : // axis of rotation
1946 53120 : core::vector3df v(vs);
1947 53120 : v.normalize();
1948 :
1949 : // cosinus angle
1950 53120 : T ca = f.dotProduct(t);
1951 :
1952 53120 : core::vector3df vt(v * (1 - ca));
1953 :
1954 53120 : M[0] = vt.X * v.X + ca;
1955 53120 : M[5] = vt.Y * v.Y + ca;
1956 53120 : M[10] = vt.Z * v.Z + ca;
1957 :
1958 53120 : vt.X *= v.Y;
1959 53120 : vt.Z *= v.X;
1960 53120 : vt.Y *= v.Z;
1961 :
1962 53120 : M[1] = vt.X - vs.Z;
1963 53120 : M[2] = vt.Z + vs.Y;
1964 53120 : M[3] = 0;
1965 :
1966 53120 : M[4] = vt.X + vs.Z;
1967 53120 : M[6] = vt.Y - vs.X;
1968 53120 : M[7] = 0;
1969 :
1970 53120 : M[8] = vt.Z - vs.Y;
1971 53120 : M[9] = vt.Y + vs.X;
1972 53120 : M[11] = 0;
1973 :
1974 53120 : M[12] = 0;
1975 53120 : M[13] = 0;
1976 53120 : M[14] = 0;
1977 53120 : M[15] = 1;
1978 :
1979 53120 : 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 0 : inline CMatrix4<T>& CMatrix4<T>::setTextureTranslate ( f32 x, f32 y )
2123 : {
2124 0 : M[8] = (T)x;
2125 0 : M[9] = (T)y;
2126 :
2127 : #if defined ( USE_MATRIX_TEST )
2128 : definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f);
2129 : #endif
2130 0 : 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 0 : inline CMatrix4<T>& CMatrix4<T>::setTextureScale ( f32 sx, f32 sy )
2148 : {
2149 0 : M[0] = (T)sx;
2150 0 : M[5] = (T)sy;
2151 : #if defined ( USE_MATRIX_TEST )
2152 : definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
2153 : #endif
2154 0 : 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 :
|