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 all elements of this matrix to the value.
\r
106 inline CMatrix4<T>& operator=(const T& scalar);
\r
108 //! Returns pointer to internal array
\r
109 const T* pointer() const { return M; }
\r
112 #if defined ( USE_MATRIX_TEST )
\r
113 definitelyIdentityMatrix=false;
\r
118 //! Returns true if other matrix is equal to this matrix.
\r
119 bool operator==(const CMatrix4<T> &other) const;
\r
121 //! Returns true if other matrix is not equal to this matrix.
\r
122 bool operator!=(const CMatrix4<T> &other) const;
\r
124 //! Add another matrix.
\r
125 CMatrix4<T> operator+(const CMatrix4<T>& other) const;
\r
127 //! Add another matrix.
\r
128 CMatrix4<T>& operator+=(const CMatrix4<T>& other);
\r
130 //! Subtract another matrix.
\r
131 CMatrix4<T> operator-(const CMatrix4<T>& other) const;
\r
133 //! Subtract another matrix.
\r
134 CMatrix4<T>& operator-=(const CMatrix4<T>& other);
\r
136 //! set this matrix to the product of two matrices
\r
137 /** Calculate b*a */
\r
138 inline CMatrix4<T>& setbyproduct(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b );
\r
140 //! Set this matrix to the product of two matrices
\r
141 /** Calculate b*a, no optimization used,
\r
142 use it if you know you never have a identity matrix */
\r
143 CMatrix4<T>& setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b );
\r
145 //! Multiply by another matrix.
\r
146 /** Calculate other*this */
\r
147 CMatrix4<T> operator*(const CMatrix4<T>& other) const;
\r
149 //! Multiply by another matrix.
\r
150 /** Calculate and return other*this */
\r
151 CMatrix4<T>& operator*=(const CMatrix4<T>& other);
\r
153 //! Multiply by scalar.
\r
154 CMatrix4<T> operator*(const T& scalar) const;
\r
156 //! Multiply by scalar.
\r
157 CMatrix4<T>& operator*=(const T& scalar);
\r
159 //! Set matrix to identity.
\r
160 inline CMatrix4<T>& makeIdentity();
\r
162 //! Returns true if the matrix is the identity matrix
\r
163 inline bool isIdentity() const;
\r
165 //! Returns true if the matrix is orthogonal
\r
166 inline bool isOrthogonal() const;
\r
168 //! Returns true if the matrix is the identity matrix
\r
169 bool isIdentity_integer_base () const;
\r
171 //! Set the translation of the current matrix. Will erase any previous values.
\r
172 CMatrix4<T>& setTranslation( const vector3d<T>& translation );
\r
174 //! Gets the current translation
\r
175 vector3d<T> getTranslation() const;
\r
177 //! Set the inverse translation of the current matrix. Will erase any previous values.
\r
178 CMatrix4<T>& setInverseTranslation( const vector3d<T>& translation );
\r
180 //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
\r
181 inline CMatrix4<T>& setRotationRadians( const vector3d<T>& rotation );
\r
183 //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
\r
184 CMatrix4<T>& setRotationDegrees( const vector3d<T>& rotation );
\r
186 //! Get the rotation, as set by setRotation() when you already know the scale.
\r
187 /** If you already know the scale then this function is faster than the other getRotationDegrees overload.
\r
188 NOTE: You will have the same end-rotation as used in setRotation, but it might not use the same axis values.
\r
190 core::vector3d<T> getRotationDegrees(const vector3d<T>& scale) const;
\r
192 //! Returns the rotation, as set by setRotation().
\r
193 /** NOTE: You will have the same end-rotation as used in setRotation, but it might not use the same axis values.
\r
195 core::vector3d<T> getRotationDegrees() const;
\r
197 //! Make an inverted rotation matrix from Euler angles.
\r
198 /** The 4th row and column are unmodified. */
\r
199 inline CMatrix4<T>& setInverseRotationRadians( const vector3d<T>& rotation );
\r
201 //! Make an inverted rotation matrix from Euler angles.
\r
202 /** The 4th row and column are unmodified. */
\r
203 inline CMatrix4<T>& setInverseRotationDegrees( const vector3d<T>& rotation );
\r
205 //! Make a rotation matrix from angle and axis, assuming left handed rotation.
\r
206 /** The 4th row and column are unmodified. */
\r
207 inline CMatrix4<T>& setRotationAxisRadians(const T& angle, const vector3d<T>& axis);
\r
210 CMatrix4<T>& setScale( const vector3d<T>& scale );
\r
213 CMatrix4<T>& setScale( const T scale ) { return setScale(core::vector3d<T>(scale,scale,scale)); }
\r
216 core::vector3d<T> getScale() const;
\r
218 //! Translate a vector by the inverse of the translation part of this matrix.
\r
219 void inverseTranslateVect( vector3df& vect ) const;
\r
221 //! Rotate a vector by the inverse of the rotation part of this matrix.
\r
222 void inverseRotateVect( vector3df& vect ) const;
\r
224 //! Rotate a vector by the rotation part of this matrix.
\r
225 void rotateVect( vector3df& vect ) const;
\r
227 //! An alternate transform vector method, writing into a second vector
\r
228 void rotateVect(core::vector3df& out, const core::vector3df& in) const;
\r
230 //! An alternate transform vector method, writing into an array of 3 floats
\r
231 void rotateVect(T *out,const core::vector3df &in) const;
\r
233 //! Transforms the vector by this matrix
\r
234 /** This operation is performed as if the vector was 4d with the 4th component =1 */
\r
235 void transformVect( vector3df& vect) const;
\r
237 //! Transforms input vector by this matrix and stores result in output vector
\r
238 /** This operation is performed as if the vector was 4d with the 4th component =1 */
\r
239 void transformVect( vector3df& out, const vector3df& in ) const;
\r
241 //! An alternate transform vector method, writing into an array of 4 floats
\r
242 /** This operation is performed as if the vector was 4d with the 4th component =1.
\r
243 NOTE: out[3] will be written to (4th vector component)*/
\r
244 void transformVect(T *out,const core::vector3df &in) const;
\r
246 //! An alternate transform vector method, reading from and writing to an array of 3 floats
\r
247 /** This operation is performed as if the vector was 4d with the 4th component =1
\r
248 NOTE: out[3] will be written to (4th vector component)*/
\r
249 void transformVec3(T *out, const T * in) const;
\r
251 //! An alternate transform vector method, reading from and writing to an array of 4 floats
\r
252 void transformVec4(T *out, const T * in) const;
\r
254 //! Translate a vector by the translation part of this matrix.
\r
255 /** This operation is performed as if the vector was 4d with the 4th component =1 */
\r
256 void translateVect( vector3df& vect ) const;
\r
258 //! Transforms a plane by this matrix
\r
259 void transformPlane( core::plane3d<f32> &plane) const;
\r
261 //! Transforms a plane by this matrix
\r
262 void transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const;
\r
264 //! Transforms a axis aligned bounding box
\r
265 /** The result box of this operation may not be accurate at all. For
\r
266 correct results, use transformBoxEx() */
\r
267 void transformBox(core::aabbox3d<f32>& box) const;
\r
269 //! Transforms a axis aligned bounding box
\r
270 /** The result box of this operation should be accurate, but this operation
\r
271 is slower than transformBox(). */
\r
272 void transformBoxEx(core::aabbox3d<f32>& box) const;
\r
274 //! Multiplies this matrix by a 1x4 matrix
\r
275 void multiplyWith1x4Matrix(T* matrix) const;
\r
277 //! Calculates inverse of matrix. Slow.
\r
278 /** \return Returns false if there is no inverse matrix.*/
\r
279 bool makeInverse();
\r
282 //! Inverts a primitive matrix which only contains a translation and a rotation
\r
283 /** \param out: where result matrix is written to. */
\r
284 bool getInversePrimitive ( CMatrix4<T>& out ) const;
\r
286 //! Gets the inverse matrix of this one
\r
287 /** \param out: where result matrix is written to.
\r
288 \return Returns false if there is no inverse matrix. */
\r
289 bool getInverse(CMatrix4<T>& out) const;
\r
291 //! Builds a right-handed perspective projection matrix based on a field of view
\r
292 //\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
293 CMatrix4<T>& buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
295 //! Builds a left-handed perspective projection matrix based on a field of view
\r
296 CMatrix4<T>& buildProjectionMatrixPerspectiveFovLH(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, with far plane at infinity
\r
299 CMatrix4<T>& buildProjectionMatrixPerspectiveFovInfinityLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon=0);
\r
301 //! Builds a right-handed perspective projection matrix.
\r
302 CMatrix4<T>& buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
304 //! Builds a left-handed perspective projection matrix.
\r
305 CMatrix4<T>& buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
307 //! Builds a left-handed orthogonal projection matrix.
\r
308 //\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
309 CMatrix4<T>& buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
311 //! Builds a right-handed orthogonal projection matrix.
\r
312 CMatrix4<T>& buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
314 //! Builds a left-handed look-at matrix.
\r
315 CMatrix4<T>& buildCameraLookAtMatrixLH(
\r
316 const vector3df& position,
\r
317 const vector3df& target,
\r
318 const vector3df& upVector);
\r
320 //! Builds a right-handed look-at matrix.
\r
321 CMatrix4<T>& buildCameraLookAtMatrixRH(
\r
322 const vector3df& position,
\r
323 const vector3df& target,
\r
324 const vector3df& upVector);
\r
326 //! Builds a matrix that flattens geometry into a plane.
\r
327 /** \param light: light source
\r
328 \param plane: plane into which the geometry if flattened into
\r
329 \param point: value between 0 and 1, describing the light source.
\r
330 If this is 1, it is a point light, if it is 0, it is a directional light. */
\r
331 CMatrix4<T>& buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point=1.0f);
\r
333 //! Builds a matrix which transforms a normalized Device Coordinate to Device Coordinates.
\r
334 /** Used to scale <-1,-1><1,1> to viewport, for example from <-1,-1> <1,1> to the viewport <0,0><0,640> */
\r
335 CMatrix4<T>& buildNDCToDCMatrix( const core::rect<s32>& area, f32 zScale);
\r
337 //! Creates a new matrix as interpolated matrix from two other ones.
\r
338 /** \param b: other matrix to interpolate with
\r
339 \param time: Must be a value between 0 and 1. */
\r
340 CMatrix4<T> interpolate(const core::CMatrix4<T>& b, f32 time) const;
\r
342 //! Gets transposed matrix
\r
343 CMatrix4<T> getTransposed() const;
\r
345 //! Gets transposed matrix
\r
346 inline void getTransposed( CMatrix4<T>& dest ) const;
\r
348 //! Builds a matrix that rotates from one vector to another
\r
349 /** \param from: vector to rotate from
\r
350 \param to: vector to rotate to
\r
352 CMatrix4<T>& buildRotateFromTo(const core::vector3df& from, const core::vector3df& to);
\r
354 //! Builds a combined matrix which translates to a center before rotation and translates from origin afterwards
\r
355 /** \param center Position to rotate around
\r
356 \param translate Translation applied after the rotation
\r
358 void setRotationCenter(const core::vector3df& center, const core::vector3df& translate);
\r
360 //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis
\r
361 /** \param camPos: viewer position in world coo
\r
362 \param center: object position in world-coo and rotation pivot
\r
363 \param translation: object final translation from center
\r
364 \param axis: axis to rotate about
\r
365 \param from: source vector to rotate from
\r
367 void buildAxisAlignedBillboard(const core::vector3df& camPos,
\r
368 const core::vector3df& center,
\r
369 const core::vector3df& translation,
\r
370 const core::vector3df& axis,
\r
371 const core::vector3df& from);
\r
374 construct 2D Texture transformations
\r
375 rotate about center, scale, and transform.
\r
377 //! Set to a texture transformation matrix with the given parameters.
\r
378 CMatrix4<T>& buildTextureTransform( f32 rotateRad,
\r
379 const core::vector2df &rotatecenter,
\r
380 const core::vector2df &translate,
\r
381 const core::vector2df &scale);
\r
383 //! Set texture transformation rotation
\r
384 /** Rotate about z axis, recenter at (0.5,0.5).
\r
385 Doesn't clear other elements than those affected
\r
386 \param radAngle Angle in radians
\r
387 \return Altered matrix */
\r
388 CMatrix4<T>& setTextureRotationCenter( f32 radAngle );
\r
390 //! Set texture transformation translation
\r
391 /** Doesn't clear other elements than those affected.
\r
392 \param x Offset on x axis
\r
393 \param y Offset on y axis
\r
394 \return Altered matrix */
\r
395 CMatrix4<T>& setTextureTranslate( f32 x, f32 y );
\r
397 //! Get texture transformation translation
\r
398 /** \param x returns offset on x axis
\r
399 \param y returns offset on y axis */
\r
400 void getTextureTranslate( f32& x, f32& y ) const;
\r
402 //! Set texture transformation translation, using a transposed representation
\r
403 /** Doesn't clear other elements than those affected.
\r
404 \param x Offset on x axis
\r
405 \param y Offset on y axis
\r
406 \return Altered matrix */
\r
407 CMatrix4<T>& setTextureTranslateTransposed( f32 x, f32 y );
\r
409 //! Set texture transformation scale
\r
410 /** Doesn't clear other elements than those affected.
\r
411 \param sx Scale factor on x axis
\r
412 \param sy Scale factor on y axis
\r
413 \return Altered matrix. */
\r
414 CMatrix4<T>& setTextureScale( f32 sx, f32 sy );
\r
416 //! Get texture transformation scale
\r
417 /** \param sx Returns x axis scale factor
\r
418 \param sy Returns y axis scale factor */
\r
419 void getTextureScale( f32& sx, f32& sy ) const;
\r
421 //! Set texture transformation scale, and recenter at (0.5,0.5)
\r
422 /** Doesn't clear other elements than those affected.
\r
423 \param sx Scale factor on x axis
\r
424 \param sy Scale factor on y axis
\r
425 \return Altered matrix. */
\r
426 CMatrix4<T>& setTextureScaleCenter( f32 sx, f32 sy );
\r
428 //! Sets all matrix data members at once
\r
429 CMatrix4<T>& setM(const T* data);
\r
431 //! Sets if the matrix is definitely identity matrix
\r
432 void setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix);
\r
434 //! Gets if the matrix is definitely identity matrix
\r
435 bool getDefinitelyIdentityMatrix() const;
\r
437 //! Compare two matrices using the equal method
\r
438 bool equals(const core::CMatrix4<T>& other, const T tolerance=(T)ROUNDING_ERROR_f64) const;
\r
441 //! Matrix data, stored in row-major order
\r
443 #if defined ( USE_MATRIX_TEST )
\r
444 //! Flag is this matrix is identity matrix
\r
445 mutable u32 definitelyIdentityMatrix;
\r
447 #if defined ( USE_MATRIX_TEST_DEBUG )
\r
454 // Default constructor
\r
456 inline CMatrix4<T>::CMatrix4( eConstructor constructor )
\r
457 #if defined ( USE_MATRIX_TEST )
\r
458 : definitelyIdentityMatrix(BIT_UNTESTED)
\r
460 #if defined ( USE_MATRIX_TEST_DEBUG )
\r
461 ,id ( MTest.ID++), calls ( 0 )
\r
464 switch ( constructor )
\r
466 case EM4CONST_NOTHING:
\r
467 case EM4CONST_COPY:
\r
469 case EM4CONST_IDENTITY:
\r
470 case EM4CONST_INVERSE:
\r
477 // Copy constructor
\r
479 inline CMatrix4<T>::CMatrix4( const CMatrix4<T>& other, eConstructor constructor)
\r
480 #if defined ( USE_MATRIX_TEST )
\r
481 : definitelyIdentityMatrix(BIT_UNTESTED)
\r
483 #if defined ( USE_MATRIX_TEST_DEBUG )
\r
484 ,id ( MTest.ID++), calls ( 0 )
\r
487 switch ( constructor )
\r
489 case EM4CONST_IDENTITY:
\r
492 case EM4CONST_NOTHING:
\r
494 case EM4CONST_COPY:
\r
497 case EM4CONST_TRANSPOSED:
\r
498 other.getTransposed(*this);
\r
500 case EM4CONST_INVERSE:
\r
501 if (!other.getInverse(*this))
\r
502 memset(M, 0, 16*sizeof(T));
\r
504 case EM4CONST_INVERSE_TRANSPOSED:
\r
505 if (!other.getInverse(*this))
\r
506 memset(M, 0, 16*sizeof(T));
\r
508 *this=getTransposed();
\r
513 //! Add another matrix.
\r
515 inline CMatrix4<T> CMatrix4<T>::operator+(const CMatrix4<T>& other) const
\r
517 CMatrix4<T> temp ( EM4CONST_NOTHING );
\r
519 temp[0] = M[0]+other[0];
\r
520 temp[1] = M[1]+other[1];
\r
521 temp[2] = M[2]+other[2];
\r
522 temp[3] = M[3]+other[3];
\r
523 temp[4] = M[4]+other[4];
\r
524 temp[5] = M[5]+other[5];
\r
525 temp[6] = M[6]+other[6];
\r
526 temp[7] = M[7]+other[7];
\r
527 temp[8] = M[8]+other[8];
\r
528 temp[9] = M[9]+other[9];
\r
529 temp[10] = M[10]+other[10];
\r
530 temp[11] = M[11]+other[11];
\r
531 temp[12] = M[12]+other[12];
\r
532 temp[13] = M[13]+other[13];
\r
533 temp[14] = M[14]+other[14];
\r
534 temp[15] = M[15]+other[15];
\r
539 //! Add another matrix.
\r
541 inline CMatrix4<T>& CMatrix4<T>::operator+=(const CMatrix4<T>& other)
\r
563 //! Subtract another matrix.
\r
565 inline CMatrix4<T> CMatrix4<T>::operator-(const CMatrix4<T>& other) const
\r
567 CMatrix4<T> temp ( EM4CONST_NOTHING );
\r
569 temp[0] = M[0]-other[0];
\r
570 temp[1] = M[1]-other[1];
\r
571 temp[2] = M[2]-other[2];
\r
572 temp[3] = M[3]-other[3];
\r
573 temp[4] = M[4]-other[4];
\r
574 temp[5] = M[5]-other[5];
\r
575 temp[6] = M[6]-other[6];
\r
576 temp[7] = M[7]-other[7];
\r
577 temp[8] = M[8]-other[8];
\r
578 temp[9] = M[9]-other[9];
\r
579 temp[10] = M[10]-other[10];
\r
580 temp[11] = M[11]-other[11];
\r
581 temp[12] = M[12]-other[12];
\r
582 temp[13] = M[13]-other[13];
\r
583 temp[14] = M[14]-other[14];
\r
584 temp[15] = M[15]-other[15];
\r
589 //! Subtract another matrix.
\r
591 inline CMatrix4<T>& CMatrix4<T>::operator-=(const CMatrix4<T>& other)
\r
613 //! Multiply by scalar.
\r
615 inline CMatrix4<T> CMatrix4<T>::operator*(const T& scalar) const
\r
617 CMatrix4<T> temp ( EM4CONST_NOTHING );
\r
619 temp[0] = M[0]*scalar;
\r
620 temp[1] = M[1]*scalar;
\r
621 temp[2] = M[2]*scalar;
\r
622 temp[3] = M[3]*scalar;
\r
623 temp[4] = M[4]*scalar;
\r
624 temp[5] = M[5]*scalar;
\r
625 temp[6] = M[6]*scalar;
\r
626 temp[7] = M[7]*scalar;
\r
627 temp[8] = M[8]*scalar;
\r
628 temp[9] = M[9]*scalar;
\r
629 temp[10] = M[10]*scalar;
\r
630 temp[11] = M[11]*scalar;
\r
631 temp[12] = M[12]*scalar;
\r
632 temp[13] = M[13]*scalar;
\r
633 temp[14] = M[14]*scalar;
\r
634 temp[15] = M[15]*scalar;
\r
639 //! Multiply by scalar.
\r
641 inline CMatrix4<T>& CMatrix4<T>::operator*=(const T& scalar)
\r
663 //! Multiply by another matrix.
\r
665 inline CMatrix4<T>& CMatrix4<T>::operator*=(const CMatrix4<T>& other)
\r
667 #if defined ( USE_MATRIX_TEST )
\r
668 // do checks on your own in order to avoid copy creation
\r
669 if ( !other.isIdentity() )
\r
671 if ( this->isIdentity() )
\r
673 return (*this = other);
\r
677 CMatrix4<T> temp ( *this );
\r
678 return setbyproduct_nocheck( temp, other );
\r
683 CMatrix4<T> temp ( *this );
\r
684 return setbyproduct_nocheck( temp, other );
\r
688 //! multiply by another matrix
\r
689 // set this matrix to the product of two other matrices
\r
690 // goal is to reduce stack use and copy
\r
692 inline CMatrix4<T>& CMatrix4<T>::setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b )
\r
694 const T *m1 = other_a.M;
\r
695 const T *m2 = other_b.M;
\r
697 M[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
\r
698 M[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
\r
699 M[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
\r
700 M[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
\r
702 M[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
\r
703 M[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
\r
704 M[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
\r
705 M[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
\r
707 M[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
\r
708 M[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
\r
709 M[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
\r
710 M[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
\r
712 M[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
\r
713 M[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
\r
714 M[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
\r
715 M[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
\r
716 #if defined ( USE_MATRIX_TEST )
\r
717 definitelyIdentityMatrix=false;
\r
723 //! multiply by another matrix
\r
724 // set this matrix to the product of two other matrices
\r
725 // goal is to reduce stack use and copy
\r
727 inline CMatrix4<T>& CMatrix4<T>::setbyproduct(const CMatrix4<T>& other_a, const CMatrix4<T>& other_b )
\r
729 #if defined ( USE_MATRIX_TEST )
\r
730 if ( other_a.isIdentity () )
\r
731 return (*this = other_b);
\r
733 if ( other_b.isIdentity () )
\r
734 return (*this = other_a);
\r
736 return setbyproduct_nocheck(other_a,other_b);
\r
738 return setbyproduct_nocheck(other_a,other_b);
\r
742 //! multiply by another matrix
\r
744 inline CMatrix4<T> CMatrix4<T>::operator*(const CMatrix4<T>& m2) const
\r
746 #if defined ( USE_MATRIX_TEST )
\r
747 // Testing purpose..
\r
748 if ( this->isIdentity() )
\r
750 if ( m2.isIdentity() )
\r
754 CMatrix4<T> m3 ( EM4CONST_NOTHING );
\r
758 m3[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
\r
759 m3[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
\r
760 m3[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
\r
761 m3[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
\r
763 m3[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
\r
764 m3[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
\r
765 m3[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
\r
766 m3[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
\r
768 m3[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
\r
769 m3[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
\r
770 m3[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
\r
771 m3[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
\r
773 m3[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
\r
774 m3[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
\r
775 m3[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
\r
776 m3[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
\r
783 inline vector3d<T> CMatrix4<T>::getTranslation() const
\r
785 return vector3d<T>(M[12], M[13], M[14]);
\r
790 inline CMatrix4<T>& CMatrix4<T>::setTranslation( const vector3d<T>& translation )
\r
792 M[12] = translation.X;
\r
793 M[13] = translation.Y;
\r
794 M[14] = translation.Z;
\r
795 #if defined ( USE_MATRIX_TEST )
\r
796 definitelyIdentityMatrix=false;
\r
802 inline CMatrix4<T>& CMatrix4<T>::setInverseTranslation( const vector3d<T>& translation )
\r
804 M[12] = -translation.X;
\r
805 M[13] = -translation.Y;
\r
806 M[14] = -translation.Z;
\r
807 #if defined ( USE_MATRIX_TEST )
\r
808 definitelyIdentityMatrix=false;
\r
814 inline CMatrix4<T>& CMatrix4<T>::setScale( const vector3d<T>& scale )
\r
819 #if defined ( USE_MATRIX_TEST )
\r
820 definitelyIdentityMatrix=false;
\r
825 //! Returns the absolute values of the scales of the matrix.
\r
827 Note that this returns the absolute (positive) values unless only scale is set.
\r
828 Unfortunately it does not appear to be possible to extract any original negative
\r
829 values. The best that we could do would be to arbitrarily make one scale
\r
830 negative if one or three of them were negative.
\r
831 FIXME - return the original values.
\r
834 inline vector3d<T> CMatrix4<T>::getScale() const
\r
836 // See http://www.robertblum.com/articles/2005/02/14/decomposing-matrices
\r
838 // Deal with the 0 rotation case first
\r
839 // Prior to Irrlicht 1.6, we always returned this value.
\r
840 if(core::iszero(M[1]) && core::iszero(M[2]) &&
\r
841 core::iszero(M[4]) && core::iszero(M[6]) &&
\r
842 core::iszero(M[8]) && core::iszero(M[9]))
\r
843 return vector3d<T>(M[0], M[5], M[10]);
\r
845 // We have to do the full calculation.
\r
846 return vector3d<T>(sqrtf(M[0] * M[0] + M[1] * M[1] + M[2] * M[2]),
\r
847 sqrtf(M[4] * M[4] + M[5] * M[5] + M[6] * M[6]),
\r
848 sqrtf(M[8] * M[8] + M[9] * M[9] + M[10] * M[10]));
\r
852 inline CMatrix4<T>& CMatrix4<T>::setRotationDegrees( const vector3d<T>& rotation )
\r
854 return setRotationRadians( rotation * core::DEGTORAD );
\r
858 inline CMatrix4<T>& CMatrix4<T>::setInverseRotationDegrees( const vector3d<T>& rotation )
\r
860 return setInverseRotationRadians( rotation * core::DEGTORAD );
\r
864 inline CMatrix4<T>& CMatrix4<T>::setRotationRadians( const vector3d<T>& rotation )
\r
866 const f64 cr = cos( rotation.X );
\r
867 const f64 sr = sin( rotation.X );
\r
868 const f64 cp = cos( rotation.Y );
\r
869 const f64 sp = sin( rotation.Y );
\r
870 const f64 cy = cos( rotation.Z );
\r
871 const f64 sy = sin( rotation.Z );
\r
873 M[0] = (T)( cp*cy );
\r
874 M[1] = (T)( cp*sy );
\r
877 const f64 srsp = sr*sp;
\r
878 const f64 crsp = cr*sp;
\r
880 M[4] = (T)( srsp*cy-cr*sy );
\r
881 M[5] = (T)( srsp*sy+cr*cy );
\r
882 M[6] = (T)( sr*cp );
\r
884 M[8] = (T)( crsp*cy+sr*sy );
\r
885 M[9] = (T)( crsp*sy-sr*cy );
\r
886 M[10] = (T)( cr*cp );
\r
887 #if defined ( USE_MATRIX_TEST )
\r
888 definitelyIdentityMatrix=false;
\r
894 //! Returns a rotation that is equivalent to that set by setRotationDegrees().
\r
895 /** This code was sent in by Chev. Note that it does not necessarily return
\r
896 the *same* Euler angles as those set by setRotationDegrees(), but the rotation will
\r
897 be equivalent, i.e. will have the same result when used to rotate a vector or node.
\r
898 This code was originally written by by Chev.
\r
901 inline core::vector3d<T> CMatrix4<T>::getRotationDegrees(const vector3d<T>& scale_) const
\r
903 const CMatrix4<T> &mat = *this;
\r
904 core::vector3d<T> scale(scale_);
\r
905 // we need to check for negative scale on to axes, which would bring up wrong results
\r
906 if (scale.Y<0 && scale.Z<0)
\r
911 else if (scale.X<0 && scale.Z<0)
\r
916 else if (scale.X<0 && scale.Y<0)
\r
921 const core::vector3d<f64> invScale(core::reciprocal(scale.X),core::reciprocal(scale.Y),core::reciprocal(scale.Z));
\r
923 f64 Y = -asin(core::clamp(mat[2]*invScale.X, -1.0, 1.0));
\r
924 const f64 C = cos(Y);
\r
927 f64 rotx, roty, X, Z;
\r
929 if (!core::iszero(C))
\r
931 const f64 invC = core::reciprocal(C);
\r
932 rotx = mat[10] * invC * invScale.Z;
\r
933 roty = mat[6] * invC * invScale.Y;
\r
934 X = atan2( roty, rotx ) * RADTODEG64;
\r
935 rotx = mat[0] * invC * invScale.X;
\r
936 roty = mat[1] * invC * invScale.X;
\r
937 Z = atan2( roty, rotx ) * RADTODEG64;
\r
942 rotx = mat[5] * invScale.Y;
\r
943 roty = -mat[4] * invScale.Y;
\r
944 Z = atan2( roty, rotx ) * RADTODEG64;
\r
947 // fix values that get below zero
\r
948 if (X < 0.0) X += 360.0;
\r
949 if (Y < 0.0) Y += 360.0;
\r
950 if (Z < 0.0) Z += 360.0;
\r
952 return vector3d<T>((T)X,(T)Y,(T)Z);
\r
955 //! Returns a rotation that is equivalent to that set by setRotationDegrees().
\r
956 /** This code was sent in by Chev. Note that it does not necessarily return
\r
957 the *same* Euler angles as those set by setRotationDegrees(), but the rotation will
\r
958 be equivalent, i.e. will have the same result when used to rotate a vector or node.
\r
959 This code was originally written by by Chev. */
\r
961 inline core::vector3d<T> CMatrix4<T>::getRotationDegrees() const
\r
963 return getRotationDegrees(getScale());
\r
967 //! Sets matrix to rotation matrix of inverse angles given as parameters
\r
969 inline CMatrix4<T>& CMatrix4<T>::setInverseRotationRadians( const vector3d<T>& rotation )
\r
971 f64 cr = cos( rotation.X );
\r
972 f64 sr = sin( rotation.X );
\r
973 f64 cp = cos( rotation.Y );
\r
974 f64 sp = sin( rotation.Y );
\r
975 f64 cy = cos( rotation.Z );
\r
976 f64 sy = sin( rotation.Z );
\r
978 M[0] = (T)( cp*cy );
\r
979 M[4] = (T)( cp*sy );
\r
985 M[1] = (T)( srsp*cy-cr*sy );
\r
986 M[5] = (T)( srsp*sy+cr*cy );
\r
987 M[9] = (T)( sr*cp );
\r
989 M[2] = (T)( crsp*cy+sr*sy );
\r
990 M[6] = (T)( crsp*sy-sr*cy );
\r
991 M[10] = (T)( cr*cp );
\r
992 #if defined ( USE_MATRIX_TEST )
\r
993 definitelyIdentityMatrix=false;
\r
998 //! Sets matrix to rotation matrix defined by axis and angle, assuming LH rotation
\r
1000 inline CMatrix4<T>& CMatrix4<T>::setRotationAxisRadians( const T& angle, const vector3d<T>& axis )
\r
1002 const f64 c = cos(angle);
\r
1003 const f64 s = sin(angle);
\r
1004 const f64 t = 1.0 - c;
\r
1006 const f64 tx = t * axis.X;
\r
1007 const f64 ty = t * axis.Y;
\r
1008 const f64 tz = t * axis.Z;
\r
1010 const f64 sx = s * axis.X;
\r
1011 const f64 sy = s * axis.Y;
\r
1012 const f64 sz = s * axis.Z;
\r
1014 M[0] = (T)(tx * axis.X + c);
\r
1015 M[1] = (T)(tx * axis.Y + sz);
\r
1016 M[2] = (T)(tx * axis.Z - sy);
\r
1018 M[4] = (T)(ty * axis.X - sz);
\r
1019 M[5] = (T)(ty * axis.Y + c);
\r
1020 M[6] = (T)(ty * axis.Z + sx);
\r
1022 M[8] = (T)(tz * axis.X + sy);
\r
1023 M[9] = (T)(tz * axis.Y - sx);
\r
1024 M[10] = (T)(tz * axis.Z + c);
\r
1026 #if defined ( USE_MATRIX_TEST )
\r
1027 definitelyIdentityMatrix=false;
\r
1035 template <class T>
\r
1036 inline CMatrix4<T>& CMatrix4<T>::makeIdentity()
\r
1038 memset(M, 0, 16*sizeof(T));
\r
1039 M[0] = M[5] = M[10] = M[15] = (T)1;
\r
1040 #if defined ( USE_MATRIX_TEST )
\r
1041 definitelyIdentityMatrix=true;
\r
1048 check identity with epsilon
\r
1049 solve floating range problems..
\r
1051 template <class T>
\r
1052 inline bool CMatrix4<T>::isIdentity() const
\r
1054 #if defined ( USE_MATRIX_TEST )
\r
1055 if (definitelyIdentityMatrix)
\r
1058 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
1061 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
1064 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
1067 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
1070 if (!core::equals( M[ 0], (T)1 ) ||
\r
1071 !core::equals( M[ 5], (T)1 ) ||
\r
1072 !core::equals( M[10], (T)1 ) ||
\r
1073 !core::equals( M[15], (T)1 ))
\r
1076 for (s32 i=0; i<4; ++i)
\r
1077 for (s32 j=0; j<4; ++j)
\r
1078 if ((j != i) && (!iszero((*this)(i,j))))
\r
1081 #if defined ( USE_MATRIX_TEST )
\r
1082 definitelyIdentityMatrix=true;
\r
1088 /* Check orthogonality of matrix. */
\r
1089 template <class T>
\r
1090 inline bool CMatrix4<T>::isOrthogonal() const
\r
1092 T dp=M[0] * M[4 ] + M[1] * M[5 ] + M[2 ] * M[6 ] + M[3 ] * M[7 ];
\r
1095 dp = M[0] * M[8 ] + M[1] * M[9 ] + M[2 ] * M[10] + M[3 ] * M[11];
\r
1098 dp = M[0] * M[12] + M[1] * M[13] + M[2 ] * M[14] + M[3 ] * M[15];
\r
1101 dp = M[4] * M[8 ] + M[5] * M[9 ] + M[6 ] * M[10] + M[7 ] * M[11];
\r
1104 dp = M[4] * M[12] + M[5] * M[13] + M[6 ] * M[14] + M[7 ] * M[15];
\r
1107 dp = M[8] * M[12] + M[9] * M[13] + M[10] * M[14] + M[11] * M[15];
\r
1108 return (iszero(dp));
\r
1113 doesn't solve floating range problems..
\r
1114 but takes care on +/- 0 on translation because we are changing it..
\r
1115 reducing floating point branches
\r
1116 but it needs the floats in memory..
\r
1118 template <class T>
\r
1119 inline bool CMatrix4<T>::isIdentity_integer_base() const
\r
1121 #if defined ( USE_MATRIX_TEST )
\r
1122 if (definitelyIdentityMatrix)
\r
1125 if(IR(M[0])!=F32_VALUE_1) return false;
\r
1126 if(IR(M[1])!=0) return false;
\r
1127 if(IR(M[2])!=0) return false;
\r
1128 if(IR(M[3])!=0) return false;
\r
1130 if(IR(M[4])!=0) return false;
\r
1131 if(IR(M[5])!=F32_VALUE_1) return false;
\r
1132 if(IR(M[6])!=0) return false;
\r
1133 if(IR(M[7])!=0) return false;
\r
1135 if(IR(M[8])!=0) return false;
\r
1136 if(IR(M[9])!=0) return false;
\r
1137 if(IR(M[10])!=F32_VALUE_1) return false;
\r
1138 if(IR(M[11])!=0) return false;
\r
1140 if(IR(M[12])!=0) return false;
\r
1141 if(IR(M[13])!=0) return false;
\r
1142 if(IR(M[13])!=0) return false;
\r
1143 if(IR(M[15])!=F32_VALUE_1) return false;
\r
1145 #if defined ( USE_MATRIX_TEST )
\r
1146 definitelyIdentityMatrix=true;
\r
1152 template <class T>
\r
1153 inline void CMatrix4<T>::rotateVect( vector3df& vect ) const
\r
1155 vector3df tmp = vect;
\r
1156 vect.X = tmp.X*M[0] + tmp.Y*M[4] + tmp.Z*M[8];
\r
1157 vect.Y = tmp.X*M[1] + tmp.Y*M[5] + tmp.Z*M[9];
\r
1158 vect.Z = tmp.X*M[2] + tmp.Y*M[6] + tmp.Z*M[10];
\r
1161 //! An alternate transform vector method, writing into a second vector
\r
1162 template <class T>
\r
1163 inline void CMatrix4<T>::rotateVect(core::vector3df& out, const core::vector3df& in) const
\r
1165 out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
\r
1166 out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
\r
1167 out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
\r
1170 //! An alternate transform vector method, writing into an array of 3 floats
\r
1171 template <class T>
\r
1172 inline void CMatrix4<T>::rotateVect(T *out, const core::vector3df& in) const
\r
1174 out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
\r
1175 out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
\r
1176 out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
\r
1179 template <class T>
\r
1180 inline void CMatrix4<T>::inverseRotateVect( vector3df& vect ) const
\r
1182 vector3df tmp = vect;
\r
1183 vect.X = tmp.X*M[0] + tmp.Y*M[1] + tmp.Z*M[2];
\r
1184 vect.Y = tmp.X*M[4] + tmp.Y*M[5] + tmp.Z*M[6];
\r
1185 vect.Z = tmp.X*M[8] + tmp.Y*M[9] + tmp.Z*M[10];
\r
1188 template <class T>
\r
1189 inline void CMatrix4<T>::transformVect( vector3df& vect) const
\r
1193 vector[0] = vect.X*M[0] + vect.Y*M[4] + vect.Z*M[8] + M[12];
\r
1194 vector[1] = vect.X*M[1] + vect.Y*M[5] + vect.Z*M[9] + M[13];
\r
1195 vector[2] = vect.X*M[2] + vect.Y*M[6] + vect.Z*M[10] + M[14];
\r
1197 vect.X = vector[0];
\r
1198 vect.Y = vector[1];
\r
1199 vect.Z = vector[2];
\r
1202 template <class T>
\r
1203 inline void CMatrix4<T>::transformVect( vector3df& out, const vector3df& in) const
\r
1205 out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
\r
1206 out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
\r
1207 out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
\r
1211 template <class T>
\r
1212 inline void CMatrix4<T>::transformVect(T *out, const core::vector3df &in) const
\r
1214 out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
\r
1215 out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
\r
1216 out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
\r
1217 out[3] = in.X*M[3] + in.Y*M[7] + in.Z*M[11] + M[15];
\r
1220 template <class T>
\r
1221 inline void CMatrix4<T>::transformVec3(T *out, const T * in) const
\r
1223 out[0] = in[0]*M[0] + in[1]*M[4] + in[2]*M[8] + M[12];
\r
1224 out[1] = in[0]*M[1] + in[1]*M[5] + in[2]*M[9] + M[13];
\r
1225 out[2] = in[0]*M[2] + in[1]*M[6] + in[2]*M[10] + M[14];
\r
1228 template <class T>
\r
1229 inline void CMatrix4<T>::transformVec4(T *out, const T * in) const
\r
1231 out[0] = in[0]*M[0] + in[1]*M[4] + in[2]*M[8] + in[3]*M[12];
\r
1232 out[1] = in[0]*M[1] + in[1]*M[5] + in[2]*M[9] + in[3]*M[13];
\r
1233 out[2] = in[0]*M[2] + in[1]*M[6] + in[2]*M[10] + in[3]*M[14];
\r
1234 out[3] = in[0]*M[3] + in[1]*M[7] + in[2]*M[11] + in[3]*M[15];
\r
1238 //! Transforms a plane by this matrix
\r
1239 template <class T>
\r
1240 inline void CMatrix4<T>::transformPlane( core::plane3d<f32> &plane) const
\r
1243 // Transform the plane member point, i.e. rotate, translate and scale it.
\r
1244 transformVect(member, plane.getMemberPoint());
\r
1246 // Transform the normal by the transposed inverse of the matrix
\r
1247 CMatrix4<T> transposedInverse(*this, EM4CONST_INVERSE_TRANSPOSED);
\r
1248 vector3df normal = plane.Normal;
\r
1249 transposedInverse.rotateVect(normal);
\r
1250 plane.setPlane(member, normal.normalize());
\r
1253 //! Transforms a plane by this matrix
\r
1254 template <class T>
\r
1255 inline void CMatrix4<T>::transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const
\r
1258 transformPlane( out );
\r
1261 //! Transforms the edge-points of a bounding box
\r
1262 //! Deprecated as it's usually not what people need (regards only 2 corners, but other corners might be outside the box after transformation)
\r
1263 //! Use transformBoxEx instead.
\r
1264 template <class T>
\r
1265 _IRR_DEPRECATED_ inline void CMatrix4<T>::transformBox(core::aabbox3d<f32>& box) const
\r
1267 #if defined ( USE_MATRIX_TEST )
\r
1272 transformVect(box.MinEdge);
\r
1273 transformVect(box.MaxEdge);
\r
1277 //! Transforms a axis aligned bounding box more accurately than transformBox()
\r
1278 template <class T>
\r
1279 inline void CMatrix4<T>::transformBoxEx(core::aabbox3d<f32>& box) const
\r
1281 #if defined ( USE_MATRIX_TEST )
\r
1286 const f32 Amin[3] = {box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z};
\r
1287 const f32 Amax[3] = {box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z};
\r
1292 Bmin[0] = Bmax[0] = M[12];
\r
1293 Bmin[1] = Bmax[1] = M[13];
\r
1294 Bmin[2] = Bmax[2] = M[14];
\r
1296 const CMatrix4<T> &m = *this;
\r
1298 for (u32 i = 0; i < 3; ++i)
\r
1300 for (u32 j = 0; j < 3; ++j)
\r
1302 const f32 a = m(j,i) * Amin[j];
\r
1303 const f32 b = m(j,i) * Amax[j];
\r
1318 box.MinEdge.X = Bmin[0];
\r
1319 box.MinEdge.Y = Bmin[1];
\r
1320 box.MinEdge.Z = Bmin[2];
\r
1322 box.MaxEdge.X = Bmax[0];
\r
1323 box.MaxEdge.Y = Bmax[1];
\r
1324 box.MaxEdge.Z = Bmax[2];
\r
1328 //! Multiplies this matrix by a 1x4 matrix
\r
1329 template <class T>
\r
1330 inline void CMatrix4<T>::multiplyWith1x4Matrix(T* matrix) const
\r
1340 mat[0] = matrix[0];
\r
1341 mat[1] = matrix[1];
\r
1342 mat[2] = matrix[2];
\r
1343 mat[3] = matrix[3];
\r
1345 matrix[0] = M[0]*mat[0] + M[4]*mat[1] + M[8]*mat[2] + M[12]*mat[3];
\r
1346 matrix[1] = M[1]*mat[0] + M[5]*mat[1] + M[9]*mat[2] + M[13]*mat[3];
\r
1347 matrix[2] = M[2]*mat[0] + M[6]*mat[1] + M[10]*mat[2] + M[14]*mat[3];
\r
1348 matrix[3] = M[3]*mat[0] + M[7]*mat[1] + M[11]*mat[2] + M[15]*mat[3];
\r
1351 template <class T>
\r
1352 inline void CMatrix4<T>::inverseTranslateVect( vector3df& vect ) const
\r
1354 vect.X = vect.X-M[12];
\r
1355 vect.Y = vect.Y-M[13];
\r
1356 vect.Z = vect.Z-M[14];
\r
1359 template <class T>
\r
1360 inline void CMatrix4<T>::translateVect( vector3df& vect ) const
\r
1362 vect.X = vect.X+M[12];
\r
1363 vect.Y = vect.Y+M[13];
\r
1364 vect.Z = vect.Z+M[14];
\r
1368 template <class T>
\r
1369 inline bool CMatrix4<T>::getInverse(CMatrix4<T>& out) const
\r
1371 /// Calculates the inverse of this Matrix
\r
1372 /// The inverse is calculated using Cramers rule.
\r
1373 /// If no inverse exists then 'false' is returned.
\r
1375 #if defined ( USE_MATRIX_TEST )
\r
1376 if ( this->isIdentity() )
\r
1382 const CMatrix4<T> &m = *this;
\r
1384 f32 d = (m[0] * m[5] - m[1] * m[4]) * (m[10] * m[15] - m[11] * m[14]) -
\r
1385 (m[0] * m[6] - m[2] * m[4]) * (m[9] * m[15] - m[11] * m[13]) +
\r
1386 (m[0] * m[7] - m[3] * m[4]) * (m[9] * m[14] - m[10] * m[13]) +
\r
1387 (m[1] * m[6] - m[2] * m[5]) * (m[8] * m[15] - m[11] * m[12]) -
\r
1388 (m[1] * m[7] - m[3] * m[5]) * (m[8] * m[14] - m[10] * m[12]) +
\r
1389 (m[2] * m[7] - m[3] * m[6]) * (m[8] * m[13] - m[9] * m[12]);
\r
1391 if( core::iszero ( d, FLT_MIN ) )
\r
1394 d = core::reciprocal ( d );
\r
1396 out[0] = d * (m[5] * (m[10] * m[15] - m[11] * m[14]) +
\r
1397 m[6] * (m[11] * m[13] - m[9] * m[15]) +
\r
1398 m[7] * (m[9] * m[14] - m[10] * m[13]));
\r
1399 out[1] = d * (m[9] * (m[2] * m[15] - m[3] * m[14]) +
\r
1400 m[10] * (m[3] * m[13] - m[1] * m[15]) +
\r
1401 m[11] * (m[1] * m[14] - m[2] * m[13]));
\r
1402 out[2] = d * (m[13] * (m[2] * m[7] - m[3] * m[6]) +
\r
1403 m[14] * (m[3] * m[5] - m[1] * m[7]) +
\r
1404 m[15] * (m[1] * m[6] - m[2] * m[5]));
\r
1405 out[3] = d * (m[1] * (m[7] * m[10] - m[6] * m[11]) +
\r
1406 m[2] * (m[5] * m[11] - m[7] * m[9]) +
\r
1407 m[3] * (m[6] * m[9] - m[5] * m[10]));
\r
1408 out[4] = d * (m[6] * (m[8] * m[15] - m[11] * m[12]) +
\r
1409 m[7] * (m[10] * m[12] - m[8] * m[14]) +
\r
1410 m[4] * (m[11] * m[14] - m[10] * m[15]));
\r
1411 out[5] = d * (m[10] * (m[0] * m[15] - m[3] * m[12]) +
\r
1412 m[11] * (m[2] * m[12] - m[0] * m[14]) +
\r
1413 m[8] * (m[3] * m[14] - m[2] * m[15]));
\r
1414 out[6] = d * (m[14] * (m[0] * m[7] - m[3] * m[4]) +
\r
1415 m[15] * (m[2] * m[4] - m[0] * m[6]) +
\r
1416 m[12] * (m[3] * m[6] - m[2] * m[7]));
\r
1417 out[7] = d * (m[2] * (m[7] * m[8] - m[4] * m[11]) +
\r
1418 m[3] * (m[4] * m[10] - m[6] * m[8]) +
\r
1419 m[0] * (m[6] * m[11] - m[7] * m[10]));
\r
1420 out[8] = d * (m[7] * (m[8] * m[13] - m[9] * m[12]) +
\r
1421 m[4] * (m[9] * m[15] - m[11] * m[13]) +
\r
1422 m[5] * (m[11] * m[12] - m[8] * m[15]));
\r
1423 out[9] = d * (m[11] * (m[0] * m[13] - m[1] * m[12]) +
\r
1424 m[8] * (m[1] * m[15] - m[3] * m[13]) +
\r
1425 m[9] * (m[3] * m[12] - m[0] * m[15]));
\r
1426 out[10] = d * (m[15] * (m[0] * m[5] - m[1] * m[4]) +
\r
1427 m[12] * (m[1] * m[7] - m[3] * m[5]) +
\r
1428 m[13] * (m[3] * m[4] - m[0] * m[7]));
\r
1429 out[11] = d * (m[3] * (m[5] * m[8] - m[4] * m[9]) +
\r
1430 m[0] * (m[7] * m[9] - m[5] * m[11]) +
\r
1431 m[1] * (m[4] * m[11] - m[7] * m[8]));
\r
1432 out[12] = d * (m[4] * (m[10] * m[13] - m[9] * m[14]) +
\r
1433 m[5] * (m[8] * m[14] - m[10] * m[12]) +
\r
1434 m[6] * (m[9] * m[12] - m[8] * m[13]));
\r
1435 out[13] = d * (m[8] * (m[2] * m[13] - m[1] * m[14]) +
\r
1436 m[9] * (m[0] * m[14] - m[2] * m[12]) +
\r
1437 m[10] * (m[1] * m[12] - m[0] * m[13]));
\r
1438 out[14] = d * (m[12] * (m[2] * m[5] - m[1] * m[6]) +
\r
1439 m[13] * (m[0] * m[6] - m[2] * m[4]) +
\r
1440 m[14] * (m[1] * m[4] - m[0] * m[5]));
\r
1441 out[15] = d * (m[0] * (m[5] * m[10] - m[6] * m[9]) +
\r
1442 m[1] * (m[6] * m[8] - m[4] * m[10]) +
\r
1443 m[2] * (m[4] * m[9] - m[5] * m[8]));
\r
1445 #if defined ( USE_MATRIX_TEST )
\r
1446 out.definitelyIdentityMatrix = definitelyIdentityMatrix;
\r
1452 //! Inverts a primitive matrix which only contains a translation and a rotation
\r
1453 //! \param out: where result matrix is written to.
\r
1454 template <class T>
\r
1455 inline bool CMatrix4<T>::getInversePrimitive ( CMatrix4<T>& out ) const
\r
1469 out.M[10] = M[10];
\r
1472 out.M[12] = (T)-(M[12]*M[0] + M[13]*M[1] + M[14]*M[2]);
\r
1473 out.M[13] = (T)-(M[12]*M[4] + M[13]*M[5] + M[14]*M[6]);
\r
1474 out.M[14] = (T)-(M[12]*M[8] + M[13]*M[9] + M[14]*M[10]);
\r
1477 #if defined ( USE_MATRIX_TEST )
\r
1478 out.definitelyIdentityMatrix = definitelyIdentityMatrix;
\r
1485 template <class T>
\r
1486 inline bool CMatrix4<T>::makeInverse()
\r
1488 #if defined ( USE_MATRIX_TEST )
\r
1489 if (definitelyIdentityMatrix)
\r
1492 CMatrix4<T> temp ( EM4CONST_NOTHING );
\r
1494 if (getInverse(temp))
\r
1504 template <class T>
\r
1505 inline CMatrix4<T>& CMatrix4<T>::operator=(const T& scalar)
\r
1507 for (s32 i = 0; i < 16; ++i)
\r
1510 #if defined ( USE_MATRIX_TEST )
\r
1511 definitelyIdentityMatrix=false;
\r
1517 template <class T>
\r
1518 inline bool CMatrix4<T>::operator==(const CMatrix4<T> &other) const
\r
1520 #if defined ( USE_MATRIX_TEST )
\r
1521 if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
\r
1524 for (s32 i = 0; i < 16; ++i)
\r
1525 if (M[i] != other.M[i])
\r
1532 template <class T>
\r
1533 inline bool CMatrix4<T>::operator!=(const CMatrix4<T> &other) const
\r
1535 return !(*this == other);
\r
1539 // Builds a right-handed perspective projection matrix based on a field of view
\r
1540 template <class T>
\r
1541 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovRH(
\r
1542 f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1544 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
\r
1545 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
\r
1546 const T w = static_cast<T>(h / aspectRatio);
\r
1548 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1569 if ( zClipFromZero ) // DirectX version
\r
1571 M[10] = (T)(zFar/(zNear-zFar));
\r
1572 M[14] = (T)(zNear*zFar/(zNear-zFar));
\r
1574 else // OpenGL version
\r
1576 M[10] = (T)((zFar+zNear)/(zNear-zFar));
\r
1577 M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
\r
1580 #if defined ( USE_MATRIX_TEST )
\r
1581 definitelyIdentityMatrix=false;
\r
1587 // Builds a left-handed perspective projection matrix based on a field of view
\r
1588 template <class T>
\r
1589 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovLH(
\r
1590 f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1592 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
\r
1593 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
\r
1594 const T w = static_cast<T>(h / aspectRatio);
\r
1596 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1617 if ( zClipFromZero ) // DirectX version
\r
1619 M[10] = (T)(zFar/(zFar-zNear));
\r
1620 M[14] = (T)(-zNear*zFar/(zFar-zNear));
\r
1622 else // OpenGL version
\r
1624 M[10] = (T)((zFar+zNear)/(zFar-zNear));
\r
1625 M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
\r
1628 #if defined ( USE_MATRIX_TEST )
\r
1629 definitelyIdentityMatrix=false;
\r
1635 // Builds a left-handed perspective projection matrix based on a field of view, with far plane culling at infinity
\r
1636 template <class T>
\r
1637 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovInfinityLH(
\r
1638 f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon)
\r
1640 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
\r
1641 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
\r
1642 const T w = static_cast<T>(h / aspectRatio);
\r
1656 M[10] = (T)(1.f-epsilon);
\r
1661 M[14] = (T)(zNear*(epsilon-1.f));
\r
1664 #if defined ( USE_MATRIX_TEST )
\r
1665 definitelyIdentityMatrix=false;
\r
1671 // Builds a left-handed orthogonal projection matrix.
\r
1672 template <class T>
\r
1673 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoLH(
\r
1674 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1676 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
\r
1677 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
\r
1678 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1679 M[0] = (T)(2/widthOfViewVolume);
\r
1685 M[5] = (T)(2/heightOfViewVolume);
\r
1699 if ( zClipFromZero )
\r
1701 M[10] = (T)(1/(zFar-zNear));
\r
1702 M[14] = (T)(zNear/(zNear-zFar));
\r
1706 M[10] = (T)(2/(zFar-zNear));
\r
1707 M[14] = (T)-(zFar+zNear)/(zFar-zNear);
\r
1710 #if defined ( USE_MATRIX_TEST )
\r
1711 definitelyIdentityMatrix=false;
\r
1717 // Builds a right-handed orthogonal projection matrix.
\r
1718 template <class T>
\r
1719 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoRH(
\r
1720 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1722 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
\r
1723 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
\r
1724 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1725 M[0] = (T)(2/widthOfViewVolume);
\r
1731 M[5] = (T)(2/heightOfViewVolume);
\r
1745 if ( zClipFromZero )
\r
1747 M[10] = (T)(1/(zNear-zFar));
\r
1748 M[14] = (T)(zNear/(zNear-zFar));
\r
1752 M[10] = (T)(2/(zNear-zFar));
\r
1753 M[14] = (T)-(zFar+zNear)/(zFar-zNear);
\r
1756 #if defined ( USE_MATRIX_TEST )
\r
1757 definitelyIdentityMatrix=false;
\r
1763 // Builds a right-handed perspective projection matrix.
\r
1764 template <class T>
\r
1765 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveRH(
\r
1766 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1768 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
\r
1769 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
\r
1770 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1771 M[0] = (T)(2*zNear/widthOfViewVolume);
\r
1777 M[5] = (T)(2*zNear/heightOfViewVolume);
\r
1791 if ( zClipFromZero ) // DirectX version
\r
1793 M[10] = (T)(zFar/(zNear-zFar));
\r
1794 M[14] = (T)(zNear*zFar/(zNear-zFar));
\r
1796 else // OpenGL version
\r
1798 M[10] = (T)((zFar+zNear)/(zNear-zFar));
\r
1799 M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
\r
1802 #if defined ( USE_MATRIX_TEST )
\r
1803 definitelyIdentityMatrix=false;
\r
1809 // Builds a left-handed perspective projection matrix.
\r
1810 template <class T>
\r
1811 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveLH(
\r
1812 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1814 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
\r
1815 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
\r
1816 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1817 M[0] = (T)(2*zNear/widthOfViewVolume);
\r
1823 M[5] = (T)(2*zNear/heightOfViewVolume);
\r
1834 //M[14] = (T)(zNear*zFar/(zNear-zFar));
\r
1837 if ( zClipFromZero ) // DirectX version
\r
1839 M[10] = (T)(zFar/(zFar-zNear));
\r
1840 M[14] = (T)(zNear*zFar/(zNear-zFar));
\r
1842 else // OpenGL version
\r
1844 M[10] = (T)((zFar+zNear)/(zFar-zNear));
\r
1845 M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
\r
1848 #if defined ( USE_MATRIX_TEST )
\r
1849 definitelyIdentityMatrix=false;
\r
1855 // Builds a matrix that flattens geometry into a plane.
\r
1856 template <class T>
\r
1857 inline CMatrix4<T>& CMatrix4<T>::buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point)
\r
1859 plane.Normal.normalize();
\r
1860 const f32 d = plane.Normal.dotProduct(light);
\r
1862 M[ 0] = (T)(-plane.Normal.X * light.X + d);
\r
1863 M[ 1] = (T)(-plane.Normal.X * light.Y);
\r
1864 M[ 2] = (T)(-plane.Normal.X * light.Z);
\r
1865 M[ 3] = (T)(-plane.Normal.X * point);
\r
1867 M[ 4] = (T)(-plane.Normal.Y * light.X);
\r
1868 M[ 5] = (T)(-plane.Normal.Y * light.Y + d);
\r
1869 M[ 6] = (T)(-plane.Normal.Y * light.Z);
\r
1870 M[ 7] = (T)(-plane.Normal.Y * point);
\r
1872 M[ 8] = (T)(-plane.Normal.Z * light.X);
\r
1873 M[ 9] = (T)(-plane.Normal.Z * light.Y);
\r
1874 M[10] = (T)(-plane.Normal.Z * light.Z + d);
\r
1875 M[11] = (T)(-plane.Normal.Z * point);
\r
1877 M[12] = (T)(-plane.D * light.X);
\r
1878 M[13] = (T)(-plane.D * light.Y);
\r
1879 M[14] = (T)(-plane.D * light.Z);
\r
1880 M[15] = (T)(-plane.D * point + d);
\r
1881 #if defined ( USE_MATRIX_TEST )
\r
1882 definitelyIdentityMatrix=false;
\r
1887 // Builds a left-handed look-at matrix.
\r
1888 template <class T>
\r
1889 inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixLH(
\r
1890 const vector3df& position,
\r
1891 const vector3df& target,
\r
1892 const vector3df& upVector)
\r
1894 vector3df zaxis = target - position;
\r
1895 zaxis.normalize();
\r
1897 vector3df xaxis = upVector.crossProduct(zaxis);
\r
1898 xaxis.normalize();
\r
1900 vector3df yaxis = zaxis.crossProduct(xaxis);
\r
1902 M[0] = (T)xaxis.X;
\r
1903 M[1] = (T)yaxis.X;
\r
1904 M[2] = (T)zaxis.X;
\r
1907 M[4] = (T)xaxis.Y;
\r
1908 M[5] = (T)yaxis.Y;
\r
1909 M[6] = (T)zaxis.Y;
\r
1912 M[8] = (T)xaxis.Z;
\r
1913 M[9] = (T)yaxis.Z;
\r
1914 M[10] = (T)zaxis.Z;
\r
1917 M[12] = (T)-xaxis.dotProduct(position);
\r
1918 M[13] = (T)-yaxis.dotProduct(position);
\r
1919 M[14] = (T)-zaxis.dotProduct(position);
\r
1921 #if defined ( USE_MATRIX_TEST )
\r
1922 definitelyIdentityMatrix=false;
\r
1928 // Builds a right-handed look-at matrix.
\r
1929 template <class T>
\r
1930 inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixRH(
\r
1931 const vector3df& position,
\r
1932 const vector3df& target,
\r
1933 const vector3df& upVector)
\r
1935 vector3df zaxis = position - target;
\r
1936 zaxis.normalize();
\r
1938 vector3df xaxis = upVector.crossProduct(zaxis);
\r
1939 xaxis.normalize();
\r
1941 vector3df yaxis = zaxis.crossProduct(xaxis);
\r
1943 M[0] = (T)xaxis.X;
\r
1944 M[1] = (T)yaxis.X;
\r
1945 M[2] = (T)zaxis.X;
\r
1948 M[4] = (T)xaxis.Y;
\r
1949 M[5] = (T)yaxis.Y;
\r
1950 M[6] = (T)zaxis.Y;
\r
1953 M[8] = (T)xaxis.Z;
\r
1954 M[9] = (T)yaxis.Z;
\r
1955 M[10] = (T)zaxis.Z;
\r
1958 M[12] = (T)-xaxis.dotProduct(position);
\r
1959 M[13] = (T)-yaxis.dotProduct(position);
\r
1960 M[14] = (T)-zaxis.dotProduct(position);
\r
1962 #if defined ( USE_MATRIX_TEST )
\r
1963 definitelyIdentityMatrix=false;
\r
1969 // creates a new matrix as interpolated matrix from this and the passed one.
\r
1970 template <class T>
\r
1971 inline CMatrix4<T> CMatrix4<T>::interpolate(const core::CMatrix4<T>& b, f32 time) const
\r
1973 CMatrix4<T> mat ( EM4CONST_NOTHING );
\r
1975 for (u32 i=0; i < 16; i += 4)
\r
1977 mat.M[i+0] = (T)(M[i+0] + ( b.M[i+0] - M[i+0] ) * time);
\r
1978 mat.M[i+1] = (T)(M[i+1] + ( b.M[i+1] - M[i+1] ) * time);
\r
1979 mat.M[i+2] = (T)(M[i+2] + ( b.M[i+2] - M[i+2] ) * time);
\r
1980 mat.M[i+3] = (T)(M[i+3] + ( b.M[i+3] - M[i+3] ) * time);
\r
1986 // returns transposed matrix
\r
1987 template <class T>
\r
1988 inline CMatrix4<T> CMatrix4<T>::getTransposed() const
\r
1990 CMatrix4<T> t ( EM4CONST_NOTHING );
\r
1991 getTransposed ( t );
\r
1996 // returns transposed matrix
\r
1997 template <class T>
\r
1998 inline void CMatrix4<T>::getTransposed( CMatrix4<T>& o ) const
\r
2019 #if defined ( USE_MATRIX_TEST )
\r
2020 o.definitelyIdentityMatrix=definitelyIdentityMatrix;
\r
2025 // used to scale <-1,-1><1,1> to viewport
\r
2026 template <class T>
\r
2027 inline CMatrix4<T>& CMatrix4<T>::buildNDCToDCMatrix( const core::rect<s32>& viewport, f32 zScale)
\r
2029 const f32 scaleX = (viewport.getWidth() - 0.75f ) * 0.5f;
\r
2030 const f32 scaleY = -(viewport.getHeight() - 0.75f ) * 0.5f;
\r
2032 const f32 dx = -0.5f + ( (viewport.UpperLeftCorner.X + viewport.LowerRightCorner.X ) * 0.5f );
\r
2033 const f32 dy = -0.5f + ( (viewport.UpperLeftCorner.Y + viewport.LowerRightCorner.Y ) * 0.5f );
\r
2038 return setScale(core::vector3d<T>((T)scaleX, (T)scaleY, (T)zScale));
\r
2041 //! Builds a matrix that rotates from one vector to another
\r
2042 /** \param from: vector to rotate from
\r
2043 \param to: vector to rotate to
\r
2045 http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/index.htm
\r
2047 template <class T>
\r
2048 inline CMatrix4<T>& CMatrix4<T>::buildRotateFromTo(const core::vector3df& from, const core::vector3df& to)
\r
2051 core::vector3df f(from);
\r
2052 core::vector3df t(to);
\r
2056 // axis multiplication by sin
\r
2057 core::vector3df vs(t.crossProduct(f));
\r
2059 // axis of rotation
\r
2060 core::vector3df v(vs);
\r
2064 T ca = f.dotProduct(t);
\r
2066 core::vector3df vt(v * (1 - ca));
\r
2068 M[0] = vt.X * v.X + ca;
\r
2069 M[5] = vt.Y * v.Y + ca;
\r
2070 M[10] = vt.Z * v.Z + ca;
\r
2076 M[1] = vt.X - vs.Z;
\r
2077 M[2] = vt.Z + vs.Y;
\r
2080 M[4] = vt.X + vs.Z;
\r
2081 M[6] = vt.Y - vs.X;
\r
2084 M[8] = vt.Z - vs.Y;
\r
2085 M[9] = vt.Y + vs.X;
\r
2096 //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis
\r
2097 /** \param camPos: viewer position in world coord
\r
2098 \param center: object position in world-coord, rotation pivot
\r
2099 \param translation: object final translation from center
\r
2100 \param axis: axis to rotate about
\r
2101 \param from: source vector to rotate from
\r
2103 template <class T>
\r
2104 inline void CMatrix4<T>::buildAxisAlignedBillboard(
\r
2105 const core::vector3df& camPos,
\r
2106 const core::vector3df& center,
\r
2107 const core::vector3df& translation,
\r
2108 const core::vector3df& axis,
\r
2109 const core::vector3df& from)
\r
2111 // axis of rotation
\r
2112 core::vector3df up = axis;
\r
2114 const core::vector3df forward = (camPos - center).normalize();
\r
2115 const core::vector3df right = up.crossProduct(forward).normalize();
\r
2117 // correct look vector
\r
2118 const core::vector3df look = right.crossProduct(up);
\r
2121 // axis multiplication by sin
\r
2122 const core::vector3df vs = look.crossProduct(from);
\r
2125 const f32 ca = from.dotProduct(look);
\r
2127 core::vector3df vt(up * (1.f - ca));
\r
2129 M[0] = static_cast<T>(vt.X * up.X + ca);
\r
2130 M[5] = static_cast<T>(vt.Y * up.Y + ca);
\r
2131 M[10] = static_cast<T>(vt.Z * up.Z + ca);
\r
2137 M[1] = static_cast<T>(vt.X - vs.Z);
\r
2138 M[2] = static_cast<T>(vt.Z + vs.Y);
\r
2141 M[4] = static_cast<T>(vt.X + vs.Z);
\r
2142 M[6] = static_cast<T>(vt.Y - vs.X);
\r
2145 M[8] = static_cast<T>(vt.Z - vs.Y);
\r
2146 M[9] = static_cast<T>(vt.Y + vs.X);
\r
2149 setRotationCenter(center, translation);
\r
2153 //! Builds a combined matrix which translate to a center before rotation and translate afterward
\r
2154 template <class T>
\r
2155 inline void CMatrix4<T>::setRotationCenter(const core::vector3df& center, const core::vector3df& translation)
\r
2157 M[12] = -M[0]*center.X - M[4]*center.Y - M[8]*center.Z + (center.X - translation.X );
\r
2158 M[13] = -M[1]*center.X - M[5]*center.Y - M[9]*center.Z + (center.Y - translation.Y );
\r
2159 M[14] = -M[2]*center.X - M[6]*center.Y - M[10]*center.Z + (center.Z - translation.Z );
\r
2161 #if defined ( USE_MATRIX_TEST )
\r
2162 definitelyIdentityMatrix=false;
\r
2167 Generate texture coordinates as linear functions so that:
\r
2168 u = Ux*x + Uy*y + Uz*z + Uw
\r
2169 v = Vx*x + Vy*y + Vz*z + Vw
\r
2170 The matrix M for this case is:
\r
2178 template <class T>
\r
2179 inline CMatrix4<T>& CMatrix4<T>::buildTextureTransform( f32 rotateRad,
\r
2180 const core::vector2df &rotatecenter,
\r
2181 const core::vector2df &translate,
\r
2182 const core::vector2df &scale)
\r
2184 const f32 c = cosf(rotateRad);
\r
2185 const f32 s = sinf(rotateRad);
\r
2187 M[0] = (T)(c * scale.X);
\r
2188 M[1] = (T)(s * scale.Y);
\r
2192 M[4] = (T)(-s * scale.X);
\r
2193 M[5] = (T)(c * scale.Y);
\r
2197 M[8] = (T)(c * scale.X * rotatecenter.X + -s * rotatecenter.Y + translate.X);
\r
2198 M[9] = (T)(s * scale.Y * rotatecenter.X + c * rotatecenter.Y + translate.Y);
\r
2206 #if defined ( USE_MATRIX_TEST )
\r
2207 definitelyIdentityMatrix=false;
\r
2213 // rotate about z axis, center ( 0.5, 0.5 )
\r
2214 template <class T>
\r
2215 inline CMatrix4<T>& CMatrix4<T>::setTextureRotationCenter( f32 rotateRad )
\r
2217 const f32 c = cosf(rotateRad);
\r
2218 const f32 s = sinf(rotateRad);
\r
2225 M[8] = (T)(0.5f * ( s - c) + 0.5f);
\r
2226 M[9] = (T)(-0.5f * ( s + c) + 0.5f);
\r
2228 #if defined ( USE_MATRIX_TEST )
\r
2229 definitelyIdentityMatrix = definitelyIdentityMatrix && (rotateRad==0.0f);
\r
2235 template <class T>
\r
2236 inline CMatrix4<T>& CMatrix4<T>::setTextureTranslate ( f32 x, f32 y )
\r
2241 #if defined ( USE_MATRIX_TEST )
\r
2242 definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f);
\r
2247 template <class T>
\r
2248 inline void CMatrix4<T>::getTextureTranslate(f32& x, f32& y) const
\r
2254 template <class T>
\r
2255 inline CMatrix4<T>& CMatrix4<T>::setTextureTranslateTransposed ( f32 x, f32 y )
\r
2260 #if defined ( USE_MATRIX_TEST )
\r
2261 definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f);
\r
2266 template <class T>
\r
2267 inline CMatrix4<T>& CMatrix4<T>::setTextureScale ( f32 sx, f32 sy )
\r
2271 #if defined ( USE_MATRIX_TEST )
\r
2272 definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
\r
2277 template <class T>
\r
2278 inline void CMatrix4<T>::getTextureScale ( f32& sx, f32& sy ) const
\r
2284 template <class T>
\r
2285 inline CMatrix4<T>& CMatrix4<T>::setTextureScaleCenter( f32 sx, f32 sy )
\r
2289 M[8] = (T)(0.5f - 0.5f * sx);
\r
2290 M[9] = (T)(0.5f - 0.5f * sy);
\r
2292 #if defined ( USE_MATRIX_TEST )
\r
2293 definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
\r
2299 // sets all matrix data members at once
\r
2300 template <class T>
\r
2301 inline CMatrix4<T>& CMatrix4<T>::setM(const T* data)
\r
2303 memcpy(M,data, 16*sizeof(T));
\r
2305 #if defined ( USE_MATRIX_TEST )
\r
2306 definitelyIdentityMatrix=false;
\r
2312 // sets if the matrix is definitely identity matrix
\r
2313 template <class T>
\r
2314 inline void CMatrix4<T>::setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix)
\r
2316 #if defined ( USE_MATRIX_TEST )
\r
2317 definitelyIdentityMatrix = isDefinitelyIdentityMatrix;
\r
2319 (void)isDefinitelyIdentityMatrix; // prevent compiler warning
\r
2324 // gets if the matrix is definitely identity matrix
\r
2325 template <class T>
\r
2326 inline bool CMatrix4<T>::getDefinitelyIdentityMatrix() const
\r
2328 #if defined ( USE_MATRIX_TEST )
\r
2329 return definitelyIdentityMatrix;
\r
2336 //! Compare two matrices using the equal method
\r
2337 template <class T>
\r
2338 inline bool CMatrix4<T>::equals(const core::CMatrix4<T>& other, const T tolerance) const
\r
2340 #if defined ( USE_MATRIX_TEST )
\r
2341 if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
\r
2344 for (s32 i = 0; i < 16; ++i)
\r
2345 if (!core::equals(M[i],other.M[i], tolerance))
\r
2352 // Multiply by scalar.
\r
2353 template <class T>
\r
2354 inline CMatrix4<T> operator*(const T scalar, const CMatrix4<T>& mat)
\r
2356 return mat*scalar;
\r
2360 //! Typedef for f32 matrix
\r
2361 typedef CMatrix4<f32> matrix4;
\r
2363 //! global const identity matrix
\r
2364 IRRLICHT_API extern const matrix4 IdentityMatrix;
\r
2366 } // end namespace core
\r
2367 } // end namespace irr
\r