1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
5 #ifndef __IRR_MATRIX_H_INCLUDED__
\r
6 #define __IRR_MATRIX_H_INCLUDED__
\r
9 #include "vector3d.h"
\r
10 #include "vector2d.h"
\r
11 #include "plane3d.h"
\r
12 #include "aabbox3d.h"
\r
14 #include "irrString.h"
\r
16 // enable this to keep track of changes to the matrix
\r
17 // and make simpler identity check for seldom changing matrices
\r
18 // otherwise identity check will always compare the elements
\r
19 //#define USE_MATRIX_TEST
\r
21 // this is only for debugging purposes
\r
22 //#define USE_MATRIX_TEST_DEBUG
\r
24 #if defined( USE_MATRIX_TEST_DEBUG )
\r
28 MatrixTest () : ID(0), Calls(0) {}
\r
33 static MatrixTest MTest;
\r
42 //! 4x4 matrix. Mostly used as transformation matrix for 3d calculations.
\r
43 /** The matrix is a D3D style matrix, row major with translations in the 4th row. */
\r
49 //! Constructor Flags
\r
52 EM4CONST_NOTHING = 0,
\r
55 EM4CONST_TRANSPOSED,
\r
57 EM4CONST_INVERSE_TRANSPOSED
\r
60 //! Default constructor
\r
61 /** \param constructor Choose the initialization style */
\r
62 CMatrix4( eConstructor constructor = EM4CONST_IDENTITY );
\r
64 //! Constructor with value initialization
\r
65 CMatrix4(const T& r0c0, const T& r0c1, const T& r0c2, const T& r0c3,
\r
66 const T& r1c0, const T& r1c1, const T& r1c2, const T& r1c3,
\r
67 const T& r2c0, const T& r2c1, const T& r2c2, const T& r2c3,
\r
68 const T& r3c0, const T& r3c1, const T& r3c2, const T& r3c3)
\r
70 M[0] = r0c0; M[1] = r0c1; M[2] = r0c2; M[3] = r0c3;
\r
71 M[4] = r1c0; M[5] = r1c1; M[6] = r1c2; M[7] = r1c3;
\r
72 M[8] = r2c0; M[9] = r2c1; M[10] = r2c2; M[11] = r2c3;
\r
73 M[12] = r3c0; M[13] = r3c1; M[14] = r3c2; M[15] = r3c3;
\r
76 //! Copy constructor
\r
77 /** \param other Other matrix to copy from
\r
78 \param constructor Choose the initialization style */
\r
79 CMatrix4(const CMatrix4<T>& other, eConstructor constructor = EM4CONST_COPY);
\r
81 //! Simple operator for directly accessing every element of the matrix.
\r
82 T& operator()(const s32 row, const s32 col)
\r
84 #if defined ( USE_MATRIX_TEST )
\r
85 definitelyIdentityMatrix=false;
\r
87 return M[ row * 4 + col ];
\r
90 //! Simple operator for directly accessing every element of the matrix.
\r
91 const T& operator()(const s32 row, const s32 col) const { return M[row * 4 + col]; }
\r
93 //! Simple operator for linearly accessing every element of the matrix.
\r
94 T& operator[](u32 index)
\r
96 #if defined ( USE_MATRIX_TEST )
\r
97 definitelyIdentityMatrix=false;
\r
102 //! Simple operator for linearly accessing every element of the matrix.
\r
103 const T& operator[](u32 index) const { return M[index]; }
\r
105 //! Sets this matrix equal to the other matrix.
\r
106 CMatrix4<T>& operator=(const CMatrix4<T> &other) = default;
\r
108 //! Sets all elements of this matrix to the value.
\r
109 inline CMatrix4<T>& operator=(const T& scalar);
\r
111 //! Returns pointer to internal array
\r
112 const T* pointer() const { return M; }
\r
115 #if defined ( USE_MATRIX_TEST )
\r
116 definitelyIdentityMatrix=false;
\r
121 //! Returns true if other matrix is equal to this matrix.
\r
122 bool operator==(const CMatrix4<T> &other) const;
\r
124 //! Returns true if other matrix is not equal to this matrix.
\r
125 bool operator!=(const CMatrix4<T> &other) const;
\r
127 //! Add another matrix.
\r
128 CMatrix4<T> operator+(const CMatrix4<T>& other) const;
\r
130 //! Add another matrix.
\r
131 CMatrix4<T>& operator+=(const CMatrix4<T>& other);
\r
133 //! Subtract another matrix.
\r
134 CMatrix4<T> operator-(const CMatrix4<T>& other) const;
\r
136 //! Subtract another matrix.
\r
137 CMatrix4<T>& operator-=(const CMatrix4<T>& other);
\r
139 //! set this matrix to the product of two matrices
\r
140 /** Calculate b*a */
\r
141 inline CMatrix4<T>& setbyproduct(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b );
\r
143 //! Set this matrix to the product of two matrices
\r
144 /** Calculate b*a, no optimization used,
\r
145 use it if you know you never have a identity matrix */
\r
146 CMatrix4<T>& setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b );
\r
148 //! Multiply by another matrix.
\r
149 /** Calculate other*this */
\r
150 CMatrix4<T> operator*(const CMatrix4<T>& other) const;
\r
152 //! Multiply by another matrix.
\r
153 /** Calculate and return other*this */
\r
154 CMatrix4<T>& operator*=(const CMatrix4<T>& other);
\r
156 //! Multiply by scalar.
\r
157 CMatrix4<T> operator*(const T& scalar) const;
\r
159 //! Multiply by scalar.
\r
160 CMatrix4<T>& operator*=(const T& scalar);
\r
162 //! Set matrix to identity.
\r
163 inline CMatrix4<T>& makeIdentity();
\r
165 //! Returns true if the matrix is the identity matrix
\r
166 inline bool isIdentity() const;
\r
168 //! Returns true if the matrix is orthogonal
\r
169 inline bool isOrthogonal() const;
\r
171 //! Returns true if the matrix is the identity matrix
\r
172 bool isIdentity_integer_base () const;
\r
174 //! Set the translation of the current matrix. Will erase any previous values.
\r
175 CMatrix4<T>& setTranslation( const vector3d<T>& translation );
\r
177 //! Gets the current translation
\r
178 vector3d<T> getTranslation() const;
\r
180 //! Set the inverse translation of the current matrix. Will erase any previous values.
\r
181 CMatrix4<T>& setInverseTranslation( const vector3d<T>& translation );
\r
183 //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
\r
184 inline CMatrix4<T>& setRotationRadians( const vector3d<T>& rotation );
\r
186 //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
\r
187 CMatrix4<T>& setRotationDegrees( const vector3d<T>& rotation );
\r
189 //! Get the rotation, as set by setRotation() when you already know the scale.
\r
190 /** If you already know the scale then this function is faster than the other getRotationDegrees overload.
\r
191 NOTE: You will have the same end-rotation as used in setRotation, but it might not use the same axis values.
\r
193 core::vector3d<T> getRotationDegrees(const vector3d<T>& scale) const;
\r
195 //! Returns the rotation, as set by setRotation().
\r
196 /** NOTE: You will have the same end-rotation as used in setRotation, but it might not use the same axis values.
\r
198 core::vector3d<T> getRotationDegrees() const;
\r
200 //! Make an inverted rotation matrix from Euler angles.
\r
201 /** The 4th row and column are unmodified. */
\r
202 inline CMatrix4<T>& setInverseRotationRadians( const vector3d<T>& rotation );
\r
204 //! Make an inverted rotation matrix from Euler angles.
\r
205 /** The 4th row and column are unmodified. */
\r
206 inline CMatrix4<T>& setInverseRotationDegrees( const vector3d<T>& rotation );
\r
208 //! Make a rotation matrix from angle and axis, assuming left handed rotation.
\r
209 /** The 4th row and column are unmodified. */
\r
210 inline CMatrix4<T>& setRotationAxisRadians(const T& angle, const vector3d<T>& axis);
\r
213 CMatrix4<T>& setScale( const vector3d<T>& scale );
\r
216 CMatrix4<T>& setScale( const T scale ) { return setScale(core::vector3d<T>(scale,scale,scale)); }
\r
219 core::vector3d<T> getScale() const;
\r
221 //! Translate a vector by the inverse of the translation part of this matrix.
\r
222 void inverseTranslateVect( vector3df& vect ) const;
\r
224 //! Rotate a vector by the inverse of the rotation part of this matrix.
\r
225 void inverseRotateVect( vector3df& vect ) const;
\r
227 //! Rotate a vector by the rotation part of this matrix.
\r
228 void rotateVect( vector3df& vect ) const;
\r
230 //! An alternate transform vector method, writing into a second vector
\r
231 void rotateVect(core::vector3df& out, const core::vector3df& in) const;
\r
233 //! An alternate transform vector method, writing into an array of 3 floats
\r
234 void rotateVect(T *out,const core::vector3df &in) const;
\r
236 //! Transforms the vector by this matrix
\r
237 /** This operation is performed as if the vector was 4d with the 4th component =1 */
\r
238 void transformVect( vector3df& vect) const;
\r
240 //! Transforms input vector by this matrix and stores result in output vector
\r
241 /** This operation is performed as if the vector was 4d with the 4th component =1 */
\r
242 void transformVect( vector3df& out, const vector3df& in ) const;
\r
244 //! An alternate transform vector method, writing into an array of 4 floats
\r
245 /** This operation is performed as if the vector was 4d with the 4th component =1.
\r
246 NOTE: out[3] will be written to (4th vector component)*/
\r
247 void transformVect(T *out,const core::vector3df &in) const;
\r
249 //! An alternate transform vector method, reading from and writing to an array of 3 floats
\r
250 /** This operation is performed as if the vector was 4d with the 4th component =1
\r
251 NOTE: out[3] will be written to (4th vector component)*/
\r
252 void transformVec3(T *out, const T * in) const;
\r
254 //! An alternate transform vector method, reading from and writing to an array of 4 floats
\r
255 void transformVec4(T *out, const T * in) const;
\r
257 //! Translate a vector by the translation part of this matrix.
\r
258 /** This operation is performed as if the vector was 4d with the 4th component =1 */
\r
259 void translateVect( vector3df& vect ) const;
\r
261 //! Transforms a plane by this matrix
\r
262 void transformPlane( core::plane3d<f32> &plane) const;
\r
264 //! Transforms a plane by this matrix
\r
265 void transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const;
\r
267 //! Transforms a axis aligned bounding box
\r
268 /** The result box of this operation may not be accurate at all. For
\r
269 correct results, use transformBoxEx() */
\r
270 void transformBox(core::aabbox3d<f32>& box) const;
\r
272 //! Transforms a axis aligned bounding box
\r
273 /** The result box of this operation should be accurate, but this operation
\r
274 is slower than transformBox(). */
\r
275 void transformBoxEx(core::aabbox3d<f32>& box) const;
\r
277 //! Multiplies this matrix by a 1x4 matrix
\r
278 void multiplyWith1x4Matrix(T* matrix) const;
\r
280 //! Calculates inverse of matrix. Slow.
\r
281 /** \return Returns false if there is no inverse matrix.*/
\r
282 bool makeInverse();
\r
285 //! Inverts a primitive matrix which only contains a translation and a rotation
\r
286 /** \param out: where result matrix is written to. */
\r
287 bool getInversePrimitive ( CMatrix4<T>& out ) const;
\r
289 //! Gets the inverse matrix of this one
\r
290 /** \param out: where result matrix is written to.
\r
291 \return Returns false if there is no inverse matrix. */
\r
292 bool getInverse(CMatrix4<T>& out) const;
\r
294 //! Builds a right-handed perspective projection matrix based on a field of view
\r
295 //\param zClipFromZero: Clipping of z can be projected from 0 to w when true (D3D style) and from -w to w when false (OGL style).
\r
296 CMatrix4<T>& buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
298 //! Builds a left-handed perspective projection matrix based on a field of view
\r
299 CMatrix4<T>& buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
301 //! Builds a left-handed perspective projection matrix based on a field of view, with far plane at infinity
\r
302 CMatrix4<T>& buildProjectionMatrixPerspectiveFovInfinityLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon=0);
\r
304 //! Builds a right-handed perspective projection matrix.
\r
305 CMatrix4<T>& buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
307 //! Builds a left-handed perspective projection matrix.
\r
308 CMatrix4<T>& buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
310 //! Builds a left-handed orthogonal projection matrix.
\r
311 //\param zClipFromZero: Clipping of z can be projected from 0 to 1 when true (D3D style) and from -1 to 1 when false (OGL style).
\r
312 CMatrix4<T>& buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
314 //! Builds a right-handed orthogonal projection matrix.
\r
315 CMatrix4<T>& buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
317 //! Builds a left-handed look-at matrix.
\r
318 CMatrix4<T>& buildCameraLookAtMatrixLH(
\r
319 const vector3df& position,
\r
320 const vector3df& target,
\r
321 const vector3df& upVector);
\r
323 //! Builds a right-handed look-at matrix.
\r
324 CMatrix4<T>& buildCameraLookAtMatrixRH(
\r
325 const vector3df& position,
\r
326 const vector3df& target,
\r
327 const vector3df& upVector);
\r
329 //! Builds a matrix that flattens geometry into a plane.
\r
330 /** \param light: light source
\r
331 \param plane: plane into which the geometry if flattened into
\r
332 \param point: value between 0 and 1, describing the light source.
\r
333 If this is 1, it is a point light, if it is 0, it is a directional light. */
\r
334 CMatrix4<T>& buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point=1.0f);
\r
336 //! Builds a matrix which transforms a normalized Device Coordinate to Device Coordinates.
\r
337 /** Used to scale <-1,-1><1,1> to viewport, for example from <-1,-1> <1,1> to the viewport <0,0><0,640> */
\r
338 CMatrix4<T>& buildNDCToDCMatrix( const core::rect<s32>& area, f32 zScale);
\r
340 //! Creates a new matrix as interpolated matrix from two other ones.
\r
341 /** \param b: other matrix to interpolate with
\r
342 \param time: Must be a value between 0 and 1. */
\r
343 CMatrix4<T> interpolate(const core::CMatrix4<T>& b, f32 time) const;
\r
345 //! Gets transposed matrix
\r
346 CMatrix4<T> getTransposed() const;
\r
348 //! Gets transposed matrix
\r
349 inline void getTransposed( CMatrix4<T>& dest ) const;
\r
351 //! Builds a matrix that rotates from one vector to another
\r
352 /** \param from: vector to rotate from
\r
353 \param to: vector to rotate to
\r
355 CMatrix4<T>& buildRotateFromTo(const core::vector3df& from, const core::vector3df& to);
\r
357 //! Builds a combined matrix which translates to a center before rotation and translates from origin afterwards
\r
358 /** \param center Position to rotate around
\r
359 \param translate Translation applied after the rotation
\r
361 void setRotationCenter(const core::vector3df& center, const core::vector3df& translate);
\r
363 //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis
\r
364 /** \param camPos: viewer position in world coo
\r
365 \param center: object position in world-coo and rotation pivot
\r
366 \param translation: object final translation from center
\r
367 \param axis: axis to rotate about
\r
368 \param from: source vector to rotate from
\r
370 void buildAxisAlignedBillboard(const core::vector3df& camPos,
\r
371 const core::vector3df& center,
\r
372 const core::vector3df& translation,
\r
373 const core::vector3df& axis,
\r
374 const core::vector3df& from);
\r
377 construct 2D Texture transformations
\r
378 rotate about center, scale, and transform.
\r
380 //! Set to a texture transformation matrix with the given parameters.
\r
381 CMatrix4<T>& buildTextureTransform( f32 rotateRad,
\r
382 const core::vector2df &rotatecenter,
\r
383 const core::vector2df &translate,
\r
384 const core::vector2df &scale);
\r
386 //! Set texture transformation rotation
\r
387 /** Rotate about z axis, recenter at (0.5,0.5).
\r
388 Doesn't clear other elements than those affected
\r
389 \param radAngle Angle in radians
\r
390 \return Altered matrix */
\r
391 CMatrix4<T>& setTextureRotationCenter( f32 radAngle );
\r
393 //! Set texture transformation translation
\r
394 /** Doesn't clear other elements than those affected.
\r
395 \param x Offset on x axis
\r
396 \param y Offset on y axis
\r
397 \return Altered matrix */
\r
398 CMatrix4<T>& setTextureTranslate( f32 x, f32 y );
\r
400 //! Get texture transformation translation
\r
401 /** \param x returns offset on x axis
\r
402 \param y returns offset on y axis */
\r
403 void getTextureTranslate( f32& x, f32& y ) const;
\r
405 //! Set texture transformation translation, using a transposed representation
\r
406 /** Doesn't clear other elements than those affected.
\r
407 \param x Offset on x axis
\r
408 \param y Offset on y axis
\r
409 \return Altered matrix */
\r
410 CMatrix4<T>& setTextureTranslateTransposed( f32 x, f32 y );
\r
412 //! Set texture transformation scale
\r
413 /** Doesn't clear other elements than those affected.
\r
414 \param sx Scale factor on x axis
\r
415 \param sy Scale factor on y axis
\r
416 \return Altered matrix. */
\r
417 CMatrix4<T>& setTextureScale( f32 sx, f32 sy );
\r
419 //! Get texture transformation scale
\r
420 /** \param sx Returns x axis scale factor
\r
421 \param sy Returns y axis scale factor */
\r
422 void getTextureScale( f32& sx, f32& sy ) const;
\r
424 //! Set texture transformation scale, and recenter at (0.5,0.5)
\r
425 /** Doesn't clear other elements than those affected.
\r
426 \param sx Scale factor on x axis
\r
427 \param sy Scale factor on y axis
\r
428 \return Altered matrix. */
\r
429 CMatrix4<T>& setTextureScaleCenter( f32 sx, f32 sy );
\r
431 //! Sets all matrix data members at once
\r
432 CMatrix4<T>& setM(const T* data);
\r
434 //! Sets if the matrix is definitely identity matrix
\r
435 void setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix);
\r
437 //! Gets if the matrix is definitely identity matrix
\r
438 bool getDefinitelyIdentityMatrix() const;
\r
440 //! Compare two matrices using the equal method
\r
441 bool equals(const core::CMatrix4<T>& other, const T tolerance=(T)ROUNDING_ERROR_f64) const;
\r
444 //! Matrix data, stored in row-major order
\r
446 #if defined ( USE_MATRIX_TEST )
\r
447 //! Flag is this matrix is identity matrix
\r
448 mutable u32 definitelyIdentityMatrix;
\r
450 #if defined ( USE_MATRIX_TEST_DEBUG )
\r
457 // Default constructor
\r
459 inline CMatrix4<T>::CMatrix4( eConstructor constructor )
\r
460 #if defined ( USE_MATRIX_TEST )
\r
461 : definitelyIdentityMatrix(BIT_UNTESTED)
\r
463 #if defined ( USE_MATRIX_TEST_DEBUG )
\r
464 ,id ( MTest.ID++), calls ( 0 )
\r
467 switch ( constructor )
\r
469 case EM4CONST_NOTHING:
\r
470 case EM4CONST_COPY:
\r
472 case EM4CONST_IDENTITY:
\r
473 case EM4CONST_INVERSE:
\r
480 // Copy constructor
\r
482 inline CMatrix4<T>::CMatrix4( const CMatrix4<T>& other, eConstructor constructor)
\r
483 #if defined ( USE_MATRIX_TEST )
\r
484 : definitelyIdentityMatrix(BIT_UNTESTED)
\r
486 #if defined ( USE_MATRIX_TEST_DEBUG )
\r
487 ,id ( MTest.ID++), calls ( 0 )
\r
490 switch ( constructor )
\r
492 case EM4CONST_IDENTITY:
\r
495 case EM4CONST_NOTHING:
\r
497 case EM4CONST_COPY:
\r
500 case EM4CONST_TRANSPOSED:
\r
501 other.getTransposed(*this);
\r
503 case EM4CONST_INVERSE:
\r
504 if (!other.getInverse(*this))
\r
505 memset(M, 0, 16*sizeof(T));
\r
507 case EM4CONST_INVERSE_TRANSPOSED:
\r
508 if (!other.getInverse(*this))
\r
509 memset(M, 0, 16*sizeof(T));
\r
511 *this=getTransposed();
\r
516 //! Add another matrix.
\r
518 inline CMatrix4<T> CMatrix4<T>::operator+(const CMatrix4<T>& other) const
\r
520 CMatrix4<T> temp ( EM4CONST_NOTHING );
\r
522 temp[0] = M[0]+other[0];
\r
523 temp[1] = M[1]+other[1];
\r
524 temp[2] = M[2]+other[2];
\r
525 temp[3] = M[3]+other[3];
\r
526 temp[4] = M[4]+other[4];
\r
527 temp[5] = M[5]+other[5];
\r
528 temp[6] = M[6]+other[6];
\r
529 temp[7] = M[7]+other[7];
\r
530 temp[8] = M[8]+other[8];
\r
531 temp[9] = M[9]+other[9];
\r
532 temp[10] = M[10]+other[10];
\r
533 temp[11] = M[11]+other[11];
\r
534 temp[12] = M[12]+other[12];
\r
535 temp[13] = M[13]+other[13];
\r
536 temp[14] = M[14]+other[14];
\r
537 temp[15] = M[15]+other[15];
\r
542 //! Add another matrix.
\r
544 inline CMatrix4<T>& CMatrix4<T>::operator+=(const CMatrix4<T>& other)
\r
566 //! Subtract another matrix.
\r
568 inline CMatrix4<T> CMatrix4<T>::operator-(const CMatrix4<T>& other) const
\r
570 CMatrix4<T> temp ( EM4CONST_NOTHING );
\r
572 temp[0] = M[0]-other[0];
\r
573 temp[1] = M[1]-other[1];
\r
574 temp[2] = M[2]-other[2];
\r
575 temp[3] = M[3]-other[3];
\r
576 temp[4] = M[4]-other[4];
\r
577 temp[5] = M[5]-other[5];
\r
578 temp[6] = M[6]-other[6];
\r
579 temp[7] = M[7]-other[7];
\r
580 temp[8] = M[8]-other[8];
\r
581 temp[9] = M[9]-other[9];
\r
582 temp[10] = M[10]-other[10];
\r
583 temp[11] = M[11]-other[11];
\r
584 temp[12] = M[12]-other[12];
\r
585 temp[13] = M[13]-other[13];
\r
586 temp[14] = M[14]-other[14];
\r
587 temp[15] = M[15]-other[15];
\r
592 //! Subtract another matrix.
\r
594 inline CMatrix4<T>& CMatrix4<T>::operator-=(const CMatrix4<T>& other)
\r
616 //! Multiply by scalar.
\r
618 inline CMatrix4<T> CMatrix4<T>::operator*(const T& scalar) const
\r
620 CMatrix4<T> temp ( EM4CONST_NOTHING );
\r
622 temp[0] = M[0]*scalar;
\r
623 temp[1] = M[1]*scalar;
\r
624 temp[2] = M[2]*scalar;
\r
625 temp[3] = M[3]*scalar;
\r
626 temp[4] = M[4]*scalar;
\r
627 temp[5] = M[5]*scalar;
\r
628 temp[6] = M[6]*scalar;
\r
629 temp[7] = M[7]*scalar;
\r
630 temp[8] = M[8]*scalar;
\r
631 temp[9] = M[9]*scalar;
\r
632 temp[10] = M[10]*scalar;
\r
633 temp[11] = M[11]*scalar;
\r
634 temp[12] = M[12]*scalar;
\r
635 temp[13] = M[13]*scalar;
\r
636 temp[14] = M[14]*scalar;
\r
637 temp[15] = M[15]*scalar;
\r
642 //! Multiply by scalar.
\r
644 inline CMatrix4<T>& CMatrix4<T>::operator*=(const T& scalar)
\r
666 //! Multiply by another matrix.
\r
668 inline CMatrix4<T>& CMatrix4<T>::operator*=(const CMatrix4<T>& other)
\r
670 #if defined ( USE_MATRIX_TEST )
\r
671 // do checks on your own in order to avoid copy creation
\r
672 if ( !other.isIdentity() )
\r
674 if ( this->isIdentity() )
\r
676 return (*this = other);
\r
680 CMatrix4<T> temp ( *this );
\r
681 return setbyproduct_nocheck( temp, other );
\r
686 CMatrix4<T> temp ( *this );
\r
687 return setbyproduct_nocheck( temp, other );
\r
691 //! multiply by another matrix
\r
692 // set this matrix to the product of two other matrices
\r
693 // goal is to reduce stack use and copy
\r
695 inline CMatrix4<T>& CMatrix4<T>::setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b )
\r
697 const T *m1 = other_a.M;
\r
698 const T *m2 = other_b.M;
\r
700 M[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
\r
701 M[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
\r
702 M[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
\r
703 M[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
\r
705 M[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
\r
706 M[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
\r
707 M[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
\r
708 M[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
\r
710 M[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
\r
711 M[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
\r
712 M[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
\r
713 M[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
\r
715 M[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
\r
716 M[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
\r
717 M[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
\r
718 M[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
\r
719 #if defined ( USE_MATRIX_TEST )
\r
720 definitelyIdentityMatrix=false;
\r
726 //! multiply by another matrix
\r
727 // set this matrix to the product of two other matrices
\r
728 // goal is to reduce stack use and copy
\r
730 inline CMatrix4<T>& CMatrix4<T>::setbyproduct(const CMatrix4<T>& other_a, const CMatrix4<T>& other_b )
\r
732 #if defined ( USE_MATRIX_TEST )
\r
733 if ( other_a.isIdentity () )
\r
734 return (*this = other_b);
\r
736 if ( other_b.isIdentity () )
\r
737 return (*this = other_a);
\r
739 return setbyproduct_nocheck(other_a,other_b);
\r
741 return setbyproduct_nocheck(other_a,other_b);
\r
745 //! multiply by another matrix
\r
747 inline CMatrix4<T> CMatrix4<T>::operator*(const CMatrix4<T>& m2) const
\r
749 #if defined ( USE_MATRIX_TEST )
\r
750 // Testing purpose..
\r
751 if ( this->isIdentity() )
\r
753 if ( m2.isIdentity() )
\r
757 CMatrix4<T> m3 ( EM4CONST_NOTHING );
\r
761 m3[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
\r
762 m3[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
\r
763 m3[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
\r
764 m3[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
\r
766 m3[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
\r
767 m3[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
\r
768 m3[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
\r
769 m3[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
\r
771 m3[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
\r
772 m3[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
\r
773 m3[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
\r
774 m3[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
\r
776 m3[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
\r
777 m3[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
\r
778 m3[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
\r
779 m3[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
\r
786 inline vector3d<T> CMatrix4<T>::getTranslation() const
\r
788 return vector3d<T>(M[12], M[13], M[14]);
\r
793 inline CMatrix4<T>& CMatrix4<T>::setTranslation( const vector3d<T>& translation )
\r
795 M[12] = translation.X;
\r
796 M[13] = translation.Y;
\r
797 M[14] = translation.Z;
\r
798 #if defined ( USE_MATRIX_TEST )
\r
799 definitelyIdentityMatrix=false;
\r
805 inline CMatrix4<T>& CMatrix4<T>::setInverseTranslation( const vector3d<T>& translation )
\r
807 M[12] = -translation.X;
\r
808 M[13] = -translation.Y;
\r
809 M[14] = -translation.Z;
\r
810 #if defined ( USE_MATRIX_TEST )
\r
811 definitelyIdentityMatrix=false;
\r
817 inline CMatrix4<T>& CMatrix4<T>::setScale( const vector3d<T>& scale )
\r
822 #if defined ( USE_MATRIX_TEST )
\r
823 definitelyIdentityMatrix=false;
\r
828 //! Returns the absolute values of the scales of the matrix.
\r
830 Note that this returns the absolute (positive) values unless only scale is set.
\r
831 Unfortunately it does not appear to be possible to extract any original negative
\r
832 values. The best that we could do would be to arbitrarily make one scale
\r
833 negative if one or three of them were negative.
\r
834 FIXME - return the original values.
\r
837 inline vector3d<T> CMatrix4<T>::getScale() const
\r
839 // See http://www.robertblum.com/articles/2005/02/14/decomposing-matrices
\r
841 // Deal with the 0 rotation case first
\r
842 // Prior to Irrlicht 1.6, we always returned this value.
\r
843 if(core::iszero(M[1]) && core::iszero(M[2]) &&
\r
844 core::iszero(M[4]) && core::iszero(M[6]) &&
\r
845 core::iszero(M[8]) && core::iszero(M[9]))
\r
846 return vector3d<T>(M[0], M[5], M[10]);
\r
848 // We have to do the full calculation.
\r
849 return vector3d<T>(sqrtf(M[0] * M[0] + M[1] * M[1] + M[2] * M[2]),
\r
850 sqrtf(M[4] * M[4] + M[5] * M[5] + M[6] * M[6]),
\r
851 sqrtf(M[8] * M[8] + M[9] * M[9] + M[10] * M[10]));
\r
855 inline CMatrix4<T>& CMatrix4<T>::setRotationDegrees( const vector3d<T>& rotation )
\r
857 return setRotationRadians( rotation * core::DEGTORAD );
\r
861 inline CMatrix4<T>& CMatrix4<T>::setInverseRotationDegrees( const vector3d<T>& rotation )
\r
863 return setInverseRotationRadians( rotation * core::DEGTORAD );
\r
867 inline CMatrix4<T>& CMatrix4<T>::setRotationRadians( const vector3d<T>& rotation )
\r
869 const f64 cr = cos( rotation.X );
\r
870 const f64 sr = sin( rotation.X );
\r
871 const f64 cp = cos( rotation.Y );
\r
872 const f64 sp = sin( rotation.Y );
\r
873 const f64 cy = cos( rotation.Z );
\r
874 const f64 sy = sin( rotation.Z );
\r
876 M[0] = (T)( cp*cy );
\r
877 M[1] = (T)( cp*sy );
\r
880 const f64 srsp = sr*sp;
\r
881 const f64 crsp = cr*sp;
\r
883 M[4] = (T)( srsp*cy-cr*sy );
\r
884 M[5] = (T)( srsp*sy+cr*cy );
\r
885 M[6] = (T)( sr*cp );
\r
887 M[8] = (T)( crsp*cy+sr*sy );
\r
888 M[9] = (T)( crsp*sy-sr*cy );
\r
889 M[10] = (T)( cr*cp );
\r
890 #if defined ( USE_MATRIX_TEST )
\r
891 definitelyIdentityMatrix=false;
\r
897 //! Returns a rotation that is equivalent to that set by setRotationDegrees().
\r
898 /** This code was sent in by Chev. Note that it does not necessarily return
\r
899 the *same* Euler angles as those set by setRotationDegrees(), but the rotation will
\r
900 be equivalent, i.e. will have the same result when used to rotate a vector or node.
\r
901 This code was originally written by by Chev.
\r
904 inline core::vector3d<T> CMatrix4<T>::getRotationDegrees(const vector3d<T>& scale_) const
\r
906 const CMatrix4<T> &mat = *this;
\r
907 core::vector3d<T> scale(scale_);
\r
908 // we need to check for negative scale on to axes, which would bring up wrong results
\r
909 if (scale.Y<0 && scale.Z<0)
\r
914 else if (scale.X<0 && scale.Z<0)
\r
919 else if (scale.X<0 && scale.Y<0)
\r
924 const core::vector3d<f64> invScale(core::reciprocal(scale.X),core::reciprocal(scale.Y),core::reciprocal(scale.Z));
\r
926 f64 Y = -asin(core::clamp(mat[2]*invScale.X, -1.0, 1.0));
\r
927 const f64 C = cos(Y);
\r
930 f64 rotx, roty, X, Z;
\r
932 if (!core::iszero(C))
\r
934 const f64 invC = core::reciprocal(C);
\r
935 rotx = mat[10] * invC * invScale.Z;
\r
936 roty = mat[6] * invC * invScale.Y;
\r
937 X = atan2( roty, rotx ) * RADTODEG64;
\r
938 rotx = mat[0] * invC * invScale.X;
\r
939 roty = mat[1] * invC * invScale.X;
\r
940 Z = atan2( roty, rotx ) * RADTODEG64;
\r
945 rotx = mat[5] * invScale.Y;
\r
946 roty = -mat[4] * invScale.Y;
\r
947 Z = atan2( roty, rotx ) * RADTODEG64;
\r
950 // fix values that get below zero
\r
951 if (X < 0.0) X += 360.0;
\r
952 if (Y < 0.0) Y += 360.0;
\r
953 if (Z < 0.0) Z += 360.0;
\r
955 return vector3d<T>((T)X,(T)Y,(T)Z);
\r
958 //! Returns a rotation that is equivalent to that set by setRotationDegrees().
\r
959 /** This code was sent in by Chev. Note that it does not necessarily return
\r
960 the *same* Euler angles as those set by setRotationDegrees(), but the rotation will
\r
961 be equivalent, i.e. will have the same result when used to rotate a vector or node.
\r
962 This code was originally written by by Chev. */
\r
964 inline core::vector3d<T> CMatrix4<T>::getRotationDegrees() const
\r
966 return getRotationDegrees(getScale());
\r
970 //! Sets matrix to rotation matrix of inverse angles given as parameters
\r
972 inline CMatrix4<T>& CMatrix4<T>::setInverseRotationRadians( const vector3d<T>& rotation )
\r
974 f64 cr = cos( rotation.X );
\r
975 f64 sr = sin( rotation.X );
\r
976 f64 cp = cos( rotation.Y );
\r
977 f64 sp = sin( rotation.Y );
\r
978 f64 cy = cos( rotation.Z );
\r
979 f64 sy = sin( rotation.Z );
\r
981 M[0] = (T)( cp*cy );
\r
982 M[4] = (T)( cp*sy );
\r
988 M[1] = (T)( srsp*cy-cr*sy );
\r
989 M[5] = (T)( srsp*sy+cr*cy );
\r
990 M[9] = (T)( sr*cp );
\r
992 M[2] = (T)( crsp*cy+sr*sy );
\r
993 M[6] = (T)( crsp*sy-sr*cy );
\r
994 M[10] = (T)( cr*cp );
\r
995 #if defined ( USE_MATRIX_TEST )
\r
996 definitelyIdentityMatrix=false;
\r
1001 //! Sets matrix to rotation matrix defined by axis and angle, assuming LH rotation
\r
1002 template <class T>
\r
1003 inline CMatrix4<T>& CMatrix4<T>::setRotationAxisRadians( const T& angle, const vector3d<T>& axis )
\r
1005 const f64 c = cos(angle);
\r
1006 const f64 s = sin(angle);
\r
1007 const f64 t = 1.0 - c;
\r
1009 const f64 tx = t * axis.X;
\r
1010 const f64 ty = t * axis.Y;
\r
1011 const f64 tz = t * axis.Z;
\r
1013 const f64 sx = s * axis.X;
\r
1014 const f64 sy = s * axis.Y;
\r
1015 const f64 sz = s * axis.Z;
\r
1017 M[0] = (T)(tx * axis.X + c);
\r
1018 M[1] = (T)(tx * axis.Y + sz);
\r
1019 M[2] = (T)(tx * axis.Z - sy);
\r
1021 M[4] = (T)(ty * axis.X - sz);
\r
1022 M[5] = (T)(ty * axis.Y + c);
\r
1023 M[6] = (T)(ty * axis.Z + sx);
\r
1025 M[8] = (T)(tz * axis.X + sy);
\r
1026 M[9] = (T)(tz * axis.Y - sx);
\r
1027 M[10] = (T)(tz * axis.Z + c);
\r
1029 #if defined ( USE_MATRIX_TEST )
\r
1030 definitelyIdentityMatrix=false;
\r
1038 template <class T>
\r
1039 inline CMatrix4<T>& CMatrix4<T>::makeIdentity()
\r
1041 memset(M, 0, 16*sizeof(T));
\r
1042 M[0] = M[5] = M[10] = M[15] = (T)1;
\r
1043 #if defined ( USE_MATRIX_TEST )
\r
1044 definitelyIdentityMatrix=true;
\r
1051 check identity with epsilon
\r
1052 solve floating range problems..
\r
1054 template <class T>
\r
1055 inline bool CMatrix4<T>::isIdentity() const
\r
1057 #if defined ( USE_MATRIX_TEST )
\r
1058 if (definitelyIdentityMatrix)
\r
1061 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 ))
\r
1064 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 ))
\r
1067 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 ))
\r
1070 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 ))
\r
1073 if (!core::equals( M[ 0], (T)1 ) ||
\r
1074 !core::equals( M[ 5], (T)1 ) ||
\r
1075 !core::equals( M[10], (T)1 ) ||
\r
1076 !core::equals( M[15], (T)1 ))
\r
1079 for (s32 i=0; i<4; ++i)
\r
1080 for (s32 j=0; j<4; ++j)
\r
1081 if ((j != i) && (!iszero((*this)(i,j))))
\r
1084 #if defined ( USE_MATRIX_TEST )
\r
1085 definitelyIdentityMatrix=true;
\r
1091 /* Check orthogonality of matrix. */
\r
1092 template <class T>
\r
1093 inline bool CMatrix4<T>::isOrthogonal() const
\r
1095 T dp=M[0] * M[4 ] + M[1] * M[5 ] + M[2 ] * M[6 ] + M[3 ] * M[7 ];
\r
1098 dp = M[0] * M[8 ] + M[1] * M[9 ] + M[2 ] * M[10] + M[3 ] * M[11];
\r
1101 dp = M[0] * M[12] + M[1] * M[13] + M[2 ] * M[14] + M[3 ] * M[15];
\r
1104 dp = M[4] * M[8 ] + M[5] * M[9 ] + M[6 ] * M[10] + M[7 ] * M[11];
\r
1107 dp = M[4] * M[12] + M[5] * M[13] + M[6 ] * M[14] + M[7 ] * M[15];
\r
1110 dp = M[8] * M[12] + M[9] * M[13] + M[10] * M[14] + M[11] * M[15];
\r
1111 return (iszero(dp));
\r
1116 doesn't solve floating range problems..
\r
1117 but takes care on +/- 0 on translation because we are changing it..
\r
1118 reducing floating point branches
\r
1119 but it needs the floats in memory..
\r
1121 template <class T>
\r
1122 inline bool CMatrix4<T>::isIdentity_integer_base() const
\r
1124 #if defined ( USE_MATRIX_TEST )
\r
1125 if (definitelyIdentityMatrix)
\r
1128 if(IR(M[0])!=F32_VALUE_1) return false;
\r
1129 if(IR(M[1])!=0) return false;
\r
1130 if(IR(M[2])!=0) return false;
\r
1131 if(IR(M[3])!=0) return false;
\r
1133 if(IR(M[4])!=0) return false;
\r
1134 if(IR(M[5])!=F32_VALUE_1) return false;
\r
1135 if(IR(M[6])!=0) return false;
\r
1136 if(IR(M[7])!=0) return false;
\r
1138 if(IR(M[8])!=0) return false;
\r
1139 if(IR(M[9])!=0) return false;
\r
1140 if(IR(M[10])!=F32_VALUE_1) return false;
\r
1141 if(IR(M[11])!=0) return false;
\r
1143 if(IR(M[12])!=0) return false;
\r
1144 if(IR(M[13])!=0) return false;
\r
1145 if(IR(M[13])!=0) return false;
\r
1146 if(IR(M[15])!=F32_VALUE_1) return false;
\r
1148 #if defined ( USE_MATRIX_TEST )
\r
1149 definitelyIdentityMatrix=true;
\r
1155 template <class T>
\r
1156 inline void CMatrix4<T>::rotateVect( vector3df& vect ) const
\r
1158 vector3df tmp = vect;
\r
1159 vect.X = tmp.X*M[0] + tmp.Y*M[4] + tmp.Z*M[8];
\r
1160 vect.Y = tmp.X*M[1] + tmp.Y*M[5] + tmp.Z*M[9];
\r
1161 vect.Z = tmp.X*M[2] + tmp.Y*M[6] + tmp.Z*M[10];
\r
1164 //! An alternate transform vector method, writing into a second vector
\r
1165 template <class T>
\r
1166 inline void CMatrix4<T>::rotateVect(core::vector3df& out, const core::vector3df& in) const
\r
1168 out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
\r
1169 out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
\r
1170 out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
\r
1173 //! An alternate transform vector method, writing into an array of 3 floats
\r
1174 template <class T>
\r
1175 inline void CMatrix4<T>::rotateVect(T *out, const core::vector3df& in) const
\r
1177 out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
\r
1178 out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
\r
1179 out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
\r
1182 template <class T>
\r
1183 inline void CMatrix4<T>::inverseRotateVect( vector3df& vect ) const
\r
1185 vector3df tmp = vect;
\r
1186 vect.X = tmp.X*M[0] + tmp.Y*M[1] + tmp.Z*M[2];
\r
1187 vect.Y = tmp.X*M[4] + tmp.Y*M[5] + tmp.Z*M[6];
\r
1188 vect.Z = tmp.X*M[8] + tmp.Y*M[9] + tmp.Z*M[10];
\r
1191 template <class T>
\r
1192 inline void CMatrix4<T>::transformVect( vector3df& vect) const
\r
1196 vector[0] = vect.X*M[0] + vect.Y*M[4] + vect.Z*M[8] + M[12];
\r
1197 vector[1] = vect.X*M[1] + vect.Y*M[5] + vect.Z*M[9] + M[13];
\r
1198 vector[2] = vect.X*M[2] + vect.Y*M[6] + vect.Z*M[10] + M[14];
\r
1200 vect.X = vector[0];
\r
1201 vect.Y = vector[1];
\r
1202 vect.Z = vector[2];
\r
1205 template <class T>
\r
1206 inline void CMatrix4<T>::transformVect( vector3df& out, const vector3df& in) const
\r
1208 out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
\r
1209 out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
\r
1210 out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
\r
1214 template <class T>
\r
1215 inline void CMatrix4<T>::transformVect(T *out, const core::vector3df &in) const
\r
1217 out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
\r
1218 out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
\r
1219 out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
\r
1220 out[3] = in.X*M[3] + in.Y*M[7] + in.Z*M[11] + M[15];
\r
1223 template <class T>
\r
1224 inline void CMatrix4<T>::transformVec3(T *out, const T * in) const
\r
1226 out[0] = in[0]*M[0] + in[1]*M[4] + in[2]*M[8] + M[12];
\r
1227 out[1] = in[0]*M[1] + in[1]*M[5] + in[2]*M[9] + M[13];
\r
1228 out[2] = in[0]*M[2] + in[1]*M[6] + in[2]*M[10] + M[14];
\r
1231 template <class T>
\r
1232 inline void CMatrix4<T>::transformVec4(T *out, const T * in) const
\r
1234 out[0] = in[0]*M[0] + in[1]*M[4] + in[2]*M[8] + in[3]*M[12];
\r
1235 out[1] = in[0]*M[1] + in[1]*M[5] + in[2]*M[9] + in[3]*M[13];
\r
1236 out[2] = in[0]*M[2] + in[1]*M[6] + in[2]*M[10] + in[3]*M[14];
\r
1237 out[3] = in[0]*M[3] + in[1]*M[7] + in[2]*M[11] + in[3]*M[15];
\r
1241 //! Transforms a plane by this matrix
\r
1242 template <class T>
\r
1243 inline void CMatrix4<T>::transformPlane( core::plane3d<f32> &plane) const
\r
1246 // Transform the plane member point, i.e. rotate, translate and scale it.
\r
1247 transformVect(member, plane.getMemberPoint());
\r
1249 // Transform the normal by the transposed inverse of the matrix
\r
1250 CMatrix4<T> transposedInverse(*this, EM4CONST_INVERSE_TRANSPOSED);
\r
1251 vector3df normal = plane.Normal;
\r
1252 transposedInverse.rotateVect(normal);
\r
1253 plane.setPlane(member, normal.normalize());
\r
1256 //! Transforms a plane by this matrix
\r
1257 template <class T>
\r
1258 inline void CMatrix4<T>::transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const
\r
1261 transformPlane( out );
\r
1264 //! Transforms the edge-points of a bounding box
\r
1265 //! Deprecated as it's usually not what people need (regards only 2 corners, but other corners might be outside the box after transformation)
\r
1266 //! Use transformBoxEx instead.
\r
1267 template <class T>
\r
1268 _IRR_DEPRECATED_ inline void CMatrix4<T>::transformBox(core::aabbox3d<f32>& box) const
\r
1270 #if defined ( USE_MATRIX_TEST )
\r
1275 transformVect(box.MinEdge);
\r
1276 transformVect(box.MaxEdge);
\r
1280 //! Transforms a axis aligned bounding box more accurately than transformBox()
\r
1281 template <class T>
\r
1282 inline void CMatrix4<T>::transformBoxEx(core::aabbox3d<f32>& box) const
\r
1284 #if defined ( USE_MATRIX_TEST )
\r
1289 const f32 Amin[3] = {box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z};
\r
1290 const f32 Amax[3] = {box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z};
\r
1295 Bmin[0] = Bmax[0] = M[12];
\r
1296 Bmin[1] = Bmax[1] = M[13];
\r
1297 Bmin[2] = Bmax[2] = M[14];
\r
1299 const CMatrix4<T> &m = *this;
\r
1301 for (u32 i = 0; i < 3; ++i)
\r
1303 for (u32 j = 0; j < 3; ++j)
\r
1305 const f32 a = m(j,i) * Amin[j];
\r
1306 const f32 b = m(j,i) * Amax[j];
\r
1321 box.MinEdge.X = Bmin[0];
\r
1322 box.MinEdge.Y = Bmin[1];
\r
1323 box.MinEdge.Z = Bmin[2];
\r
1325 box.MaxEdge.X = Bmax[0];
\r
1326 box.MaxEdge.Y = Bmax[1];
\r
1327 box.MaxEdge.Z = Bmax[2];
\r
1331 //! Multiplies this matrix by a 1x4 matrix
\r
1332 template <class T>
\r
1333 inline void CMatrix4<T>::multiplyWith1x4Matrix(T* matrix) const
\r
1343 mat[0] = matrix[0];
\r
1344 mat[1] = matrix[1];
\r
1345 mat[2] = matrix[2];
\r
1346 mat[3] = matrix[3];
\r
1348 matrix[0] = M[0]*mat[0] + M[4]*mat[1] + M[8]*mat[2] + M[12]*mat[3];
\r
1349 matrix[1] = M[1]*mat[0] + M[5]*mat[1] + M[9]*mat[2] + M[13]*mat[3];
\r
1350 matrix[2] = M[2]*mat[0] + M[6]*mat[1] + M[10]*mat[2] + M[14]*mat[3];
\r
1351 matrix[3] = M[3]*mat[0] + M[7]*mat[1] + M[11]*mat[2] + M[15]*mat[3];
\r
1354 template <class T>
\r
1355 inline void CMatrix4<T>::inverseTranslateVect( vector3df& vect ) const
\r
1357 vect.X = vect.X-M[12];
\r
1358 vect.Y = vect.Y-M[13];
\r
1359 vect.Z = vect.Z-M[14];
\r
1362 template <class T>
\r
1363 inline void CMatrix4<T>::translateVect( vector3df& vect ) const
\r
1365 vect.X = vect.X+M[12];
\r
1366 vect.Y = vect.Y+M[13];
\r
1367 vect.Z = vect.Z+M[14];
\r
1371 template <class T>
\r
1372 inline bool CMatrix4<T>::getInverse(CMatrix4<T>& out) const
\r
1374 /// Calculates the inverse of this Matrix
\r
1375 /// The inverse is calculated using Cramers rule.
\r
1376 /// If no inverse exists then 'false' is returned.
\r
1378 #if defined ( USE_MATRIX_TEST )
\r
1379 if ( this->isIdentity() )
\r
1385 const CMatrix4<T> &m = *this;
\r
1387 f32 d = (m[0] * m[5] - m[1] * m[4]) * (m[10] * m[15] - m[11] * m[14]) -
\r
1388 (m[0] * m[6] - m[2] * m[4]) * (m[9] * m[15] - m[11] * m[13]) +
\r
1389 (m[0] * m[7] - m[3] * m[4]) * (m[9] * m[14] - m[10] * m[13]) +
\r
1390 (m[1] * m[6] - m[2] * m[5]) * (m[8] * m[15] - m[11] * m[12]) -
\r
1391 (m[1] * m[7] - m[3] * m[5]) * (m[8] * m[14] - m[10] * m[12]) +
\r
1392 (m[2] * m[7] - m[3] * m[6]) * (m[8] * m[13] - m[9] * m[12]);
\r
1394 if( core::iszero ( d, FLT_MIN ) )
\r
1397 d = core::reciprocal ( d );
\r
1399 out[0] = d * (m[5] * (m[10] * m[15] - m[11] * m[14]) +
\r
1400 m[6] * (m[11] * m[13] - m[9] * m[15]) +
\r
1401 m[7] * (m[9] * m[14] - m[10] * m[13]));
\r
1402 out[1] = d * (m[9] * (m[2] * m[15] - m[3] * m[14]) +
\r
1403 m[10] * (m[3] * m[13] - m[1] * m[15]) +
\r
1404 m[11] * (m[1] * m[14] - m[2] * m[13]));
\r
1405 out[2] = d * (m[13] * (m[2] * m[7] - m[3] * m[6]) +
\r
1406 m[14] * (m[3] * m[5] - m[1] * m[7]) +
\r
1407 m[15] * (m[1] * m[6] - m[2] * m[5]));
\r
1408 out[3] = d * (m[1] * (m[7] * m[10] - m[6] * m[11]) +
\r
1409 m[2] * (m[5] * m[11] - m[7] * m[9]) +
\r
1410 m[3] * (m[6] * m[9] - m[5] * m[10]));
\r
1411 out[4] = d * (m[6] * (m[8] * m[15] - m[11] * m[12]) +
\r
1412 m[7] * (m[10] * m[12] - m[8] * m[14]) +
\r
1413 m[4] * (m[11] * m[14] - m[10] * m[15]));
\r
1414 out[5] = d * (m[10] * (m[0] * m[15] - m[3] * m[12]) +
\r
1415 m[11] * (m[2] * m[12] - m[0] * m[14]) +
\r
1416 m[8] * (m[3] * m[14] - m[2] * m[15]));
\r
1417 out[6] = d * (m[14] * (m[0] * m[7] - m[3] * m[4]) +
\r
1418 m[15] * (m[2] * m[4] - m[0] * m[6]) +
\r
1419 m[12] * (m[3] * m[6] - m[2] * m[7]));
\r
1420 out[7] = d * (m[2] * (m[7] * m[8] - m[4] * m[11]) +
\r
1421 m[3] * (m[4] * m[10] - m[6] * m[8]) +
\r
1422 m[0] * (m[6] * m[11] - m[7] * m[10]));
\r
1423 out[8] = d * (m[7] * (m[8] * m[13] - m[9] * m[12]) +
\r
1424 m[4] * (m[9] * m[15] - m[11] * m[13]) +
\r
1425 m[5] * (m[11] * m[12] - m[8] * m[15]));
\r
1426 out[9] = d * (m[11] * (m[0] * m[13] - m[1] * m[12]) +
\r
1427 m[8] * (m[1] * m[15] - m[3] * m[13]) +
\r
1428 m[9] * (m[3] * m[12] - m[0] * m[15]));
\r
1429 out[10] = d * (m[15] * (m[0] * m[5] - m[1] * m[4]) +
\r
1430 m[12] * (m[1] * m[7] - m[3] * m[5]) +
\r
1431 m[13] * (m[3] * m[4] - m[0] * m[7]));
\r
1432 out[11] = d * (m[3] * (m[5] * m[8] - m[4] * m[9]) +
\r
1433 m[0] * (m[7] * m[9] - m[5] * m[11]) +
\r
1434 m[1] * (m[4] * m[11] - m[7] * m[8]));
\r
1435 out[12] = d * (m[4] * (m[10] * m[13] - m[9] * m[14]) +
\r
1436 m[5] * (m[8] * m[14] - m[10] * m[12]) +
\r
1437 m[6] * (m[9] * m[12] - m[8] * m[13]));
\r
1438 out[13] = d * (m[8] * (m[2] * m[13] - m[1] * m[14]) +
\r
1439 m[9] * (m[0] * m[14] - m[2] * m[12]) +
\r
1440 m[10] * (m[1] * m[12] - m[0] * m[13]));
\r
1441 out[14] = d * (m[12] * (m[2] * m[5] - m[1] * m[6]) +
\r
1442 m[13] * (m[0] * m[6] - m[2] * m[4]) +
\r
1443 m[14] * (m[1] * m[4] - m[0] * m[5]));
\r
1444 out[15] = d * (m[0] * (m[5] * m[10] - m[6] * m[9]) +
\r
1445 m[1] * (m[6] * m[8] - m[4] * m[10]) +
\r
1446 m[2] * (m[4] * m[9] - m[5] * m[8]));
\r
1448 #if defined ( USE_MATRIX_TEST )
\r
1449 out.definitelyIdentityMatrix = definitelyIdentityMatrix;
\r
1455 //! Inverts a primitive matrix which only contains a translation and a rotation
\r
1456 //! \param out: where result matrix is written to.
\r
1457 template <class T>
\r
1458 inline bool CMatrix4<T>::getInversePrimitive ( CMatrix4<T>& out ) const
\r
1472 out.M[10] = M[10];
\r
1475 out.M[12] = (T)-(M[12]*M[0] + M[13]*M[1] + M[14]*M[2]);
\r
1476 out.M[13] = (T)-(M[12]*M[4] + M[13]*M[5] + M[14]*M[6]);
\r
1477 out.M[14] = (T)-(M[12]*M[8] + M[13]*M[9] + M[14]*M[10]);
\r
1480 #if defined ( USE_MATRIX_TEST )
\r
1481 out.definitelyIdentityMatrix = definitelyIdentityMatrix;
\r
1488 template <class T>
\r
1489 inline bool CMatrix4<T>::makeInverse()
\r
1491 #if defined ( USE_MATRIX_TEST )
\r
1492 if (definitelyIdentityMatrix)
\r
1495 CMatrix4<T> temp ( EM4CONST_NOTHING );
\r
1497 if (getInverse(temp))
\r
1507 template <class T>
\r
1508 inline CMatrix4<T>& CMatrix4<T>::operator=(const T& scalar)
\r
1510 for (s32 i = 0; i < 16; ++i)
\r
1513 #if defined ( USE_MATRIX_TEST )
\r
1514 definitelyIdentityMatrix=false;
\r
1520 template <class T>
\r
1521 inline bool CMatrix4<T>::operator==(const CMatrix4<T> &other) const
\r
1523 #if defined ( USE_MATRIX_TEST )
\r
1524 if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
\r
1527 for (s32 i = 0; i < 16; ++i)
\r
1528 if (M[i] != other.M[i])
\r
1535 template <class T>
\r
1536 inline bool CMatrix4<T>::operator!=(const CMatrix4<T> &other) const
\r
1538 return !(*this == other);
\r
1542 // Builds a right-handed perspective projection matrix based on a field of view
\r
1543 template <class T>
\r
1544 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovRH(
\r
1545 f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1547 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
\r
1548 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
\r
1549 const T w = static_cast<T>(h / aspectRatio);
\r
1551 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1572 if ( zClipFromZero ) // DirectX version
\r
1574 M[10] = (T)(zFar/(zNear-zFar));
\r
1575 M[14] = (T)(zNear*zFar/(zNear-zFar));
\r
1577 else // OpenGL version
\r
1579 M[10] = (T)((zFar+zNear)/(zNear-zFar));
\r
1580 M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
\r
1583 #if defined ( USE_MATRIX_TEST )
\r
1584 definitelyIdentityMatrix=false;
\r
1590 // Builds a left-handed perspective projection matrix based on a field of view
\r
1591 template <class T>
\r
1592 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovLH(
\r
1593 f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1595 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
\r
1596 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
\r
1597 const T w = static_cast<T>(h / aspectRatio);
\r
1599 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1620 if ( zClipFromZero ) // DirectX version
\r
1622 M[10] = (T)(zFar/(zFar-zNear));
\r
1623 M[14] = (T)(-zNear*zFar/(zFar-zNear));
\r
1625 else // OpenGL version
\r
1627 M[10] = (T)((zFar+zNear)/(zFar-zNear));
\r
1628 M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
\r
1631 #if defined ( USE_MATRIX_TEST )
\r
1632 definitelyIdentityMatrix=false;
\r
1638 // Builds a left-handed perspective projection matrix based on a field of view, with far plane culling at infinity
\r
1639 template <class T>
\r
1640 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovInfinityLH(
\r
1641 f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon)
\r
1643 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
\r
1644 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
\r
1645 const T w = static_cast<T>(h / aspectRatio);
\r
1659 M[10] = (T)(1.f-epsilon);
\r
1664 M[14] = (T)(zNear*(epsilon-1.f));
\r
1667 #if defined ( USE_MATRIX_TEST )
\r
1668 definitelyIdentityMatrix=false;
\r
1674 // Builds a left-handed orthogonal projection matrix.
\r
1675 template <class T>
\r
1676 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoLH(
\r
1677 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1679 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
\r
1680 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
\r
1681 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1682 M[0] = (T)(2/widthOfViewVolume);
\r
1688 M[5] = (T)(2/heightOfViewVolume);
\r
1702 if ( zClipFromZero )
\r
1704 M[10] = (T)(1/(zFar-zNear));
\r
1705 M[14] = (T)(zNear/(zNear-zFar));
\r
1709 M[10] = (T)(2/(zFar-zNear));
\r
1710 M[14] = (T)-(zFar+zNear)/(zFar-zNear);
\r
1713 #if defined ( USE_MATRIX_TEST )
\r
1714 definitelyIdentityMatrix=false;
\r
1720 // Builds a right-handed orthogonal projection matrix.
\r
1721 template <class T>
\r
1722 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoRH(
\r
1723 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1725 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
\r
1726 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
\r
1727 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1728 M[0] = (T)(2/widthOfViewVolume);
\r
1734 M[5] = (T)(2/heightOfViewVolume);
\r
1748 if ( zClipFromZero )
\r
1750 M[10] = (T)(1/(zNear-zFar));
\r
1751 M[14] = (T)(zNear/(zNear-zFar));
\r
1755 M[10] = (T)(2/(zNear-zFar));
\r
1756 M[14] = (T)-(zFar+zNear)/(zFar-zNear);
\r
1759 #if defined ( USE_MATRIX_TEST )
\r
1760 definitelyIdentityMatrix=false;
\r
1766 // Builds a right-handed perspective projection matrix.
\r
1767 template <class T>
\r
1768 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveRH(
\r
1769 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1771 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
\r
1772 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
\r
1773 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1774 M[0] = (T)(2*zNear/widthOfViewVolume);
\r
1780 M[5] = (T)(2*zNear/heightOfViewVolume);
\r
1794 if ( zClipFromZero ) // DirectX version
\r
1796 M[10] = (T)(zFar/(zNear-zFar));
\r
1797 M[14] = (T)(zNear*zFar/(zNear-zFar));
\r
1799 else // OpenGL version
\r
1801 M[10] = (T)((zFar+zNear)/(zNear-zFar));
\r
1802 M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
\r
1805 #if defined ( USE_MATRIX_TEST )
\r
1806 definitelyIdentityMatrix=false;
\r
1812 // Builds a left-handed perspective projection matrix.
\r
1813 template <class T>
\r
1814 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveLH(
\r
1815 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1817 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
\r
1818 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
\r
1819 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1820 M[0] = (T)(2*zNear/widthOfViewVolume);
\r
1826 M[5] = (T)(2*zNear/heightOfViewVolume);
\r
1837 //M[14] = (T)(zNear*zFar/(zNear-zFar));
\r
1840 if ( zClipFromZero ) // DirectX version
\r
1842 M[10] = (T)(zFar/(zFar-zNear));
\r
1843 M[14] = (T)(zNear*zFar/(zNear-zFar));
\r
1845 else // OpenGL version
\r
1847 M[10] = (T)((zFar+zNear)/(zFar-zNear));
\r
1848 M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
\r
1851 #if defined ( USE_MATRIX_TEST )
\r
1852 definitelyIdentityMatrix=false;
\r
1858 // Builds a matrix that flattens geometry into a plane.
\r
1859 template <class T>
\r
1860 inline CMatrix4<T>& CMatrix4<T>::buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point)
\r
1862 plane.Normal.normalize();
\r
1863 const f32 d = plane.Normal.dotProduct(light);
\r
1865 M[ 0] = (T)(-plane.Normal.X * light.X + d);
\r
1866 M[ 1] = (T)(-plane.Normal.X * light.Y);
\r
1867 M[ 2] = (T)(-plane.Normal.X * light.Z);
\r
1868 M[ 3] = (T)(-plane.Normal.X * point);
\r
1870 M[ 4] = (T)(-plane.Normal.Y * light.X);
\r
1871 M[ 5] = (T)(-plane.Normal.Y * light.Y + d);
\r
1872 M[ 6] = (T)(-plane.Normal.Y * light.Z);
\r
1873 M[ 7] = (T)(-plane.Normal.Y * point);
\r
1875 M[ 8] = (T)(-plane.Normal.Z * light.X);
\r
1876 M[ 9] = (T)(-plane.Normal.Z * light.Y);
\r
1877 M[10] = (T)(-plane.Normal.Z * light.Z + d);
\r
1878 M[11] = (T)(-plane.Normal.Z * point);
\r
1880 M[12] = (T)(-plane.D * light.X);
\r
1881 M[13] = (T)(-plane.D * light.Y);
\r
1882 M[14] = (T)(-plane.D * light.Z);
\r
1883 M[15] = (T)(-plane.D * point + d);
\r
1884 #if defined ( USE_MATRIX_TEST )
\r
1885 definitelyIdentityMatrix=false;
\r
1890 // Builds a left-handed look-at matrix.
\r
1891 template <class T>
\r
1892 inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixLH(
\r
1893 const vector3df& position,
\r
1894 const vector3df& target,
\r
1895 const vector3df& upVector)
\r
1897 vector3df zaxis = target - position;
\r
1898 zaxis.normalize();
\r
1900 vector3df xaxis = upVector.crossProduct(zaxis);
\r
1901 xaxis.normalize();
\r
1903 vector3df yaxis = zaxis.crossProduct(xaxis);
\r
1905 M[0] = (T)xaxis.X;
\r
1906 M[1] = (T)yaxis.X;
\r
1907 M[2] = (T)zaxis.X;
\r
1910 M[4] = (T)xaxis.Y;
\r
1911 M[5] = (T)yaxis.Y;
\r
1912 M[6] = (T)zaxis.Y;
\r
1915 M[8] = (T)xaxis.Z;
\r
1916 M[9] = (T)yaxis.Z;
\r
1917 M[10] = (T)zaxis.Z;
\r
1920 M[12] = (T)-xaxis.dotProduct(position);
\r
1921 M[13] = (T)-yaxis.dotProduct(position);
\r
1922 M[14] = (T)-zaxis.dotProduct(position);
\r
1924 #if defined ( USE_MATRIX_TEST )
\r
1925 definitelyIdentityMatrix=false;
\r
1931 // Builds a right-handed look-at matrix.
\r
1932 template <class T>
\r
1933 inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixRH(
\r
1934 const vector3df& position,
\r
1935 const vector3df& target,
\r
1936 const vector3df& upVector)
\r
1938 vector3df zaxis = position - target;
\r
1939 zaxis.normalize();
\r
1941 vector3df xaxis = upVector.crossProduct(zaxis);
\r
1942 xaxis.normalize();
\r
1944 vector3df yaxis = zaxis.crossProduct(xaxis);
\r
1946 M[0] = (T)xaxis.X;
\r
1947 M[1] = (T)yaxis.X;
\r
1948 M[2] = (T)zaxis.X;
\r
1951 M[4] = (T)xaxis.Y;
\r
1952 M[5] = (T)yaxis.Y;
\r
1953 M[6] = (T)zaxis.Y;
\r
1956 M[8] = (T)xaxis.Z;
\r
1957 M[9] = (T)yaxis.Z;
\r
1958 M[10] = (T)zaxis.Z;
\r
1961 M[12] = (T)-xaxis.dotProduct(position);
\r
1962 M[13] = (T)-yaxis.dotProduct(position);
\r
1963 M[14] = (T)-zaxis.dotProduct(position);
\r
1965 #if defined ( USE_MATRIX_TEST )
\r
1966 definitelyIdentityMatrix=false;
\r
1972 // creates a new matrix as interpolated matrix from this and the passed one.
\r
1973 template <class T>
\r
1974 inline CMatrix4<T> CMatrix4<T>::interpolate(const core::CMatrix4<T>& b, f32 time) const
\r
1976 CMatrix4<T> mat ( EM4CONST_NOTHING );
\r
1978 for (u32 i=0; i < 16; i += 4)
\r
1980 mat.M[i+0] = (T)(M[i+0] + ( b.M[i+0] - M[i+0] ) * time);
\r
1981 mat.M[i+1] = (T)(M[i+1] + ( b.M[i+1] - M[i+1] ) * time);
\r
1982 mat.M[i+2] = (T)(M[i+2] + ( b.M[i+2] - M[i+2] ) * time);
\r
1983 mat.M[i+3] = (T)(M[i+3] + ( b.M[i+3] - M[i+3] ) * time);
\r
1989 // returns transposed matrix
\r
1990 template <class T>
\r
1991 inline CMatrix4<T> CMatrix4<T>::getTransposed() const
\r
1993 CMatrix4<T> t ( EM4CONST_NOTHING );
\r
1994 getTransposed ( t );
\r
1999 // returns transposed matrix
\r
2000 template <class T>
\r
2001 inline void CMatrix4<T>::getTransposed( CMatrix4<T>& o ) const
\r
2022 #if defined ( USE_MATRIX_TEST )
\r
2023 o.definitelyIdentityMatrix=definitelyIdentityMatrix;
\r
2028 // used to scale <-1,-1><1,1> to viewport
\r
2029 template <class T>
\r
2030 inline CMatrix4<T>& CMatrix4<T>::buildNDCToDCMatrix( const core::rect<s32>& viewport, f32 zScale)
\r
2032 const f32 scaleX = (viewport.getWidth() - 0.75f ) * 0.5f;
\r
2033 const f32 scaleY = -(viewport.getHeight() - 0.75f ) * 0.5f;
\r
2035 const f32 dx = -0.5f + ( (viewport.UpperLeftCorner.X + viewport.LowerRightCorner.X ) * 0.5f );
\r
2036 const f32 dy = -0.5f + ( (viewport.UpperLeftCorner.Y + viewport.LowerRightCorner.Y ) * 0.5f );
\r
2041 return setScale(core::vector3d<T>((T)scaleX, (T)scaleY, (T)zScale));
\r
2044 //! Builds a matrix that rotates from one vector to another
\r
2045 /** \param from: vector to rotate from
\r
2046 \param to: vector to rotate to
\r
2048 http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/index.htm
\r
2050 template <class T>
\r
2051 inline CMatrix4<T>& CMatrix4<T>::buildRotateFromTo(const core::vector3df& from, const core::vector3df& to)
\r
2054 core::vector3df f(from);
\r
2055 core::vector3df t(to);
\r
2059 // axis multiplication by sin
\r
2060 core::vector3df vs(t.crossProduct(f));
\r
2062 // axis of rotation
\r
2063 core::vector3df v(vs);
\r
2067 T ca = f.dotProduct(t);
\r
2069 core::vector3df vt(v * (1 - ca));
\r
2071 M[0] = vt.X * v.X + ca;
\r
2072 M[5] = vt.Y * v.Y + ca;
\r
2073 M[10] = vt.Z * v.Z + ca;
\r
2079 M[1] = vt.X - vs.Z;
\r
2080 M[2] = vt.Z + vs.Y;
\r
2083 M[4] = vt.X + vs.Z;
\r
2084 M[6] = vt.Y - vs.X;
\r
2087 M[8] = vt.Z - vs.Y;
\r
2088 M[9] = vt.Y + vs.X;
\r
2099 //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis
\r
2100 /** \param camPos: viewer position in world coord
\r
2101 \param center: object position in world-coord, rotation pivot
\r
2102 \param translation: object final translation from center
\r
2103 \param axis: axis to rotate about
\r
2104 \param from: source vector to rotate from
\r
2106 template <class T>
\r
2107 inline void CMatrix4<T>::buildAxisAlignedBillboard(
\r
2108 const core::vector3df& camPos,
\r
2109 const core::vector3df& center,
\r
2110 const core::vector3df& translation,
\r
2111 const core::vector3df& axis,
\r
2112 const core::vector3df& from)
\r
2114 // axis of rotation
\r
2115 core::vector3df up = axis;
\r
2117 const core::vector3df forward = (camPos - center).normalize();
\r
2118 const core::vector3df right = up.crossProduct(forward).normalize();
\r
2120 // correct look vector
\r
2121 const core::vector3df look = right.crossProduct(up);
\r
2124 // axis multiplication by sin
\r
2125 const core::vector3df vs = look.crossProduct(from);
\r
2128 const f32 ca = from.dotProduct(look);
\r
2130 core::vector3df vt(up * (1.f - ca));
\r
2132 M[0] = static_cast<T>(vt.X * up.X + ca);
\r
2133 M[5] = static_cast<T>(vt.Y * up.Y + ca);
\r
2134 M[10] = static_cast<T>(vt.Z * up.Z + ca);
\r
2140 M[1] = static_cast<T>(vt.X - vs.Z);
\r
2141 M[2] = static_cast<T>(vt.Z + vs.Y);
\r
2144 M[4] = static_cast<T>(vt.X + vs.Z);
\r
2145 M[6] = static_cast<T>(vt.Y - vs.X);
\r
2148 M[8] = static_cast<T>(vt.Z - vs.Y);
\r
2149 M[9] = static_cast<T>(vt.Y + vs.X);
\r
2152 setRotationCenter(center, translation);
\r
2156 //! Builds a combined matrix which translate to a center before rotation and translate afterward
\r
2157 template <class T>
\r
2158 inline void CMatrix4<T>::setRotationCenter(const core::vector3df& center, const core::vector3df& translation)
\r
2160 M[12] = -M[0]*center.X - M[4]*center.Y - M[8]*center.Z + (center.X - translation.X );
\r
2161 M[13] = -M[1]*center.X - M[5]*center.Y - M[9]*center.Z + (center.Y - translation.Y );
\r
2162 M[14] = -M[2]*center.X - M[6]*center.Y - M[10]*center.Z + (center.Z - translation.Z );
\r
2164 #if defined ( USE_MATRIX_TEST )
\r
2165 definitelyIdentityMatrix=false;
\r
2170 Generate texture coordinates as linear functions so that:
\r
2171 u = Ux*x + Uy*y + Uz*z + Uw
\r
2172 v = Vx*x + Vy*y + Vz*z + Vw
\r
2173 The matrix M for this case is:
\r
2181 template <class T>
\r
2182 inline CMatrix4<T>& CMatrix4<T>::buildTextureTransform( f32 rotateRad,
\r
2183 const core::vector2df &rotatecenter,
\r
2184 const core::vector2df &translate,
\r
2185 const core::vector2df &scale)
\r
2187 const f32 c = cosf(rotateRad);
\r
2188 const f32 s = sinf(rotateRad);
\r
2190 M[0] = (T)(c * scale.X);
\r
2191 M[1] = (T)(s * scale.Y);
\r
2195 M[4] = (T)(-s * scale.X);
\r
2196 M[5] = (T)(c * scale.Y);
\r
2200 M[8] = (T)(c * scale.X * rotatecenter.X + -s * rotatecenter.Y + translate.X);
\r
2201 M[9] = (T)(s * scale.Y * rotatecenter.X + c * rotatecenter.Y + translate.Y);
\r
2209 #if defined ( USE_MATRIX_TEST )
\r
2210 definitelyIdentityMatrix=false;
\r
2216 // rotate about z axis, center ( 0.5, 0.5 )
\r
2217 template <class T>
\r
2218 inline CMatrix4<T>& CMatrix4<T>::setTextureRotationCenter( f32 rotateRad )
\r
2220 const f32 c = cosf(rotateRad);
\r
2221 const f32 s = sinf(rotateRad);
\r
2228 M[8] = (T)(0.5f * ( s - c) + 0.5f);
\r
2229 M[9] = (T)(-0.5f * ( s + c) + 0.5f);
\r
2231 #if defined ( USE_MATRIX_TEST )
\r
2232 definitelyIdentityMatrix = definitelyIdentityMatrix && (rotateRad==0.0f);
\r
2238 template <class T>
\r
2239 inline CMatrix4<T>& CMatrix4<T>::setTextureTranslate ( f32 x, f32 y )
\r
2244 #if defined ( USE_MATRIX_TEST )
\r
2245 definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f);
\r
2250 template <class T>
\r
2251 inline void CMatrix4<T>::getTextureTranslate(f32& x, f32& y) const
\r
2257 template <class T>
\r
2258 inline CMatrix4<T>& CMatrix4<T>::setTextureTranslateTransposed ( f32 x, f32 y )
\r
2263 #if defined ( USE_MATRIX_TEST )
\r
2264 definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f);
\r
2269 template <class T>
\r
2270 inline CMatrix4<T>& CMatrix4<T>::setTextureScale ( f32 sx, f32 sy )
\r
2274 #if defined ( USE_MATRIX_TEST )
\r
2275 definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
\r
2280 template <class T>
\r
2281 inline void CMatrix4<T>::getTextureScale ( f32& sx, f32& sy ) const
\r
2287 template <class T>
\r
2288 inline CMatrix4<T>& CMatrix4<T>::setTextureScaleCenter( f32 sx, f32 sy )
\r
2292 M[8] = (T)(0.5f - 0.5f * sx);
\r
2293 M[9] = (T)(0.5f - 0.5f * sy);
\r
2295 #if defined ( USE_MATRIX_TEST )
\r
2296 definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
\r
2302 // sets all matrix data members at once
\r
2303 template <class T>
\r
2304 inline CMatrix4<T>& CMatrix4<T>::setM(const T* data)
\r
2306 memcpy(M,data, 16*sizeof(T));
\r
2308 #if defined ( USE_MATRIX_TEST )
\r
2309 definitelyIdentityMatrix=false;
\r
2315 // sets if the matrix is definitely identity matrix
\r
2316 template <class T>
\r
2317 inline void CMatrix4<T>::setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix)
\r
2319 #if defined ( USE_MATRIX_TEST )
\r
2320 definitelyIdentityMatrix = isDefinitelyIdentityMatrix;
\r
2322 (void)isDefinitelyIdentityMatrix; // prevent compiler warning
\r
2327 // gets if the matrix is definitely identity matrix
\r
2328 template <class T>
\r
2329 inline bool CMatrix4<T>::getDefinitelyIdentityMatrix() const
\r
2331 #if defined ( USE_MATRIX_TEST )
\r
2332 return definitelyIdentityMatrix;
\r
2339 //! Compare two matrices using the equal method
\r
2340 template <class T>
\r
2341 inline bool CMatrix4<T>::equals(const core::CMatrix4<T>& other, const T tolerance) const
\r
2343 #if defined ( USE_MATRIX_TEST )
\r
2344 if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
\r
2347 for (s32 i = 0; i < 16; ++i)
\r
2348 if (!core::equals(M[i],other.M[i], tolerance))
\r
2355 // Multiply by scalar.
\r
2356 template <class T>
\r
2357 inline CMatrix4<T> operator*(const T scalar, const CMatrix4<T>& mat)
\r
2359 return mat*scalar;
\r
2363 //! Typedef for f32 matrix
\r
2364 typedef CMatrix4<f32> matrix4;
\r
2366 //! global const identity matrix
\r
2367 IRRLICHT_API extern const matrix4 IdentityMatrix;
\r
2369 } // end namespace core
\r
2370 } // end namespace irr
\r