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 {
MatrixTestMatrixTest28 	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.
operator()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.
operator()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
pointer()99 			const T* pointer() const { return M; }
pointer()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
setScale(const T 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>
CMatrix4(eConstructor constructor)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>
CMatrix4(const CMatrix4<T> & other,eConstructor constructor)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>
setbyproduct_nocheck(const CMatrix4<T> & other_a,const CMatrix4<T> & other_b)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>
setbyproduct(const CMatrix4<T> & other_a,const CMatrix4<T> & other_b)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>
getTranslation()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>
setTranslation(const vector3d<T> & translation)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>
setInverseTranslation(const vector3d<T> & translation)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>
setScale(const vector3d<T> & scale)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>
getScale()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>
setRotationDegrees(const vector3d<T> & rotation)813 	inline CMatrix4<T>& CMatrix4<T>::setRotationDegrees( const vector3d<T>& rotation )
814 	{
815 		return setRotationRadians( rotation * core::DEGTORAD );
816 	}
817 
818 	template <class T>
setInverseRotationDegrees(const vector3d<T> & rotation)819 	inline CMatrix4<T>& CMatrix4<T>::setInverseRotationDegrees( const vector3d<T>& rotation )
820 	{
821 		return setInverseRotationRadians( rotation * core::DEGTORAD );
822 	}
823 
824 	template <class T>
setRotationRadians(const vector3d<T> & rotation)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>
getRotationDegrees()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>
setInverseRotationRadians(const vector3d<T> & rotation)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>
setRotationAxisRadians(const T & angle,const vector3d<T> & axis)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>
makeIdentity()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>
isIdentity()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>
isOrthogonal()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>
isIdentity_integer_base()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>
rotateVect(vector3df & vect)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>
rotateVect(core::vector3df & out,const core::vector3df & in)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>
rotateVect(T * out,const core::vector3df & in)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>
inverseRotateVect(vector3df & vect)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>
transformVect(vector3df & vect)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>
transformVect(vector3df & out,const vector3df & in)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>
transformVect(T * out,const core::vector3df & in)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>
transformVec3(T * out,const T * in)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>
transformPlane(core::plane3d<f32> & plane)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>
transformPlane(const core::plane3d<f32> & in,core::plane3d<f32> & out)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 the edge-points of a bounding box
1202 	//! Deprecated as it's usually not what people need (regards only 2 corners, but other corners might be outside the box after transformation)
1203 	//! Use transformBoxEx instead.
1204 	template <class T>
transformBox(core::aabbox3d<f32> & box)1205 	_IRR_DEPRECATED_ inline void CMatrix4<T>::transformBox(core::aabbox3d<f32>& box) const
1206 	{
1207 #if defined ( USE_MATRIX_TEST )
1208 		if (isIdentity())
1209 			return;
1210 #endif
1211 
1212 		transformVect(box.MinEdge);
1213 		transformVect(box.MaxEdge);
1214 		box.repair();
1215 	}
1216 
1217 	//! Transforms a axis aligned bounding box more accurately than transformBox()
1218 	template <class T>
transformBoxEx(core::aabbox3d<f32> & box)1219 	inline void CMatrix4<T>::transformBoxEx(core::aabbox3d<f32>& box) const
1220 	{
1221 #if defined ( USE_MATRIX_TEST )
1222 		if (isIdentity())
1223 			return;
1224 #endif
1225 
1226 		const f32 Amin[3] = {box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z};
1227 		const f32 Amax[3] = {box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z};
1228 
1229 		f32 Bmin[3];
1230 		f32 Bmax[3];
1231 
1232 		Bmin[0] = Bmax[0] = M[12];
1233 		Bmin[1] = Bmax[1] = M[13];
1234 		Bmin[2] = Bmax[2] = M[14];
1235 
1236 		const CMatrix4<T> &m = *this;
1237 
1238 		for (u32 i = 0; i < 3; ++i)
1239 		{
1240 			for (u32 j = 0; j < 3; ++j)
1241 			{
1242 				const f32 a = m(j,i) * Amin[j];
1243 				const f32 b = m(j,i) * Amax[j];
1244 
1245 				if (a < b)
1246 				{
1247 					Bmin[i] += a;
1248 					Bmax[i] += b;
1249 				}
1250 				else
1251 				{
1252 					Bmin[i] += b;
1253 					Bmax[i] += a;
1254 				}
1255 			}
1256 		}
1257 
1258 		box.MinEdge.X = Bmin[0];
1259 		box.MinEdge.Y = Bmin[1];
1260 		box.MinEdge.Z = Bmin[2];
1261 
1262 		box.MaxEdge.X = Bmax[0];
1263 		box.MaxEdge.Y = Bmax[1];
1264 		box.MaxEdge.Z = Bmax[2];
1265 	}
1266 
1267 
1268 	//! Multiplies this matrix by a 1x4 matrix
1269 	template <class T>
multiplyWith1x4Matrix(T * matrix)1270 	inline void CMatrix4<T>::multiplyWith1x4Matrix(T* matrix) const
1271 	{
1272 		/*
1273 		0  1  2  3
1274 		4  5  6  7
1275 		8  9  10 11
1276 		12 13 14 15
1277 		*/
1278 
1279 		T mat[4];
1280 		mat[0] = matrix[0];
1281 		mat[1] = matrix[1];
1282 		mat[2] = matrix[2];
1283 		mat[3] = matrix[3];
1284 
1285 		matrix[0] = M[0]*mat[0] + M[4]*mat[1] + M[8]*mat[2] + M[12]*mat[3];
1286 		matrix[1] = M[1]*mat[0] + M[5]*mat[1] + M[9]*mat[2] + M[13]*mat[3];
1287 		matrix[2] = M[2]*mat[0] + M[6]*mat[1] + M[10]*mat[2] + M[14]*mat[3];
1288 		matrix[3] = M[3]*mat[0] + M[7]*mat[1] + M[11]*mat[2] + M[15]*mat[3];
1289 	}
1290 
1291 	template <class T>
inverseTranslateVect(vector3df & vect)1292 	inline void CMatrix4<T>::inverseTranslateVect( vector3df& vect ) const
1293 	{
1294 		vect.X = vect.X-M[12];
1295 		vect.Y = vect.Y-M[13];
1296 		vect.Z = vect.Z-M[14];
1297 	}
1298 
1299 	template <class T>
translateVect(vector3df & vect)1300 	inline void CMatrix4<T>::translateVect( vector3df& vect ) const
1301 	{
1302 		vect.X = vect.X+M[12];
1303 		vect.Y = vect.Y+M[13];
1304 		vect.Z = vect.Z+M[14];
1305 	}
1306 
1307 
1308 	template <class T>
getInverse(CMatrix4<T> & out)1309 	inline bool CMatrix4<T>::getInverse(CMatrix4<T>& out) const
1310 	{
1311 		/// Calculates the inverse of this Matrix
1312 		/// The inverse is calculated using Cramers rule.
1313 		/// If no inverse exists then 'false' is returned.
1314 
1315 #if defined ( USE_MATRIX_TEST )
1316 		if ( this->isIdentity() )
1317 		{
1318 			out=*this;
1319 			return true;
1320 		}
1321 #endif
1322 		const CMatrix4<T> &m = *this;
1323 
1324 		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)) -
1325 			(m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) +
1326 			(m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1)) +
1327 			(m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) -
1328 			(m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) +
1329 			(m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0));
1330 
1331 		if( core::iszero ( d, FLT_MIN ) )
1332 			return false;
1333 
1334 		d = core::reciprocal ( d );
1335 
1336 		out(0, 0) = d * (m(1, 1) * (m(2, 2) * m(3, 3) - m(2, 3) * m(3, 2)) +
1337 				m(1, 2) * (m(2, 3) * m(3, 1) - m(2, 1) * m(3, 3)) +
1338 				m(1, 3) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1)));
1339 		out(0, 1) = d * (m(2, 1) * (m(0, 2) * m(3, 3) - m(0, 3) * m(3, 2)) +
1340 				m(2, 2) * (m(0, 3) * m(3, 1) - m(0, 1) * m(3, 3)) +
1341 				m(2, 3) * (m(0, 1) * m(3, 2) - m(0, 2) * m(3, 1)));
1342 		out(0, 2) = d * (m(3, 1) * (m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) +
1343 				m(3, 2) * (m(0, 3) * m(1, 1) - m(0, 1) * m(1, 3)) +
1344 				m(3, 3) * (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)));
1345 		out(0, 3) = d * (m(0, 1) * (m(1, 3) * m(2, 2) - m(1, 2) * m(2, 3)) +
1346 				m(0, 2) * (m(1, 1) * m(2, 3) - m(1, 3) * m(2, 1)) +
1347 				m(0, 3) * (m(1, 2) * m(2, 1) - m(1, 1) * m(2, 2)));
1348 		out(1, 0) = d * (m(1, 2) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) +
1349 				m(1, 3) * (m(2, 2) * m(3, 0) - m(2, 0) * m(3, 2)) +
1350 				m(1, 0) * (m(2, 3) * m(3, 2) - m(2, 2) * m(3, 3)));
1351 		out(1, 1) = d * (m(2, 2) * (m(0, 0) * m(3, 3) - m(0, 3) * m(3, 0)) +
1352 				m(2, 3) * (m(0, 2) * m(3, 0) - m(0, 0) * m(3, 2)) +
1353 				m(2, 0) * (m(0, 3) * m(3, 2) - m(0, 2) * m(3, 3)));
1354 		out(1, 2) = d * (m(3, 2) * (m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) +
1355 				m(3, 3) * (m(0, 2) * m(1, 0) - m(0, 0) * m(1, 2)) +
1356 				m(3, 0) * (m(0, 3) * m(1, 2) - m(0, 2) * m(1, 3)));
1357 		out(1, 3) = d * (m(0, 2) * (m(1, 3) * m(2, 0) - m(1, 0) * m(2, 3)) +
1358 				m(0, 3) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) +
1359 				m(0, 0) * (m(1, 2) * m(2, 3) - m(1, 3) * m(2, 2)));
1360 		out(2, 0) = d * (m(1, 3) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0)) +
1361 				m(1, 0) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) +
1362 				m(1, 1) * (m(2, 3) * m(3, 0) - m(2, 0) * m(3, 3)));
1363 		out(2, 1) = d * (m(2, 3) * (m(0, 0) * m(3, 1) - m(0, 1) * m(3, 0)) +
1364 				m(2, 0) * (m(0, 1) * m(3, 3) - m(0, 3) * m(3, 1)) +
1365 				m(2, 1) * (m(0, 3) * m(3, 0) - m(0, 0) * m(3, 3)));
1366 		out(2, 2) = d * (m(3, 3) * (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) +
1367 				m(3, 0) * (m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) +
1368 				m(3, 1) * (m(0, 3) * m(1, 0) - m(0, 0) * m(1, 3)));
1369 		out(2, 3) = d * (m(0, 3) * (m(1, 1) * m(2, 0) - m(1, 0) * m(2, 1)) +
1370 				m(0, 0) * (m(1, 3) * m(2, 1) - m(1, 1) * m(2, 3)) +
1371 				m(0, 1) * (m(1, 0) * m(2, 3) - m(1, 3) * m(2, 0)));
1372 		out(3, 0) = d * (m(1, 0) * (m(2, 2) * m(3, 1) - m(2, 1) * m(3, 2)) +
1373 				m(1, 1) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) +
1374 				m(1, 2) * (m(2, 1) * m(3, 0) - m(2, 0) * m(3, 1)));
1375 		out(3, 1) = d * (m(2, 0) * (m(0, 2) * m(3, 1) - m(0, 1) * m(3, 2)) +
1376 				m(2, 1) * (m(0, 0) * m(3, 2) - m(0, 2) * m(3, 0)) +
1377 				m(2, 2) * (m(0, 1) * m(3, 0) - m(0, 0) * m(3, 1)));
1378 		out(3, 2) = d * (m(3, 0) * (m(0, 2) * m(1, 1) - m(0, 1) * m(1, 2)) +
1379 				m(3, 1) * (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) +
1380 				m(3, 2) * (m(0, 1) * m(1, 0) - m(0, 0) * m(1, 1)));
1381 		out(3, 3) = d * (m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) +
1382 				m(0, 1) * (m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2)) +
1383 				m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0)));
1384 
1385 #if defined ( USE_MATRIX_TEST )
1386 		out.definitelyIdentityMatrix = definitelyIdentityMatrix;
1387 #endif
1388 		return true;
1389 	}
1390 
1391 
1392 	//! Inverts a primitive matrix which only contains a translation and a rotation
1393 	//! \param out: where result matrix is written to.
1394 	template <class T>
getInversePrimitive(CMatrix4<T> & out)1395 	inline bool CMatrix4<T>::getInversePrimitive ( CMatrix4<T>& out ) const
1396 	{
1397 		out.M[0 ] = M[0];
1398 		out.M[1 ] = M[4];
1399 		out.M[2 ] = M[8];
1400 		out.M[3 ] = 0;
1401 
1402 		out.M[4 ] = M[1];
1403 		out.M[5 ] = M[5];
1404 		out.M[6 ] = M[9];
1405 		out.M[7 ] = 0;
1406 
1407 		out.M[8 ] = M[2];
1408 		out.M[9 ] = M[6];
1409 		out.M[10] = M[10];
1410 		out.M[11] = 0;
1411 
1412 		out.M[12] = (T)-(M[12]*M[0] + M[13]*M[1] + M[14]*M[2]);
1413 		out.M[13] = (T)-(M[12]*M[4] + M[13]*M[5] + M[14]*M[6]);
1414 		out.M[14] = (T)-(M[12]*M[8] + M[13]*M[9] + M[14]*M[10]);
1415 		out.M[15] = 1;
1416 
1417 #if defined ( USE_MATRIX_TEST )
1418 		out.definitelyIdentityMatrix = definitelyIdentityMatrix;
1419 #endif
1420 		return true;
1421 	}
1422 
1423 	/*!
1424 	*/
1425 	template <class T>
makeInverse()1426 	inline bool CMatrix4<T>::makeInverse()
1427 	{
1428 #if defined ( USE_MATRIX_TEST )
1429 		if (definitelyIdentityMatrix)
1430 			return true;
1431 #endif
1432 		CMatrix4<T> temp ( EM4CONST_NOTHING );
1433 
1434 		if (getInverse(temp))
1435 		{
1436 			*this = temp;
1437 			return true;
1438 		}
1439 
1440 		return false;
1441 	}
1442 
1443 
1444 	template <class T>
1445 	inline CMatrix4<T>& CMatrix4<T>::operator=(const CMatrix4<T> &other)
1446 	{
1447 		if (this==&other)
1448 			return *this;
1449 		memcpy(M, other.M, 16*sizeof(T));
1450 #if defined ( USE_MATRIX_TEST )
1451 		definitelyIdentityMatrix=other.definitelyIdentityMatrix;
1452 #endif
1453 		return *this;
1454 	}
1455 
1456 
1457 	template <class T>
1458 	inline CMatrix4<T>& CMatrix4<T>::operator=(const T& scalar)
1459 	{
1460 		for (s32 i = 0; i < 16; ++i)
1461 			M[i]=scalar;
1462 
1463 #if defined ( USE_MATRIX_TEST )
1464 		definitelyIdentityMatrix=false;
1465 #endif
1466 		return *this;
1467 	}
1468 
1469 
1470 	template <class T>
1471 	inline bool CMatrix4<T>::operator==(const CMatrix4<T> &other) const
1472 	{
1473 #if defined ( USE_MATRIX_TEST )
1474 		if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
1475 			return true;
1476 #endif
1477 		for (s32 i = 0; i < 16; ++i)
1478 			if (M[i] != other.M[i])
1479 				return false;
1480 
1481 		return true;
1482 	}
1483 
1484 
1485 	template <class T>
1486 	inline bool CMatrix4<T>::operator!=(const CMatrix4<T> &other) const
1487 	{
1488 		return !(*this == other);
1489 	}
1490 
1491 
1492 	// Builds a right-handed perspective projection matrix based on a field of view
1493 	template <class T>
buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians,f32 aspectRatio,f32 zNear,f32 zFar)1494 	inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovRH(
1495 			f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar)
1496 	{
1497 		const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
1498 		_IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
1499 		const T w = static_cast<T>(h / aspectRatio);
1500 
1501 		_IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
1502 		M[0] = w;
1503 		M[1] = 0;
1504 		M[2] = 0;
1505 		M[3] = 0;
1506 
1507 		M[4] = 0;
1508 		M[5] = (T)h;
1509 		M[6] = 0;
1510 		M[7] = 0;
1511 
1512 		M[8] = 0;
1513 		M[9] = 0;
1514 		M[10] = (T)(zFar/(zNear-zFar)); // DirectX version
1515 //		M[10] = (T)(zFar+zNear/(zNear-zFar)); // OpenGL version
1516 		M[11] = -1;
1517 
1518 		M[12] = 0;
1519 		M[13] = 0;
1520 		M[14] = (T)(zNear*zFar/(zNear-zFar)); // DirectX version
1521 //		M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar)); // OpenGL version
1522 		M[15] = 0;
1523 
1524 #if defined ( USE_MATRIX_TEST )
1525 		definitelyIdentityMatrix=false;
1526 #endif
1527 		return *this;
1528 	}
1529 
1530 
1531 	// Builds a left-handed perspective projection matrix based on a field of view
1532 	template <class T>
buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians,f32 aspectRatio,f32 zNear,f32 zFar)1533 	inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovLH(
1534 			f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar)
1535 	{
1536 		const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
1537 		_IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
1538 		const T w = static_cast<T>(h / aspectRatio);
1539 
1540 		_IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
1541 		M[0] = w;
1542 		M[1] = 0;
1543 		M[2] = 0;
1544 		M[3] = 0;
1545 
1546 		M[4] = 0;
1547 		M[5] = (T)h;
1548 		M[6] = 0;
1549 		M[7] = 0;
1550 
1551 		M[8] = 0;
1552 		M[9] = 0;
1553 		M[10] = (T)(zFar/(zFar-zNear));
1554 		M[11] = 1;
1555 
1556 		M[12] = 0;
1557 		M[13] = 0;
1558 		M[14] = (T)(-zNear*zFar/(zFar-zNear));
1559 		M[15] = 0;
1560 
1561 #if defined ( USE_MATRIX_TEST )
1562 		definitelyIdentityMatrix=false;
1563 #endif
1564 		return *this;
1565 	}
1566 
1567 
1568 	// Builds a left-handed perspective projection matrix based on a field of view, with far plane culling at infinity
1569 	template <class T>
buildProjectionMatrixPerspectiveFovInfinityLH(f32 fieldOfViewRadians,f32 aspectRatio,f32 zNear,f32 epsilon)1570 	inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovInfinityLH(
1571 			f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon)
1572 	{
1573 		const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
1574 		_IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
1575 		const T w = static_cast<T>(h / aspectRatio);
1576 
1577 		M[0] = w;
1578 		M[1] = 0;
1579 		M[2] = 0;
1580 		M[3] = 0;
1581 
1582 		M[4] = 0;
1583 		M[5] = (T)h;
1584 		M[6] = 0;
1585 		M[7] = 0;
1586 
1587 		M[8] = 0;
1588 		M[9] = 0;
1589 		M[10] = (T)(1.f-epsilon);
1590 		M[11] = 1;
1591 
1592 		M[12] = 0;
1593 		M[13] = 0;
1594 		M[14] = (T)(zNear*(epsilon-1.f));
1595 		M[15] = 0;
1596 
1597 #if defined ( USE_MATRIX_TEST )
1598 		definitelyIdentityMatrix=false;
1599 #endif
1600 		return *this;
1601 	}
1602 
1603 
1604 	// Builds a left-handed orthogonal projection matrix.
1605 	template <class T>
buildProjectionMatrixOrthoLH(f32 widthOfViewVolume,f32 heightOfViewVolume,f32 zNear,f32 zFar)1606 	inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoLH(
1607 			f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
1608 	{
1609 		_IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
1610 		_IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
1611 		_IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
1612 		M[0] = (T)(2/widthOfViewVolume);
1613 		M[1] = 0;
1614 		M[2] = 0;
1615 		M[3] = 0;
1616 
1617 		M[4] = 0;
1618 		M[5] = (T)(2/heightOfViewVolume);
1619 		M[6] = 0;
1620 		M[7] = 0;
1621 
1622 		M[8] = 0;
1623 		M[9] = 0;
1624 		M[10] = (T)(1/(zFar-zNear));
1625 		M[11] = 0;
1626 
1627 		M[12] = 0;
1628 		M[13] = 0;
1629 		M[14] = (T)(zNear/(zNear-zFar));
1630 		M[15] = 1;
1631 
1632 #if defined ( USE_MATRIX_TEST )
1633 		definitelyIdentityMatrix=false;
1634 #endif
1635 		return *this;
1636 	}
1637 
1638 
1639 	// Builds a right-handed orthogonal projection matrix.
1640 	template <class T>
buildProjectionMatrixOrthoRH(f32 widthOfViewVolume,f32 heightOfViewVolume,f32 zNear,f32 zFar)1641 	inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoRH(
1642 			f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
1643 	{
1644 		_IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
1645 		_IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
1646 		_IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
1647 		M[0] = (T)(2/widthOfViewVolume);
1648 		M[1] = 0;
1649 		M[2] = 0;
1650 		M[3] = 0;
1651 
1652 		M[4] = 0;
1653 		M[5] = (T)(2/heightOfViewVolume);
1654 		M[6] = 0;
1655 		M[7] = 0;
1656 
1657 		M[8] = 0;
1658 		M[9] = 0;
1659 		M[10] = (T)(1/(zNear-zFar));
1660 		M[11] = 0;
1661 
1662 		M[12] = 0;
1663 		M[13] = 0;
1664 		M[14] = (T)(zNear/(zNear-zFar));
1665 		M[15] = 1;
1666 
1667 #if defined ( USE_MATRIX_TEST )
1668 		definitelyIdentityMatrix=false;
1669 #endif
1670 		return *this;
1671 	}
1672 
1673 
1674 	// Builds a right-handed perspective projection matrix.
1675 	template <class T>
buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume,f32 heightOfViewVolume,f32 zNear,f32 zFar)1676 	inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveRH(
1677 			f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
1678 	{
1679 		_IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
1680 		_IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
1681 		_IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
1682 		M[0] = (T)(2*zNear/widthOfViewVolume);
1683 		M[1] = 0;
1684 		M[2] = 0;
1685 		M[3] = 0;
1686 
1687 		M[4] = 0;
1688 		M[5] = (T)(2*zNear/heightOfViewVolume);
1689 		M[6] = 0;
1690 		M[7] = 0;
1691 
1692 		M[8] = 0;
1693 		M[9] = 0;
1694 		M[10] = (T)(zFar/(zNear-zFar));
1695 		M[11] = -1;
1696 
1697 		M[12] = 0;
1698 		M[13] = 0;
1699 		M[14] = (T)(zNear*zFar/(zNear-zFar));
1700 		M[15] = 0;
1701 
1702 #if defined ( USE_MATRIX_TEST )
1703 		definitelyIdentityMatrix=false;
1704 #endif
1705 		return *this;
1706 	}
1707 
1708 
1709 	// Builds a left-handed perspective projection matrix.
1710 	template <class T>
buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume,f32 heightOfViewVolume,f32 zNear,f32 zFar)1711 	inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveLH(
1712 			f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar)
1713 	{
1714 		_IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
1715 		_IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
1716 		_IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
1717 		M[0] = (T)(2*zNear/widthOfViewVolume);
1718 		M[1] = 0;
1719 		M[2] = 0;
1720 		M[3] = 0;
1721 
1722 		M[4] = 0;
1723 		M[5] = (T)(2*zNear/heightOfViewVolume);
1724 		M[6] = 0;
1725 		M[7] = 0;
1726 
1727 		M[8] = 0;
1728 		M[9] = 0;
1729 		M[10] = (T)(zFar/(zFar-zNear));
1730 		M[11] = 1;
1731 
1732 		M[12] = 0;
1733 		M[13] = 0;
1734 		M[14] = (T)(zNear*zFar/(zNear-zFar));
1735 		M[15] = 0;
1736 #if defined ( USE_MATRIX_TEST )
1737 		definitelyIdentityMatrix=false;
1738 #endif
1739 		return *this;
1740 	}
1741 
1742 
1743 	// Builds a matrix that flattens geometry into a plane.
1744 	template <class T>
buildShadowMatrix(const core::vector3df & light,core::plane3df plane,f32 point)1745 	inline CMatrix4<T>& CMatrix4<T>::buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point)
1746 	{
1747 		plane.Normal.normalize();
1748 		const f32 d = plane.Normal.dotProduct(light);
1749 
1750 		M[ 0] = (T)(-plane.Normal.X * light.X + d);
1751 		M[ 1] = (T)(-plane.Normal.X * light.Y);
1752 		M[ 2] = (T)(-plane.Normal.X * light.Z);
1753 		M[ 3] = (T)(-plane.Normal.X * point);
1754 
1755 		M[ 4] = (T)(-plane.Normal.Y * light.X);
1756 		M[ 5] = (T)(-plane.Normal.Y * light.Y + d);
1757 		M[ 6] = (T)(-plane.Normal.Y * light.Z);
1758 		M[ 7] = (T)(-plane.Normal.Y * point);
1759 
1760 		M[ 8] = (T)(-plane.Normal.Z * light.X);
1761 		M[ 9] = (T)(-plane.Normal.Z * light.Y);
1762 		M[10] = (T)(-plane.Normal.Z * light.Z + d);
1763 		M[11] = (T)(-plane.Normal.Z * point);
1764 
1765 		M[12] = (T)(-plane.D * light.X);
1766 		M[13] = (T)(-plane.D * light.Y);
1767 		M[14] = (T)(-plane.D * light.Z);
1768 		M[15] = (T)(-plane.D * point + d);
1769 #if defined ( USE_MATRIX_TEST )
1770 		definitelyIdentityMatrix=false;
1771 #endif
1772 		return *this;
1773 	}
1774 
1775 	// Builds a left-handed look-at matrix.
1776 	template <class T>
buildCameraLookAtMatrixLH(const vector3df & position,const vector3df & target,const vector3df & upVector)1777 	inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixLH(
1778 				const vector3df& position,
1779 				const vector3df& target,
1780 				const vector3df& upVector)
1781 	{
1782 		vector3df zaxis = target - position;
1783 		zaxis.normalize();
1784 
1785 		vector3df xaxis = upVector.crossProduct(zaxis);
1786 		xaxis.normalize();
1787 
1788 		vector3df yaxis = zaxis.crossProduct(xaxis);
1789 
1790 		M[0] = (T)xaxis.X;
1791 		M[1] = (T)yaxis.X;
1792 		M[2] = (T)zaxis.X;
1793 		M[3] = 0;
1794 
1795 		M[4] = (T)xaxis.Y;
1796 		M[5] = (T)yaxis.Y;
1797 		M[6] = (T)zaxis.Y;
1798 		M[7] = 0;
1799 
1800 		M[8] = (T)xaxis.Z;
1801 		M[9] = (T)yaxis.Z;
1802 		M[10] = (T)zaxis.Z;
1803 		M[11] = 0;
1804 
1805 		M[12] = (T)-xaxis.dotProduct(position);
1806 		M[13] = (T)-yaxis.dotProduct(position);
1807 		M[14] = (T)-zaxis.dotProduct(position);
1808 		M[15] = 1;
1809 #if defined ( USE_MATRIX_TEST )
1810 		definitelyIdentityMatrix=false;
1811 #endif
1812 		return *this;
1813 	}
1814 
1815 
1816 	// Builds a right-handed look-at matrix.
1817 	template <class T>
buildCameraLookAtMatrixRH(const vector3df & position,const vector3df & target,const vector3df & upVector)1818 	inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixRH(
1819 				const vector3df& position,
1820 				const vector3df& target,
1821 				const vector3df& upVector)
1822 	{
1823 		vector3df zaxis = position - target;
1824 		zaxis.normalize();
1825 
1826 		vector3df xaxis = upVector.crossProduct(zaxis);
1827 		xaxis.normalize();
1828 
1829 		vector3df yaxis = zaxis.crossProduct(xaxis);
1830 
1831 		M[0] = (T)xaxis.X;
1832 		M[1] = (T)yaxis.X;
1833 		M[2] = (T)zaxis.X;
1834 		M[3] = 0;
1835 
1836 		M[4] = (T)xaxis.Y;
1837 		M[5] = (T)yaxis.Y;
1838 		M[6] = (T)zaxis.Y;
1839 		M[7] = 0;
1840 
1841 		M[8] = (T)xaxis.Z;
1842 		M[9] = (T)yaxis.Z;
1843 		M[10] = (T)zaxis.Z;
1844 		M[11] = 0;
1845 
1846 		M[12] = (T)-xaxis.dotProduct(position);
1847 		M[13] = (T)-yaxis.dotProduct(position);
1848 		M[14] = (T)-zaxis.dotProduct(position);
1849 		M[15] = 1;
1850 #if defined ( USE_MATRIX_TEST )
1851 		definitelyIdentityMatrix=false;
1852 #endif
1853 		return *this;
1854 	}
1855 
1856 
1857 	// creates a new matrix as interpolated matrix from this and the passed one.
1858 	template <class T>
interpolate(const core::CMatrix4<T> & b,f32 time)1859 	inline CMatrix4<T> CMatrix4<T>::interpolate(const core::CMatrix4<T>& b, f32 time) const
1860 	{
1861 		CMatrix4<T> mat ( EM4CONST_NOTHING );
1862 
1863 		for (u32 i=0; i < 16; i += 4)
1864 		{
1865 			mat.M[i+0] = (T)(M[i+0] + ( b.M[i+0] - M[i+0] ) * time);
1866 			mat.M[i+1] = (T)(M[i+1] + ( b.M[i+1] - M[i+1] ) * time);
1867 			mat.M[i+2] = (T)(M[i+2] + ( b.M[i+2] - M[i+2] ) * time);
1868 			mat.M[i+3] = (T)(M[i+3] + ( b.M[i+3] - M[i+3] ) * time);
1869 		}
1870 		return mat;
1871 	}
1872 
1873 
1874 	// returns transposed matrix
1875 	template <class T>
getTransposed()1876 	inline CMatrix4<T> CMatrix4<T>::getTransposed() const
1877 	{
1878 		CMatrix4<T> t ( EM4CONST_NOTHING );
1879 		getTransposed ( t );
1880 		return t;
1881 	}
1882 
1883 
1884 	// returns transposed matrix
1885 	template <class T>
getTransposed(CMatrix4<T> & o)1886 	inline void CMatrix4<T>::getTransposed( CMatrix4<T>& o ) const
1887 	{
1888 		o[ 0] = M[ 0];
1889 		o[ 1] = M[ 4];
1890 		o[ 2] = M[ 8];
1891 		o[ 3] = M[12];
1892 
1893 		o[ 4] = M[ 1];
1894 		o[ 5] = M[ 5];
1895 		o[ 6] = M[ 9];
1896 		o[ 7] = M[13];
1897 
1898 		o[ 8] = M[ 2];
1899 		o[ 9] = M[ 6];
1900 		o[10] = M[10];
1901 		o[11] = M[14];
1902 
1903 		o[12] = M[ 3];
1904 		o[13] = M[ 7];
1905 		o[14] = M[11];
1906 		o[15] = M[15];
1907 #if defined ( USE_MATRIX_TEST )
1908 		o.definitelyIdentityMatrix=definitelyIdentityMatrix;
1909 #endif
1910 	}
1911 
1912 
1913 	// used to scale <-1,-1><1,1> to viewport
1914 	template <class T>
buildNDCToDCMatrix(const core::rect<s32> & viewport,f32 zScale)1915 	inline CMatrix4<T>& CMatrix4<T>::buildNDCToDCMatrix( const core::rect<s32>& viewport, f32 zScale)
1916 	{
1917 		const f32 scaleX = (viewport.getWidth() - 0.75f ) * 0.5f;
1918 		const f32 scaleY = -(viewport.getHeight() - 0.75f ) * 0.5f;
1919 
1920 		const f32 dx = -0.5f + ( (viewport.UpperLeftCorner.X + viewport.LowerRightCorner.X ) * 0.5f );
1921 		const f32 dy = -0.5f + ( (viewport.UpperLeftCorner.Y + viewport.LowerRightCorner.Y ) * 0.5f );
1922 
1923 		makeIdentity();
1924 		M[12] = (T)dx;
1925 		M[13] = (T)dy;
1926 		return setScale(core::vector3d<T>((T)scaleX, (T)scaleY, (T)zScale));
1927 	}
1928 
1929 	//! Builds a matrix that rotates from one vector to another
1930 	/** \param from: vector to rotate from
1931 	\param to: vector to rotate to
1932 
1933 		http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/index.htm
1934 	 */
1935 	template <class T>
buildRotateFromTo(const core::vector3df & from,const core::vector3df & to)1936 	inline CMatrix4<T>& CMatrix4<T>::buildRotateFromTo(const core::vector3df& from, const core::vector3df& to)
1937 	{
1938 		// unit vectors
1939 		core::vector3df f(from);
1940 		core::vector3df t(to);
1941 		f.normalize();
1942 		t.normalize();
1943 
1944 		// axis multiplication by sin
1945 		core::vector3df vs(t.crossProduct(f));
1946 
1947 		// axis of rotation
1948 		core::vector3df v(vs);
1949 		v.normalize();
1950 
1951 		// cosinus angle
1952 		T ca = f.dotProduct(t);
1953 
1954 		core::vector3df vt(v * (1 - ca));
1955 
1956 		M[0] = vt.X * v.X + ca;
1957 		M[5] = vt.Y * v.Y + ca;
1958 		M[10] = vt.Z * v.Z + ca;
1959 
1960 		vt.X *= v.Y;
1961 		vt.Z *= v.X;
1962 		vt.Y *= v.Z;
1963 
1964 		M[1] = vt.X - vs.Z;
1965 		M[2] = vt.Z + vs.Y;
1966 		M[3] = 0;
1967 
1968 		M[4] = vt.X + vs.Z;
1969 		M[6] = vt.Y - vs.X;
1970 		M[7] = 0;
1971 
1972 		M[8] = vt.Z - vs.Y;
1973 		M[9] = vt.Y + vs.X;
1974 		M[11] = 0;
1975 
1976 		M[12] = 0;
1977 		M[13] = 0;
1978 		M[14] = 0;
1979 		M[15] = 1;
1980 
1981 		return *this;
1982 	}
1983 
1984 	//! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis
1985 	/** \param camPos: viewer position in world coord
1986 	\param center: object position in world-coord, rotation pivot
1987 	\param translation: object final translation from center
1988 	\param axis: axis to rotate about
1989 	\param from: source vector to rotate from
1990 	 */
1991 	template <class T>
buildAxisAlignedBillboard(const core::vector3df & camPos,const core::vector3df & center,const core::vector3df & translation,const core::vector3df & axis,const core::vector3df & from)1992 	inline void CMatrix4<T>::buildAxisAlignedBillboard(
1993 				const core::vector3df& camPos,
1994 				const core::vector3df& center,
1995 				const core::vector3df& translation,
1996 				const core::vector3df& axis,
1997 				const core::vector3df& from)
1998 	{
1999 		// axis of rotation
2000 		core::vector3df up = axis;
2001 		up.normalize();
2002 		const core::vector3df forward = (camPos - center).normalize();
2003 		const core::vector3df right = up.crossProduct(forward).normalize();
2004 
2005 		// correct look vector
2006 		const core::vector3df look = right.crossProduct(up);
2007 
2008 		// rotate from to
2009 		// axis multiplication by sin
2010 		const core::vector3df vs = look.crossProduct(from);
2011 
2012 		// cosinus angle
2013 		const f32 ca = from.dotProduct(look);
2014 
2015 		core::vector3df vt(up * (1.f - ca));
2016 
2017 		M[0] = static_cast<T>(vt.X * up.X + ca);
2018 		M[5] = static_cast<T>(vt.Y * up.Y + ca);
2019 		M[10] = static_cast<T>(vt.Z * up.Z + ca);
2020 
2021 		vt.X *= up.Y;
2022 		vt.Z *= up.X;
2023 		vt.Y *= up.Z;
2024 
2025 		M[1] = static_cast<T>(vt.X - vs.Z);
2026 		M[2] = static_cast<T>(vt.Z + vs.Y);
2027 		M[3] = 0;
2028 
2029 		M[4] = static_cast<T>(vt.X + vs.Z);
2030 		M[6] = static_cast<T>(vt.Y - vs.X);
2031 		M[7] = 0;
2032 
2033 		M[8] = static_cast<T>(vt.Z - vs.Y);
2034 		M[9] = static_cast<T>(vt.Y + vs.X);
2035 		M[11] = 0;
2036 
2037 		setRotationCenter(center, translation);
2038 	}
2039 
2040 
2041 	//! Builds a combined matrix which translate to a center before rotation and translate afterwards
2042 	template <class T>
setRotationCenter(const core::vector3df & center,const core::vector3df & translation)2043 	inline void CMatrix4<T>::setRotationCenter(const core::vector3df& center, const core::vector3df& translation)
2044 	{
2045 		M[12] = -M[0]*center.X - M[4]*center.Y - M[8]*center.Z + (center.X - translation.X );
2046 		M[13] = -M[1]*center.X - M[5]*center.Y - M[9]*center.Z + (center.Y - translation.Y );
2047 		M[14] = -M[2]*center.X - M[6]*center.Y - M[10]*center.Z + (center.Z - translation.Z );
2048 		M[15] = (T) 1.0;
2049 #if defined ( USE_MATRIX_TEST )
2050 		definitelyIdentityMatrix=false;
2051 #endif
2052 	}
2053 
2054 	/*!
2055 		Generate texture coordinates as linear functions so that:
2056 			u = Ux*x + Uy*y + Uz*z + Uw
2057 			v = Vx*x + Vy*y + Vz*z + Vw
2058 		The matrix M for this case is:
2059 			Ux  Vx  0  0
2060 			Uy  Vy  0  0
2061 			Uz  Vz  0  0
2062 			Uw  Vw  0  0
2063 	*/
2064 
2065 
2066 	template <class T>
buildTextureTransform(f32 rotateRad,const core::vector2df & rotatecenter,const core::vector2df & translate,const core::vector2df & scale)2067 	inline CMatrix4<T>& CMatrix4<T>::buildTextureTransform( f32 rotateRad,
2068 			const core::vector2df &rotatecenter,
2069 			const core::vector2df &translate,
2070 			const core::vector2df &scale)
2071 	{
2072 		const f32 c = cosf(rotateRad);
2073 		const f32 s = sinf(rotateRad);
2074 
2075 		M[0] = (T)(c * scale.X);
2076 		M[1] = (T)(s * scale.Y);
2077 		M[2] = 0;
2078 		M[3] = 0;
2079 
2080 		M[4] = (T)(-s * scale.X);
2081 		M[5] = (T)(c * scale.Y);
2082 		M[6] = 0;
2083 		M[7] = 0;
2084 
2085 		M[8] = (T)(c * scale.X * rotatecenter.X + -s * rotatecenter.Y + translate.X);
2086 		M[9] = (T)(s * scale.Y * rotatecenter.X +  c * rotatecenter.Y + translate.Y);
2087 		M[10] = 1;
2088 		M[11] = 0;
2089 
2090 		M[12] = 0;
2091 		M[13] = 0;
2092 		M[14] = 0;
2093 		M[15] = 1;
2094 #if defined ( USE_MATRIX_TEST )
2095 		definitelyIdentityMatrix=false;
2096 #endif
2097 		return *this;
2098 	}
2099 
2100 
2101 	// rotate about z axis, center ( 0.5, 0.5 )
2102 	template <class T>
setTextureRotationCenter(f32 rotateRad)2103 	inline CMatrix4<T>& CMatrix4<T>::setTextureRotationCenter( f32 rotateRad )
2104 	{
2105 		const f32 c = cosf(rotateRad);
2106 		const f32 s = sinf(rotateRad);
2107 		M[0] = (T)c;
2108 		M[1] = (T)s;
2109 
2110 		M[4] = (T)-s;
2111 		M[5] = (T)c;
2112 
2113 		M[8] = (T)(0.5f * ( s - c) + 0.5f);
2114 		M[9] = (T)(-0.5f * ( s + c) + 0.5f);
2115 
2116 #if defined ( USE_MATRIX_TEST )
2117 		definitelyIdentityMatrix = definitelyIdentityMatrix && (rotateRad==0.0f);
2118 #endif
2119 		return *this;
2120 	}
2121 
2122 
2123 	template <class T>
setTextureTranslate(f32 x,f32 y)2124 	inline CMatrix4<T>& CMatrix4<T>::setTextureTranslate ( f32 x, f32 y )
2125 	{
2126 		M[8] = (T)x;
2127 		M[9] = (T)y;
2128 
2129 #if defined ( USE_MATRIX_TEST )
2130 		definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f);
2131 #endif
2132 		return *this;
2133 	}
2134 
2135 
2136 	template <class T>
setTextureTranslateTransposed(f32 x,f32 y)2137 	inline CMatrix4<T>& CMatrix4<T>::setTextureTranslateTransposed ( f32 x, f32 y )
2138 	{
2139 		M[2] = (T)x;
2140 		M[6] = (T)y;
2141 
2142 #if defined ( USE_MATRIX_TEST )
2143 		definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f) ;
2144 #endif
2145 		return *this;
2146 	}
2147 
2148 	template <class T>
setTextureScale(f32 sx,f32 sy)2149 	inline CMatrix4<T>& CMatrix4<T>::setTextureScale ( f32 sx, f32 sy )
2150 	{
2151 		M[0] = (T)sx;
2152 		M[5] = (T)sy;
2153 #if defined ( USE_MATRIX_TEST )
2154 		definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
2155 #endif
2156 		return *this;
2157 	}
2158 
2159 
2160 	template <class T>
setTextureScaleCenter(f32 sx,f32 sy)2161 	inline CMatrix4<T>& CMatrix4<T>::setTextureScaleCenter( f32 sx, f32 sy )
2162 	{
2163 		M[0] = (T)sx;
2164 		M[5] = (T)sy;
2165 		M[8] = (T)(0.5f - 0.5f * sx);
2166 		M[9] = (T)(0.5f - 0.5f * sy);
2167 
2168 #if defined ( USE_MATRIX_TEST )
2169 		definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
2170 #endif
2171 		return *this;
2172 	}
2173 
2174 
2175 	// sets all matrix data members at once
2176 	template <class T>
setM(const T * data)2177 	inline CMatrix4<T>& CMatrix4<T>::setM(const T* data)
2178 	{
2179 		memcpy(M,data, 16*sizeof(T));
2180 
2181 #if defined ( USE_MATRIX_TEST )
2182 		definitelyIdentityMatrix=false;
2183 #endif
2184 		return *this;
2185 	}
2186 
2187 
2188 	// sets if the matrix is definitely identity matrix
2189 	template <class T>
setDefinitelyIdentityMatrix(bool isDefinitelyIdentityMatrix)2190 	inline void CMatrix4<T>::setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix)
2191 	{
2192 #if defined ( USE_MATRIX_TEST )
2193 		definitelyIdentityMatrix = isDefinitelyIdentityMatrix;
2194 #endif
2195 	}
2196 
2197 
2198 	// gets if the matrix is definitely identity matrix
2199 	template <class T>
getDefinitelyIdentityMatrix()2200 	inline bool CMatrix4<T>::getDefinitelyIdentityMatrix() const
2201 	{
2202 #if defined ( USE_MATRIX_TEST )
2203 		return definitelyIdentityMatrix;
2204 #else
2205 		return false;
2206 #endif
2207 	}
2208 
2209 
2210 	//! Compare two matrices using the equal method
2211 	template <class T>
equals(const core::CMatrix4<T> & other,const T tolerance)2212 	inline bool CMatrix4<T>::equals(const core::CMatrix4<T>& other, const T tolerance) const
2213 	{
2214 #if defined ( USE_MATRIX_TEST )
2215 		if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
2216 			return true;
2217 #endif
2218 		for (s32 i = 0; i < 16; ++i)
2219 			if (!core::equals(M[i],other.M[i], tolerance))
2220 				return false;
2221 
2222 		return true;
2223 	}
2224 
2225 
2226 	// Multiply by scalar.
2227 	template <class T>
2228 	inline CMatrix4<T> operator*(const T scalar, const CMatrix4<T>& mat)
2229 	{
2230 		return mat*scalar;
2231 	}
2232 
2233 
2234 	//! Typedef for f32 matrix
2235 	typedef CMatrix4<f32> matrix4;
2236 
2237 	//! global const identity matrix
2238 	IRRLICHT_API extern const matrix4 IdentityMatrix;
2239 
2240 } // end namespace core
2241 } // end namespace irr
2242 
2243 #endif
2244 
2245