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
15 #include "IrrCompileConfig.h" // for IRRLICHT_API
\r
17 // enable this to keep track of changes to the matrix
\r
18 // and make simpler identity check for seldom changing matrices
\r
19 // otherwise identity check will always compare the elements
\r
20 //#define USE_MATRIX_TEST
\r
22 // this is only for debugging purposes
\r
23 //#define USE_MATRIX_TEST_DEBUG
\r
25 #if defined( USE_MATRIX_TEST_DEBUG )
\r
29 MatrixTest () : ID(0), Calls(0) {}
\r
34 static MatrixTest MTest;
\r
43 //! 4x4 matrix. Mostly used as transformation matrix for 3d calculations.
\r
44 /** The matrix is a D3D style matrix, row major with translations in the 4th row. */
\r
50 //! Constructor Flags
\r
53 EM4CONST_NOTHING = 0,
\r
56 EM4CONST_TRANSPOSED,
\r
58 EM4CONST_INVERSE_TRANSPOSED
\r
61 //! Default constructor
\r
62 /** \param constructor Choose the initialization style */
\r
63 CMatrix4( eConstructor constructor = EM4CONST_IDENTITY );
\r
65 //! Constructor with value initialization
\r
66 CMatrix4(const T& r0c0, const T& r0c1, const T& r0c2, const T& r0c3,
\r
67 const T& r1c0, const T& r1c1, const T& r1c2, const T& r1c3,
\r
68 const T& r2c0, const T& r2c1, const T& r2c2, const T& r2c3,
\r
69 const T& r3c0, const T& r3c1, const T& r3c2, const T& r3c3)
\r
71 M[0] = r0c0; M[1] = r0c1; M[2] = r0c2; M[3] = r0c3;
\r
72 M[4] = r1c0; M[5] = r1c1; M[6] = r1c2; M[7] = r1c3;
\r
73 M[8] = r2c0; M[9] = r2c1; M[10] = r2c2; M[11] = r2c3;
\r
74 M[12] = r3c0; M[13] = r3c1; M[14] = r3c2; M[15] = r3c3;
\r
77 //! Copy constructor
\r
78 /** \param other Other matrix to copy from
\r
79 \param constructor Choose the initialization style */
\r
80 CMatrix4(const CMatrix4<T>& other, eConstructor constructor = EM4CONST_COPY);
\r
82 //! Simple operator for directly accessing every element of the matrix.
\r
83 T& operator()(const s32 row, const s32 col)
\r
85 #if defined ( USE_MATRIX_TEST )
\r
86 definitelyIdentityMatrix=false;
\r
88 return M[ row * 4 + col ];
\r
91 //! Simple operator for directly accessing every element of the matrix.
\r
92 const T& operator()(const s32 row, const s32 col) const { return M[row * 4 + col]; }
\r
94 //! Simple operator for linearly accessing every element of the matrix.
\r
95 T& operator[](u32 index)
\r
97 #if defined ( USE_MATRIX_TEST )
\r
98 definitelyIdentityMatrix=false;
\r
103 //! Simple operator for linearly accessing every element of the matrix.
\r
104 const T& operator[](u32 index) const { return M[index]; }
\r
106 //! Sets this matrix equal to the other matrix.
\r
107 CMatrix4<T>& operator=(const CMatrix4<T> &other) = default;
\r
109 //! Sets all elements of this matrix to the value.
\r
110 inline CMatrix4<T>& operator=(const T& scalar);
\r
112 //! Returns pointer to internal array
\r
113 const T* pointer() const { return M; }
\r
116 #if defined ( USE_MATRIX_TEST )
\r
117 definitelyIdentityMatrix=false;
\r
122 //! Returns true if other matrix is equal to this matrix.
\r
123 bool operator==(const CMatrix4<T> &other) const;
\r
125 //! Returns true if other matrix is not equal to this matrix.
\r
126 bool operator!=(const CMatrix4<T> &other) const;
\r
128 //! Add another matrix.
\r
129 CMatrix4<T> operator+(const CMatrix4<T>& other) const;
\r
131 //! Add another matrix.
\r
132 CMatrix4<T>& operator+=(const CMatrix4<T>& other);
\r
134 //! Subtract another matrix.
\r
135 CMatrix4<T> operator-(const CMatrix4<T>& other) const;
\r
137 //! Subtract another matrix.
\r
138 CMatrix4<T>& operator-=(const CMatrix4<T>& other);
\r
140 //! set this matrix to the product of two matrices
\r
141 /** Calculate b*a */
\r
142 inline CMatrix4<T>& setbyproduct(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b );
\r
144 //! Set this matrix to the product of two matrices
\r
145 /** Calculate b*a, no optimization used,
\r
146 use it if you know you never have a identity matrix */
\r
147 CMatrix4<T>& setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b );
\r
149 //! Multiply by another matrix.
\r
150 /** Calculate other*this */
\r
151 CMatrix4<T> operator*(const CMatrix4<T>& other) const;
\r
153 //! Multiply by another matrix.
\r
154 /** Calculate and return other*this */
\r
155 CMatrix4<T>& operator*=(const CMatrix4<T>& other);
\r
157 //! Multiply by scalar.
\r
158 CMatrix4<T> operator*(const T& scalar) const;
\r
160 //! Multiply by scalar.
\r
161 CMatrix4<T>& operator*=(const T& scalar);
\r
163 //! Set matrix to identity.
\r
164 inline CMatrix4<T>& makeIdentity();
\r
166 //! Returns true if the matrix is the identity matrix
\r
167 inline bool isIdentity() const;
\r
169 //! Returns true if the matrix is orthogonal
\r
170 inline bool isOrthogonal() const;
\r
172 //! Returns true if the matrix is the identity matrix
\r
173 bool isIdentity_integer_base () const;
\r
175 //! Set the translation of the current matrix. Will erase any previous values.
\r
176 CMatrix4<T>& setTranslation( const vector3d<T>& translation );
\r
178 //! Gets the current translation
\r
179 vector3d<T> getTranslation() const;
\r
181 //! Set the inverse translation of the current matrix. Will erase any previous values.
\r
182 CMatrix4<T>& setInverseTranslation( const vector3d<T>& translation );
\r
184 //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
\r
185 inline CMatrix4<T>& setRotationRadians( const vector3d<T>& rotation );
\r
187 //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
\r
188 CMatrix4<T>& setRotationDegrees( const vector3d<T>& rotation );
\r
190 //! Get the rotation, as set by setRotation() when you already know the scale.
\r
191 /** If you already know the scale then this function is faster than the other getRotationDegrees overload.
\r
192 NOTE: You will have the same end-rotation as used in setRotation, but it might not use the same axis values.
\r
194 core::vector3d<T> getRotationDegrees(const vector3d<T>& scale) const;
\r
196 //! Returns the rotation, as set by setRotation().
\r
197 /** NOTE: You will have the same end-rotation as used in setRotation, but it might not use the same axis values.
\r
199 core::vector3d<T> getRotationDegrees() const;
\r
201 //! Make an inverted rotation matrix from Euler angles.
\r
202 /** The 4th row and column are unmodified. */
\r
203 inline CMatrix4<T>& setInverseRotationRadians( const vector3d<T>& rotation );
\r
205 //! Make an inverted rotation matrix from Euler angles.
\r
206 /** The 4th row and column are unmodified. */
\r
207 inline CMatrix4<T>& setInverseRotationDegrees( const vector3d<T>& rotation );
\r
209 //! Make a rotation matrix from angle and axis, assuming left handed rotation.
\r
210 /** The 4th row and column are unmodified. */
\r
211 inline CMatrix4<T>& setRotationAxisRadians(const T& angle, const vector3d<T>& axis);
\r
214 CMatrix4<T>& setScale( const vector3d<T>& scale );
\r
217 CMatrix4<T>& setScale( const T scale ) { return setScale(core::vector3d<T>(scale,scale,scale)); }
\r
220 core::vector3d<T> getScale() const;
\r
222 //! Translate a vector by the inverse of the translation part of this matrix.
\r
223 void inverseTranslateVect( vector3df& vect ) const;
\r
225 //! Rotate a vector by the inverse of the rotation part of this matrix.
\r
226 void inverseRotateVect( vector3df& vect ) const;
\r
228 //! Rotate a vector by the rotation part of this matrix.
\r
229 void rotateVect( vector3df& vect ) const;
\r
231 //! An alternate transform vector method, writing into a second vector
\r
232 void rotateVect(core::vector3df& out, const core::vector3df& in) const;
\r
234 //! An alternate transform vector method, writing into an array of 3 floats
\r
235 void rotateVect(T *out,const core::vector3df &in) const;
\r
237 //! Transforms the vector by this matrix
\r
238 /** This operation is performed as if the vector was 4d with the 4th component =1 */
\r
239 void transformVect( vector3df& vect) const;
\r
241 //! Transforms input vector by this matrix and stores result in output vector
\r
242 /** This operation is performed as if the vector was 4d with the 4th component =1 */
\r
243 void transformVect( vector3df& out, const vector3df& in ) const;
\r
245 //! An alternate transform vector method, writing into an array of 4 floats
\r
246 /** This operation is performed as if the vector was 4d with the 4th component =1.
\r
247 NOTE: out[3] will be written to (4th vector component)*/
\r
248 void transformVect(T *out,const core::vector3df &in) const;
\r
250 //! An alternate transform vector method, reading from and writing to an array of 3 floats
\r
251 /** This operation is performed as if the vector was 4d with the 4th component =1
\r
252 NOTE: out[3] will be written to (4th vector component)*/
\r
253 void transformVec3(T *out, const T * in) const;
\r
255 //! An alternate transform vector method, reading from and writing to an array of 4 floats
\r
256 void transformVec4(T *out, const T * in) const;
\r
258 //! Translate a vector by the translation part of this matrix.
\r
259 /** This operation is performed as if the vector was 4d with the 4th component =1 */
\r
260 void translateVect( vector3df& vect ) const;
\r
262 //! Transforms a plane by this matrix
\r
263 void transformPlane( core::plane3d<f32> &plane) const;
\r
265 //! Transforms a plane by this matrix
\r
266 void transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const;
\r
268 //! Transforms a axis aligned bounding box
\r
269 /** The result box of this operation may not be accurate at all. For
\r
270 correct results, use transformBoxEx() */
\r
271 void transformBox(core::aabbox3d<f32>& box) const;
\r
273 //! Transforms a axis aligned bounding box
\r
274 /** The result box of this operation should be accurate, but this operation
\r
275 is slower than transformBox(). */
\r
276 void transformBoxEx(core::aabbox3d<f32>& box) const;
\r
278 //! Multiplies this matrix by a 1x4 matrix
\r
279 void multiplyWith1x4Matrix(T* matrix) const;
\r
281 //! Calculates inverse of matrix. Slow.
\r
282 /** \return Returns false if there is no inverse matrix.*/
\r
283 bool makeInverse();
\r
286 //! Inverts a primitive matrix which only contains a translation and a rotation
\r
287 /** \param out: where result matrix is written to. */
\r
288 bool getInversePrimitive ( CMatrix4<T>& out ) const;
\r
290 //! Gets the inverse matrix of this one
\r
291 /** \param out: where result matrix is written to.
\r
292 \return Returns false if there is no inverse matrix. */
\r
293 bool getInverse(CMatrix4<T>& out) const;
\r
295 //! Builds a right-handed perspective projection matrix based on a field of view
\r
296 //\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
297 CMatrix4<T>& buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
299 //! Builds a left-handed perspective projection matrix based on a field of view
\r
300 CMatrix4<T>& buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
302 //! Builds a left-handed perspective projection matrix based on a field of view, with far plane at infinity
\r
303 CMatrix4<T>& buildProjectionMatrixPerspectiveFovInfinityLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon=0);
\r
305 //! Builds a right-handed perspective projection matrix.
\r
306 CMatrix4<T>& buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
308 //! Builds a left-handed perspective projection matrix.
\r
309 CMatrix4<T>& buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
311 //! Builds a left-handed orthogonal projection matrix.
\r
312 //\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
313 CMatrix4<T>& buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
315 //! Builds a right-handed orthogonal projection matrix.
\r
316 CMatrix4<T>& buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
318 //! Builds a left-handed look-at matrix.
\r
319 CMatrix4<T>& buildCameraLookAtMatrixLH(
\r
320 const vector3df& position,
\r
321 const vector3df& target,
\r
322 const vector3df& upVector);
\r
324 //! Builds a right-handed look-at matrix.
\r
325 CMatrix4<T>& buildCameraLookAtMatrixRH(
\r
326 const vector3df& position,
\r
327 const vector3df& target,
\r
328 const vector3df& upVector);
\r
330 //! Builds a matrix that flattens geometry into a plane.
\r
331 /** \param light: light source
\r
332 \param plane: plane into which the geometry if flattened into
\r
333 \param point: value between 0 and 1, describing the light source.
\r
334 If this is 1, it is a point light, if it is 0, it is a directional light. */
\r
335 CMatrix4<T>& buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point=1.0f);
\r
337 //! Builds a matrix which transforms a normalized Device Coordinate to Device Coordinates.
\r
338 /** Used to scale <-1,-1><1,1> to viewport, for example from <-1,-1> <1,1> to the viewport <0,0><0,640> */
\r
339 CMatrix4<T>& buildNDCToDCMatrix( const core::rect<s32>& area, f32 zScale);
\r
341 //! Creates a new matrix as interpolated matrix from two other ones.
\r
342 /** \param b: other matrix to interpolate with
\r
343 \param time: Must be a value between 0 and 1. */
\r
344 CMatrix4<T> interpolate(const core::CMatrix4<T>& b, f32 time) const;
\r
346 //! Gets transposed matrix
\r
347 CMatrix4<T> getTransposed() const;
\r
349 //! Gets transposed matrix
\r
350 inline void getTransposed( CMatrix4<T>& dest ) const;
\r
352 //! Builds a matrix that rotates from one vector to another
\r
353 /** \param from: vector to rotate from
\r
354 \param to: vector to rotate to
\r
356 CMatrix4<T>& buildRotateFromTo(const core::vector3df& from, const core::vector3df& to);
\r
358 //! Builds a combined matrix which translates to a center before rotation and translates from origin afterwards
\r
359 /** \param center Position to rotate around
\r
360 \param translate Translation applied after the rotation
\r
362 void setRotationCenter(const core::vector3df& center, const core::vector3df& translate);
\r
364 //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis
\r
365 /** \param camPos: viewer position in world coo
\r
366 \param center: object position in world-coo and rotation pivot
\r
367 \param translation: object final translation from center
\r
368 \param axis: axis to rotate about
\r
369 \param from: source vector to rotate from
\r
371 void buildAxisAlignedBillboard(const core::vector3df& camPos,
\r
372 const core::vector3df& center,
\r
373 const core::vector3df& translation,
\r
374 const core::vector3df& axis,
\r
375 const core::vector3df& from);
\r
378 construct 2D Texture transformations
\r
379 rotate about center, scale, and transform.
\r
381 //! Set to a texture transformation matrix with the given parameters.
\r
382 CMatrix4<T>& buildTextureTransform( f32 rotateRad,
\r
383 const core::vector2df &rotatecenter,
\r
384 const core::vector2df &translate,
\r
385 const core::vector2df &scale);
\r
387 //! Set texture transformation rotation
\r
388 /** Rotate about z axis, recenter at (0.5,0.5).
\r
389 Doesn't clear other elements than those affected
\r
390 \param radAngle Angle in radians
\r
391 \return Altered matrix */
\r
392 CMatrix4<T>& setTextureRotationCenter( f32 radAngle );
\r
394 //! Set texture transformation translation
\r
395 /** Doesn't clear other elements than those affected.
\r
396 \param x Offset on x axis
\r
397 \param y Offset on y axis
\r
398 \return Altered matrix */
\r
399 CMatrix4<T>& setTextureTranslate( f32 x, f32 y );
\r
401 //! Get texture transformation translation
\r
402 /** \param x returns offset on x axis
\r
403 \param y returns offset on y axis */
\r
404 void getTextureTranslate( f32& x, f32& y ) const;
\r
406 //! Set texture transformation translation, using a transposed representation
\r
407 /** Doesn't clear other elements than those affected.
\r
408 \param x Offset on x axis
\r
409 \param y Offset on y axis
\r
410 \return Altered matrix */
\r
411 CMatrix4<T>& setTextureTranslateTransposed( f32 x, f32 y );
\r
413 //! Set texture transformation scale
\r
414 /** Doesn't clear other elements than those affected.
\r
415 \param sx Scale factor on x axis
\r
416 \param sy Scale factor on y axis
\r
417 \return Altered matrix. */
\r
418 CMatrix4<T>& setTextureScale( f32 sx, f32 sy );
\r
420 //! Get texture transformation scale
\r
421 /** \param sx Returns x axis scale factor
\r
422 \param sy Returns y axis scale factor */
\r
423 void getTextureScale( f32& sx, f32& sy ) const;
\r
425 //! Set texture transformation scale, and recenter at (0.5,0.5)
\r
426 /** Doesn't clear other elements than those affected.
\r
427 \param sx Scale factor on x axis
\r
428 \param sy Scale factor on y axis
\r
429 \return Altered matrix. */
\r
430 CMatrix4<T>& setTextureScaleCenter( f32 sx, f32 sy );
\r
432 //! Sets all matrix data members at once
\r
433 CMatrix4<T>& setM(const T* data);
\r
435 //! Sets if the matrix is definitely identity matrix
\r
436 void setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix);
\r
438 //! Gets if the matrix is definitely identity matrix
\r
439 bool getDefinitelyIdentityMatrix() const;
\r
441 //! Compare two matrices using the equal method
\r
442 bool equals(const core::CMatrix4<T>& other, const T tolerance=(T)ROUNDING_ERROR_f64) const;
\r
445 //! Matrix data, stored in row-major order
\r
447 #if defined ( USE_MATRIX_TEST )
\r
448 //! Flag is this matrix is identity matrix
\r
449 mutable u32 definitelyIdentityMatrix;
\r
451 #if defined ( USE_MATRIX_TEST_DEBUG )
\r
458 // Default constructor
\r
460 inline CMatrix4<T>::CMatrix4( eConstructor constructor )
\r
461 #if defined ( USE_MATRIX_TEST )
\r
462 : definitelyIdentityMatrix(BIT_UNTESTED)
\r
464 #if defined ( USE_MATRIX_TEST_DEBUG )
\r
465 ,id ( MTest.ID++), calls ( 0 )
\r
468 switch ( constructor )
\r
470 case EM4CONST_NOTHING:
\r
471 case EM4CONST_COPY:
\r
473 case EM4CONST_IDENTITY:
\r
474 case EM4CONST_INVERSE:
\r
481 // Copy constructor
\r
483 inline CMatrix4<T>::CMatrix4( const CMatrix4<T>& other, eConstructor constructor)
\r
484 #if defined ( USE_MATRIX_TEST )
\r
485 : definitelyIdentityMatrix(BIT_UNTESTED)
\r
487 #if defined ( USE_MATRIX_TEST_DEBUG )
\r
488 ,id ( MTest.ID++), calls ( 0 )
\r
491 switch ( constructor )
\r
493 case EM4CONST_IDENTITY:
\r
496 case EM4CONST_NOTHING:
\r
498 case EM4CONST_COPY:
\r
501 case EM4CONST_TRANSPOSED:
\r
502 other.getTransposed(*this);
\r
504 case EM4CONST_INVERSE:
\r
505 if (!other.getInverse(*this))
\r
506 memset(M, 0, 16*sizeof(T));
\r
508 case EM4CONST_INVERSE_TRANSPOSED:
\r
509 if (!other.getInverse(*this))
\r
510 memset(M, 0, 16*sizeof(T));
\r
512 *this=getTransposed();
\r
517 //! Add another matrix.
\r
519 inline CMatrix4<T> CMatrix4<T>::operator+(const CMatrix4<T>& other) const
\r
521 CMatrix4<T> temp ( EM4CONST_NOTHING );
\r
523 temp[0] = M[0]+other[0];
\r
524 temp[1] = M[1]+other[1];
\r
525 temp[2] = M[2]+other[2];
\r
526 temp[3] = M[3]+other[3];
\r
527 temp[4] = M[4]+other[4];
\r
528 temp[5] = M[5]+other[5];
\r
529 temp[6] = M[6]+other[6];
\r
530 temp[7] = M[7]+other[7];
\r
531 temp[8] = M[8]+other[8];
\r
532 temp[9] = M[9]+other[9];
\r
533 temp[10] = M[10]+other[10];
\r
534 temp[11] = M[11]+other[11];
\r
535 temp[12] = M[12]+other[12];
\r
536 temp[13] = M[13]+other[13];
\r
537 temp[14] = M[14]+other[14];
\r
538 temp[15] = M[15]+other[15];
\r
543 //! Add another matrix.
\r
545 inline CMatrix4<T>& CMatrix4<T>::operator+=(const CMatrix4<T>& other)
\r
567 //! Subtract another matrix.
\r
569 inline CMatrix4<T> CMatrix4<T>::operator-(const CMatrix4<T>& other) const
\r
571 CMatrix4<T> temp ( EM4CONST_NOTHING );
\r
573 temp[0] = M[0]-other[0];
\r
574 temp[1] = M[1]-other[1];
\r
575 temp[2] = M[2]-other[2];
\r
576 temp[3] = M[3]-other[3];
\r
577 temp[4] = M[4]-other[4];
\r
578 temp[5] = M[5]-other[5];
\r
579 temp[6] = M[6]-other[6];
\r
580 temp[7] = M[7]-other[7];
\r
581 temp[8] = M[8]-other[8];
\r
582 temp[9] = M[9]-other[9];
\r
583 temp[10] = M[10]-other[10];
\r
584 temp[11] = M[11]-other[11];
\r
585 temp[12] = M[12]-other[12];
\r
586 temp[13] = M[13]-other[13];
\r
587 temp[14] = M[14]-other[14];
\r
588 temp[15] = M[15]-other[15];
\r
593 //! Subtract another matrix.
\r
595 inline CMatrix4<T>& CMatrix4<T>::operator-=(const CMatrix4<T>& other)
\r
617 //! Multiply by scalar.
\r
619 inline CMatrix4<T> CMatrix4<T>::operator*(const T& scalar) const
\r
621 CMatrix4<T> temp ( EM4CONST_NOTHING );
\r
623 temp[0] = M[0]*scalar;
\r
624 temp[1] = M[1]*scalar;
\r
625 temp[2] = M[2]*scalar;
\r
626 temp[3] = M[3]*scalar;
\r
627 temp[4] = M[4]*scalar;
\r
628 temp[5] = M[5]*scalar;
\r
629 temp[6] = M[6]*scalar;
\r
630 temp[7] = M[7]*scalar;
\r
631 temp[8] = M[8]*scalar;
\r
632 temp[9] = M[9]*scalar;
\r
633 temp[10] = M[10]*scalar;
\r
634 temp[11] = M[11]*scalar;
\r
635 temp[12] = M[12]*scalar;
\r
636 temp[13] = M[13]*scalar;
\r
637 temp[14] = M[14]*scalar;
\r
638 temp[15] = M[15]*scalar;
\r
643 //! Multiply by scalar.
\r
645 inline CMatrix4<T>& CMatrix4<T>::operator*=(const T& scalar)
\r
667 //! Multiply by another matrix.
\r
669 inline CMatrix4<T>& CMatrix4<T>::operator*=(const CMatrix4<T>& other)
\r
671 #if defined ( USE_MATRIX_TEST )
\r
672 // do checks on your own in order to avoid copy creation
\r
673 if ( !other.isIdentity() )
\r
675 if ( this->isIdentity() )
\r
677 return (*this = other);
\r
681 CMatrix4<T> temp ( *this );
\r
682 return setbyproduct_nocheck( temp, other );
\r
687 CMatrix4<T> temp ( *this );
\r
688 return setbyproduct_nocheck( temp, other );
\r
692 //! multiply by another matrix
\r
693 // set this matrix to the product of two other matrices
\r
694 // goal is to reduce stack use and copy
\r
696 inline CMatrix4<T>& CMatrix4<T>::setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b )
\r
698 const T *m1 = other_a.M;
\r
699 const T *m2 = other_b.M;
\r
701 M[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
\r
702 M[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
\r
703 M[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
\r
704 M[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
\r
706 M[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
\r
707 M[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
\r
708 M[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
\r
709 M[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
\r
711 M[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
\r
712 M[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
\r
713 M[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
\r
714 M[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
\r
716 M[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
\r
717 M[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
\r
718 M[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
\r
719 M[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
\r
720 #if defined ( USE_MATRIX_TEST )
\r
721 definitelyIdentityMatrix=false;
\r
727 //! multiply by another matrix
\r
728 // set this matrix to the product of two other matrices
\r
729 // goal is to reduce stack use and copy
\r
731 inline CMatrix4<T>& CMatrix4<T>::setbyproduct(const CMatrix4<T>& other_a, const CMatrix4<T>& other_b )
\r
733 #if defined ( USE_MATRIX_TEST )
\r
734 if ( other_a.isIdentity () )
\r
735 return (*this = other_b);
\r
737 if ( other_b.isIdentity () )
\r
738 return (*this = other_a);
\r
740 return setbyproduct_nocheck(other_a,other_b);
\r
742 return setbyproduct_nocheck(other_a,other_b);
\r
746 //! multiply by another matrix
\r
748 inline CMatrix4<T> CMatrix4<T>::operator*(const CMatrix4<T>& m2) const
\r
750 #if defined ( USE_MATRIX_TEST )
\r
751 // Testing purpose..
\r
752 if ( this->isIdentity() )
\r
754 if ( m2.isIdentity() )
\r
758 CMatrix4<T> m3 ( EM4CONST_NOTHING );
\r
762 m3[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
\r
763 m3[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
\r
764 m3[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
\r
765 m3[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
\r
767 m3[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
\r
768 m3[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
\r
769 m3[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
\r
770 m3[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
\r
772 m3[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
\r
773 m3[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
\r
774 m3[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
\r
775 m3[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
\r
777 m3[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
\r
778 m3[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
\r
779 m3[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
\r
780 m3[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
\r
787 inline vector3d<T> CMatrix4<T>::getTranslation() const
\r
789 return vector3d<T>(M[12], M[13], M[14]);
\r
794 inline CMatrix4<T>& CMatrix4<T>::setTranslation( const vector3d<T>& translation )
\r
796 M[12] = translation.X;
\r
797 M[13] = translation.Y;
\r
798 M[14] = translation.Z;
\r
799 #if defined ( USE_MATRIX_TEST )
\r
800 definitelyIdentityMatrix=false;
\r
806 inline CMatrix4<T>& CMatrix4<T>::setInverseTranslation( const vector3d<T>& translation )
\r
808 M[12] = -translation.X;
\r
809 M[13] = -translation.Y;
\r
810 M[14] = -translation.Z;
\r
811 #if defined ( USE_MATRIX_TEST )
\r
812 definitelyIdentityMatrix=false;
\r
818 inline CMatrix4<T>& CMatrix4<T>::setScale( const vector3d<T>& scale )
\r
823 #if defined ( USE_MATRIX_TEST )
\r
824 definitelyIdentityMatrix=false;
\r
829 //! Returns the absolute values of the scales of the matrix.
\r
831 Note that this returns the absolute (positive) values unless only scale is set.
\r
832 Unfortunately it does not appear to be possible to extract any original negative
\r
833 values. The best that we could do would be to arbitrarily make one scale
\r
834 negative if one or three of them were negative.
\r
835 FIXME - return the original values.
\r
838 inline vector3d<T> CMatrix4<T>::getScale() const
\r
840 // See http://www.robertblum.com/articles/2005/02/14/decomposing-matrices
\r
842 // Deal with the 0 rotation case first
\r
843 // Prior to Irrlicht 1.6, we always returned this value.
\r
844 if(core::iszero(M[1]) && core::iszero(M[2]) &&
\r
845 core::iszero(M[4]) && core::iszero(M[6]) &&
\r
846 core::iszero(M[8]) && core::iszero(M[9]))
\r
847 return vector3d<T>(M[0], M[5], M[10]);
\r
849 // We have to do the full calculation.
\r
850 return vector3d<T>(sqrtf(M[0] * M[0] + M[1] * M[1] + M[2] * M[2]),
\r
851 sqrtf(M[4] * M[4] + M[5] * M[5] + M[6] * M[6]),
\r
852 sqrtf(M[8] * M[8] + M[9] * M[9] + M[10] * M[10]));
\r
856 inline CMatrix4<T>& CMatrix4<T>::setRotationDegrees( const vector3d<T>& rotation )
\r
858 return setRotationRadians( rotation * core::DEGTORAD );
\r
862 inline CMatrix4<T>& CMatrix4<T>::setInverseRotationDegrees( const vector3d<T>& rotation )
\r
864 return setInverseRotationRadians( rotation * core::DEGTORAD );
\r
868 inline CMatrix4<T>& CMatrix4<T>::setRotationRadians( const vector3d<T>& rotation )
\r
870 const f64 cr = cos( rotation.X );
\r
871 const f64 sr = sin( rotation.X );
\r
872 const f64 cp = cos( rotation.Y );
\r
873 const f64 sp = sin( rotation.Y );
\r
874 const f64 cy = cos( rotation.Z );
\r
875 const f64 sy = sin( rotation.Z );
\r
877 M[0] = (T)( cp*cy );
\r
878 M[1] = (T)( cp*sy );
\r
881 const f64 srsp = sr*sp;
\r
882 const f64 crsp = cr*sp;
\r
884 M[4] = (T)( srsp*cy-cr*sy );
\r
885 M[5] = (T)( srsp*sy+cr*cy );
\r
886 M[6] = (T)( sr*cp );
\r
888 M[8] = (T)( crsp*cy+sr*sy );
\r
889 M[9] = (T)( crsp*sy-sr*cy );
\r
890 M[10] = (T)( cr*cp );
\r
891 #if defined ( USE_MATRIX_TEST )
\r
892 definitelyIdentityMatrix=false;
\r
898 //! Returns a rotation that is equivalent to that set by setRotationDegrees().
\r
899 /** This code was sent in by Chev. Note that it does not necessarily return
\r
900 the *same* Euler angles as those set by setRotationDegrees(), but the rotation will
\r
901 be equivalent, i.e. will have the same result when used to rotate a vector or node.
\r
902 This code was originally written by by Chev.
\r
905 inline core::vector3d<T> CMatrix4<T>::getRotationDegrees(const vector3d<T>& scale_) const
\r
907 const CMatrix4<T> &mat = *this;
\r
908 core::vector3d<T> scale(scale_);
\r
909 // we need to check for negative scale on to axes, which would bring up wrong results
\r
910 if (scale.Y<0 && scale.Z<0)
\r
915 else if (scale.X<0 && scale.Z<0)
\r
920 else if (scale.X<0 && scale.Y<0)
\r
925 const core::vector3d<f64> invScale(core::reciprocal(scale.X),core::reciprocal(scale.Y),core::reciprocal(scale.Z));
\r
927 f64 Y = -asin(core::clamp(mat[2]*invScale.X, -1.0, 1.0));
\r
928 const f64 C = cos(Y);
\r
931 f64 rotx, roty, X, Z;
\r
933 if (!core::iszero(C))
\r
935 const f64 invC = core::reciprocal(C);
\r
936 rotx = mat[10] * invC * invScale.Z;
\r
937 roty = mat[6] * invC * invScale.Y;
\r
938 X = atan2( roty, rotx ) * RADTODEG64;
\r
939 rotx = mat[0] * invC * invScale.X;
\r
940 roty = mat[1] * invC * invScale.X;
\r
941 Z = atan2( roty, rotx ) * RADTODEG64;
\r
946 rotx = mat[5] * invScale.Y;
\r
947 roty = -mat[4] * invScale.Y;
\r
948 Z = atan2( roty, rotx ) * RADTODEG64;
\r
951 // fix values that get below zero
\r
952 if (X < 0.0) X += 360.0;
\r
953 if (Y < 0.0) Y += 360.0;
\r
954 if (Z < 0.0) Z += 360.0;
\r
956 return vector3d<T>((T)X,(T)Y,(T)Z);
\r
959 //! Returns a rotation that is equivalent to that set by setRotationDegrees().
\r
960 /** This code was sent in by Chev. Note that it does not necessarily return
\r
961 the *same* Euler angles as those set by setRotationDegrees(), but the rotation will
\r
962 be equivalent, i.e. will have the same result when used to rotate a vector or node.
\r
963 This code was originally written by by Chev. */
\r
965 inline core::vector3d<T> CMatrix4<T>::getRotationDegrees() const
\r
967 return getRotationDegrees(getScale());
\r
971 //! Sets matrix to rotation matrix of inverse angles given as parameters
\r
973 inline CMatrix4<T>& CMatrix4<T>::setInverseRotationRadians( const vector3d<T>& rotation )
\r
975 f64 cr = cos( rotation.X );
\r
976 f64 sr = sin( rotation.X );
\r
977 f64 cp = cos( rotation.Y );
\r
978 f64 sp = sin( rotation.Y );
\r
979 f64 cy = cos( rotation.Z );
\r
980 f64 sy = sin( rotation.Z );
\r
982 M[0] = (T)( cp*cy );
\r
983 M[4] = (T)( cp*sy );
\r
989 M[1] = (T)( srsp*cy-cr*sy );
\r
990 M[5] = (T)( srsp*sy+cr*cy );
\r
991 M[9] = (T)( sr*cp );
\r
993 M[2] = (T)( crsp*cy+sr*sy );
\r
994 M[6] = (T)( crsp*sy-sr*cy );
\r
995 M[10] = (T)( cr*cp );
\r
996 #if defined ( USE_MATRIX_TEST )
\r
997 definitelyIdentityMatrix=false;
\r
1002 //! Sets matrix to rotation matrix defined by axis and angle, assuming LH rotation
\r
1003 template <class T>
\r
1004 inline CMatrix4<T>& CMatrix4<T>::setRotationAxisRadians( const T& angle, const vector3d<T>& axis )
\r
1006 const f64 c = cos(angle);
\r
1007 const f64 s = sin(angle);
\r
1008 const f64 t = 1.0 - c;
\r
1010 const f64 tx = t * axis.X;
\r
1011 const f64 ty = t * axis.Y;
\r
1012 const f64 tz = t * axis.Z;
\r
1014 const f64 sx = s * axis.X;
\r
1015 const f64 sy = s * axis.Y;
\r
1016 const f64 sz = s * axis.Z;
\r
1018 M[0] = (T)(tx * axis.X + c);
\r
1019 M[1] = (T)(tx * axis.Y + sz);
\r
1020 M[2] = (T)(tx * axis.Z - sy);
\r
1022 M[4] = (T)(ty * axis.X - sz);
\r
1023 M[5] = (T)(ty * axis.Y + c);
\r
1024 M[6] = (T)(ty * axis.Z + sx);
\r
1026 M[8] = (T)(tz * axis.X + sy);
\r
1027 M[9] = (T)(tz * axis.Y - sx);
\r
1028 M[10] = (T)(tz * axis.Z + c);
\r
1030 #if defined ( USE_MATRIX_TEST )
\r
1031 definitelyIdentityMatrix=false;
\r
1039 template <class T>
\r
1040 inline CMatrix4<T>& CMatrix4<T>::makeIdentity()
\r
1042 memset(M, 0, 16*sizeof(T));
\r
1043 M[0] = M[5] = M[10] = M[15] = (T)1;
\r
1044 #if defined ( USE_MATRIX_TEST )
\r
1045 definitelyIdentityMatrix=true;
\r
1052 check identity with epsilon
\r
1053 solve floating range problems..
\r
1055 template <class T>
\r
1056 inline bool CMatrix4<T>::isIdentity() const
\r
1058 #if defined ( USE_MATRIX_TEST )
\r
1059 if (definitelyIdentityMatrix)
\r
1062 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
1065 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
1068 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
1071 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
1074 if (!core::equals( M[ 0], (T)1 ) ||
\r
1075 !core::equals( M[ 5], (T)1 ) ||
\r
1076 !core::equals( M[10], (T)1 ) ||
\r
1077 !core::equals( M[15], (T)1 ))
\r
1080 for (s32 i=0; i<4; ++i)
\r
1081 for (s32 j=0; j<4; ++j)
\r
1082 if ((j != i) && (!iszero((*this)(i,j))))
\r
1085 #if defined ( USE_MATRIX_TEST )
\r
1086 definitelyIdentityMatrix=true;
\r
1092 /* Check orthogonality of matrix. */
\r
1093 template <class T>
\r
1094 inline bool CMatrix4<T>::isOrthogonal() const
\r
1096 T dp=M[0] * M[4 ] + M[1] * M[5 ] + M[2 ] * M[6 ] + M[3 ] * M[7 ];
\r
1099 dp = M[0] * M[8 ] + M[1] * M[9 ] + M[2 ] * M[10] + M[3 ] * M[11];
\r
1102 dp = M[0] * M[12] + M[1] * M[13] + M[2 ] * M[14] + M[3 ] * M[15];
\r
1105 dp = M[4] * M[8 ] + M[5] * M[9 ] + M[6 ] * M[10] + M[7 ] * M[11];
\r
1108 dp = M[4] * M[12] + M[5] * M[13] + M[6 ] * M[14] + M[7 ] * M[15];
\r
1111 dp = M[8] * M[12] + M[9] * M[13] + M[10] * M[14] + M[11] * M[15];
\r
1112 return (iszero(dp));
\r
1117 doesn't solve floating range problems..
\r
1118 but takes care on +/- 0 on translation because we are changing it..
\r
1119 reducing floating point branches
\r
1120 but it needs the floats in memory..
\r
1122 template <class T>
\r
1123 inline bool CMatrix4<T>::isIdentity_integer_base() const
\r
1125 #if defined ( USE_MATRIX_TEST )
\r
1126 if (definitelyIdentityMatrix)
\r
1129 if(IR(M[0])!=F32_VALUE_1) return false;
\r
1130 if(IR(M[1])!=0) return false;
\r
1131 if(IR(M[2])!=0) return false;
\r
1132 if(IR(M[3])!=0) return false;
\r
1134 if(IR(M[4])!=0) return false;
\r
1135 if(IR(M[5])!=F32_VALUE_1) return false;
\r
1136 if(IR(M[6])!=0) return false;
\r
1137 if(IR(M[7])!=0) return false;
\r
1139 if(IR(M[8])!=0) return false;
\r
1140 if(IR(M[9])!=0) return false;
\r
1141 if(IR(M[10])!=F32_VALUE_1) return false;
\r
1142 if(IR(M[11])!=0) return false;
\r
1144 if(IR(M[12])!=0) return false;
\r
1145 if(IR(M[13])!=0) return false;
\r
1146 if(IR(M[13])!=0) return false;
\r
1147 if(IR(M[15])!=F32_VALUE_1) return false;
\r
1149 #if defined ( USE_MATRIX_TEST )
\r
1150 definitelyIdentityMatrix=true;
\r
1156 template <class T>
\r
1157 inline void CMatrix4<T>::rotateVect( vector3df& vect ) const
\r
1159 vector3d<T> tmp(static_cast<T>(vect.X), static_cast<T>(vect.Y), static_cast<T>(vect.Z));
\r
1160 vect.X = static_cast<f32>(tmp.X*M[0] + tmp.Y*M[4] + tmp.Z*M[8]);
\r
1161 vect.Y = static_cast<f32>(tmp.X*M[1] + tmp.Y*M[5] + tmp.Z*M[9]);
\r
1162 vect.Z = static_cast<f32>(tmp.X*M[2] + tmp.Y*M[6] + tmp.Z*M[10]);
\r
1165 //! An alternate transform vector method, writing into a second vector
\r
1166 template <class T>
\r
1167 inline void CMatrix4<T>::rotateVect(core::vector3df& out, const core::vector3df& in) const
\r
1169 out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
\r
1170 out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
\r
1171 out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
\r
1174 //! An alternate transform vector method, writing into an array of 3 floats
\r
1175 template <class T>
\r
1176 inline void CMatrix4<T>::rotateVect(T *out, const core::vector3df& in) const
\r
1178 out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
\r
1179 out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
\r
1180 out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
\r
1183 template <class T>
\r
1184 inline void CMatrix4<T>::inverseRotateVect( vector3df& vect ) const
\r
1186 vector3d<T> tmp(static_cast<T>(vect.X), static_cast<T>(vect.Y), static_cast<T>(vect.Z));
\r
1187 vect.X = static_cast<f32>(tmp.X*M[0] + tmp.Y*M[1] + tmp.Z*M[2]);
\r
1188 vect.Y = static_cast<f32>(tmp.X*M[4] + tmp.Y*M[5] + tmp.Z*M[6]);
\r
1189 vect.Z = static_cast<f32>(tmp.X*M[8] + tmp.Y*M[9] + tmp.Z*M[10]);
\r
1192 template <class T>
\r
1193 inline void CMatrix4<T>::transformVect( vector3df& vect) const
\r
1197 vector[0] = vect.X*M[0] + vect.Y*M[4] + vect.Z*M[8] + M[12];
\r
1198 vector[1] = vect.X*M[1] + vect.Y*M[5] + vect.Z*M[9] + M[13];
\r
1199 vector[2] = vect.X*M[2] + vect.Y*M[6] + vect.Z*M[10] + M[14];
\r
1201 vect.X = vector[0];
\r
1202 vect.Y = vector[1];
\r
1203 vect.Z = vector[2];
\r
1206 template <class T>
\r
1207 inline void CMatrix4<T>::transformVect( vector3df& out, const vector3df& in) const
\r
1209 out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
\r
1210 out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
\r
1211 out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
\r
1215 template <class T>
\r
1216 inline void CMatrix4<T>::transformVect(T *out, const core::vector3df &in) const
\r
1218 out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
\r
1219 out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
\r
1220 out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
\r
1221 out[3] = in.X*M[3] + in.Y*M[7] + in.Z*M[11] + M[15];
\r
1224 template <class T>
\r
1225 inline void CMatrix4<T>::transformVec3(T *out, const T * in) const
\r
1227 out[0] = in[0]*M[0] + in[1]*M[4] + in[2]*M[8] + M[12];
\r
1228 out[1] = in[0]*M[1] + in[1]*M[5] + in[2]*M[9] + M[13];
\r
1229 out[2] = in[0]*M[2] + in[1]*M[6] + in[2]*M[10] + M[14];
\r
1232 template <class T>
\r
1233 inline void CMatrix4<T>::transformVec4(T *out, const T * in) const
\r
1235 out[0] = in[0]*M[0] + in[1]*M[4] + in[2]*M[8] + in[3]*M[12];
\r
1236 out[1] = in[0]*M[1] + in[1]*M[5] + in[2]*M[9] + in[3]*M[13];
\r
1237 out[2] = in[0]*M[2] + in[1]*M[6] + in[2]*M[10] + in[3]*M[14];
\r
1238 out[3] = in[0]*M[3] + in[1]*M[7] + in[2]*M[11] + in[3]*M[15];
\r
1242 //! Transforms a plane by this matrix
\r
1243 template <class T>
\r
1244 inline void CMatrix4<T>::transformPlane( core::plane3d<f32> &plane) const
\r
1247 // Transform the plane member point, i.e. rotate, translate and scale it.
\r
1248 transformVect(member, plane.getMemberPoint());
\r
1250 // Transform the normal by the transposed inverse of the matrix
\r
1251 CMatrix4<T> transposedInverse(*this, EM4CONST_INVERSE_TRANSPOSED);
\r
1252 vector3df normal = plane.Normal;
\r
1253 transposedInverse.rotateVect(normal);
\r
1254 plane.setPlane(member, normal.normalize());
\r
1257 //! Transforms a plane by this matrix
\r
1258 template <class T>
\r
1259 inline void CMatrix4<T>::transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const
\r
1262 transformPlane( out );
\r
1265 //! Transforms the edge-points of a bounding box
\r
1266 //! Deprecated as it's usually not what people need (regards only 2 corners, but other corners might be outside the box after transformation)
\r
1267 //! Use transformBoxEx instead.
\r
1268 template <class T>
\r
1269 _IRR_DEPRECATED_ inline void CMatrix4<T>::transformBox(core::aabbox3d<f32>& box) const
\r
1271 #if defined ( USE_MATRIX_TEST )
\r
1276 transformVect(box.MinEdge);
\r
1277 transformVect(box.MaxEdge);
\r
1281 //! Transforms a axis aligned bounding box more accurately than transformBox()
\r
1282 template <class T>
\r
1283 inline void CMatrix4<T>::transformBoxEx(core::aabbox3d<f32>& box) const
\r
1285 #if defined ( USE_MATRIX_TEST )
\r
1290 const f32 Amin[3] = {box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z};
\r
1291 const f32 Amax[3] = {box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z};
\r
1296 Bmin[0] = Bmax[0] = M[12];
\r
1297 Bmin[1] = Bmax[1] = M[13];
\r
1298 Bmin[2] = Bmax[2] = M[14];
\r
1300 const CMatrix4<T> &m = *this;
\r
1302 for (u32 i = 0; i < 3; ++i)
\r
1304 for (u32 j = 0; j < 3; ++j)
\r
1306 const f32 a = m(j,i) * Amin[j];
\r
1307 const f32 b = m(j,i) * Amax[j];
\r
1322 box.MinEdge.X = Bmin[0];
\r
1323 box.MinEdge.Y = Bmin[1];
\r
1324 box.MinEdge.Z = Bmin[2];
\r
1326 box.MaxEdge.X = Bmax[0];
\r
1327 box.MaxEdge.Y = Bmax[1];
\r
1328 box.MaxEdge.Z = Bmax[2];
\r
1332 //! Multiplies this matrix by a 1x4 matrix
\r
1333 template <class T>
\r
1334 inline void CMatrix4<T>::multiplyWith1x4Matrix(T* matrix) const
\r
1344 mat[0] = matrix[0];
\r
1345 mat[1] = matrix[1];
\r
1346 mat[2] = matrix[2];
\r
1347 mat[3] = matrix[3];
\r
1349 matrix[0] = M[0]*mat[0] + M[4]*mat[1] + M[8]*mat[2] + M[12]*mat[3];
\r
1350 matrix[1] = M[1]*mat[0] + M[5]*mat[1] + M[9]*mat[2] + M[13]*mat[3];
\r
1351 matrix[2] = M[2]*mat[0] + M[6]*mat[1] + M[10]*mat[2] + M[14]*mat[3];
\r
1352 matrix[3] = M[3]*mat[0] + M[7]*mat[1] + M[11]*mat[2] + M[15]*mat[3];
\r
1355 template <class T>
\r
1356 inline void CMatrix4<T>::inverseTranslateVect( vector3df& vect ) const
\r
1358 vect.X = vect.X-M[12];
\r
1359 vect.Y = vect.Y-M[13];
\r
1360 vect.Z = vect.Z-M[14];
\r
1363 template <class T>
\r
1364 inline void CMatrix4<T>::translateVect( vector3df& vect ) const
\r
1366 vect.X = vect.X+M[12];
\r
1367 vect.Y = vect.Y+M[13];
\r
1368 vect.Z = vect.Z+M[14];
\r
1372 template <class T>
\r
1373 inline bool CMatrix4<T>::getInverse(CMatrix4<T>& out) const
\r
1375 /// Calculates the inverse of this Matrix
\r
1376 /// The inverse is calculated using Cramers rule.
\r
1377 /// If no inverse exists then 'false' is returned.
\r
1379 #if defined ( USE_MATRIX_TEST )
\r
1380 if ( this->isIdentity() )
\r
1386 const CMatrix4<T> &m = *this;
\r
1388 f32 d = (m[0] * m[5] - m[1] * m[4]) * (m[10] * m[15] - m[11] * m[14]) -
\r
1389 (m[0] * m[6] - m[2] * m[4]) * (m[9] * m[15] - m[11] * m[13]) +
\r
1390 (m[0] * m[7] - m[3] * m[4]) * (m[9] * m[14] - m[10] * m[13]) +
\r
1391 (m[1] * m[6] - m[2] * m[5]) * (m[8] * m[15] - m[11] * m[12]) -
\r
1392 (m[1] * m[7] - m[3] * m[5]) * (m[8] * m[14] - m[10] * m[12]) +
\r
1393 (m[2] * m[7] - m[3] * m[6]) * (m[8] * m[13] - m[9] * m[12]);
\r
1395 if( core::iszero ( d, FLT_MIN ) )
\r
1398 d = core::reciprocal ( d );
\r
1400 out[0] = d * (m[5] * (m[10] * m[15] - m[11] * m[14]) +
\r
1401 m[6] * (m[11] * m[13] - m[9] * m[15]) +
\r
1402 m[7] * (m[9] * m[14] - m[10] * m[13]));
\r
1403 out[1] = d * (m[9] * (m[2] * m[15] - m[3] * m[14]) +
\r
1404 m[10] * (m[3] * m[13] - m[1] * m[15]) +
\r
1405 m[11] * (m[1] * m[14] - m[2] * m[13]));
\r
1406 out[2] = d * (m[13] * (m[2] * m[7] - m[3] * m[6]) +
\r
1407 m[14] * (m[3] * m[5] - m[1] * m[7]) +
\r
1408 m[15] * (m[1] * m[6] - m[2] * m[5]));
\r
1409 out[3] = d * (m[1] * (m[7] * m[10] - m[6] * m[11]) +
\r
1410 m[2] * (m[5] * m[11] - m[7] * m[9]) +
\r
1411 m[3] * (m[6] * m[9] - m[5] * m[10]));
\r
1412 out[4] = d * (m[6] * (m[8] * m[15] - m[11] * m[12]) +
\r
1413 m[7] * (m[10] * m[12] - m[8] * m[14]) +
\r
1414 m[4] * (m[11] * m[14] - m[10] * m[15]));
\r
1415 out[5] = d * (m[10] * (m[0] * m[15] - m[3] * m[12]) +
\r
1416 m[11] * (m[2] * m[12] - m[0] * m[14]) +
\r
1417 m[8] * (m[3] * m[14] - m[2] * m[15]));
\r
1418 out[6] = d * (m[14] * (m[0] * m[7] - m[3] * m[4]) +
\r
1419 m[15] * (m[2] * m[4] - m[0] * m[6]) +
\r
1420 m[12] * (m[3] * m[6] - m[2] * m[7]));
\r
1421 out[7] = d * (m[2] * (m[7] * m[8] - m[4] * m[11]) +
\r
1422 m[3] * (m[4] * m[10] - m[6] * m[8]) +
\r
1423 m[0] * (m[6] * m[11] - m[7] * m[10]));
\r
1424 out[8] = d * (m[7] * (m[8] * m[13] - m[9] * m[12]) +
\r
1425 m[4] * (m[9] * m[15] - m[11] * m[13]) +
\r
1426 m[5] * (m[11] * m[12] - m[8] * m[15]));
\r
1427 out[9] = d * (m[11] * (m[0] * m[13] - m[1] * m[12]) +
\r
1428 m[8] * (m[1] * m[15] - m[3] * m[13]) +
\r
1429 m[9] * (m[3] * m[12] - m[0] * m[15]));
\r
1430 out[10] = d * (m[15] * (m[0] * m[5] - m[1] * m[4]) +
\r
1431 m[12] * (m[1] * m[7] - m[3] * m[5]) +
\r
1432 m[13] * (m[3] * m[4] - m[0] * m[7]));
\r
1433 out[11] = d * (m[3] * (m[5] * m[8] - m[4] * m[9]) +
\r
1434 m[0] * (m[7] * m[9] - m[5] * m[11]) +
\r
1435 m[1] * (m[4] * m[11] - m[7] * m[8]));
\r
1436 out[12] = d * (m[4] * (m[10] * m[13] - m[9] * m[14]) +
\r
1437 m[5] * (m[8] * m[14] - m[10] * m[12]) +
\r
1438 m[6] * (m[9] * m[12] - m[8] * m[13]));
\r
1439 out[13] = d * (m[8] * (m[2] * m[13] - m[1] * m[14]) +
\r
1440 m[9] * (m[0] * m[14] - m[2] * m[12]) +
\r
1441 m[10] * (m[1] * m[12] - m[0] * m[13]));
\r
1442 out[14] = d * (m[12] * (m[2] * m[5] - m[1] * m[6]) +
\r
1443 m[13] * (m[0] * m[6] - m[2] * m[4]) +
\r
1444 m[14] * (m[1] * m[4] - m[0] * m[5]));
\r
1445 out[15] = d * (m[0] * (m[5] * m[10] - m[6] * m[9]) +
\r
1446 m[1] * (m[6] * m[8] - m[4] * m[10]) +
\r
1447 m[2] * (m[4] * m[9] - m[5] * m[8]));
\r
1449 #if defined ( USE_MATRIX_TEST )
\r
1450 out.definitelyIdentityMatrix = definitelyIdentityMatrix;
\r
1456 //! Inverts a primitive matrix which only contains a translation and a rotation
\r
1457 //! \param out: where result matrix is written to.
\r
1458 template <class T>
\r
1459 inline bool CMatrix4<T>::getInversePrimitive ( CMatrix4<T>& out ) const
\r
1473 out.M[10] = M[10];
\r
1476 out.M[12] = (T)-(M[12]*M[0] + M[13]*M[1] + M[14]*M[2]);
\r
1477 out.M[13] = (T)-(M[12]*M[4] + M[13]*M[5] + M[14]*M[6]);
\r
1478 out.M[14] = (T)-(M[12]*M[8] + M[13]*M[9] + M[14]*M[10]);
\r
1481 #if defined ( USE_MATRIX_TEST )
\r
1482 out.definitelyIdentityMatrix = definitelyIdentityMatrix;
\r
1489 template <class T>
\r
1490 inline bool CMatrix4<T>::makeInverse()
\r
1492 #if defined ( USE_MATRIX_TEST )
\r
1493 if (definitelyIdentityMatrix)
\r
1496 CMatrix4<T> temp ( EM4CONST_NOTHING );
\r
1498 if (getInverse(temp))
\r
1508 template <class T>
\r
1509 inline CMatrix4<T>& CMatrix4<T>::operator=(const T& scalar)
\r
1511 for (s32 i = 0; i < 16; ++i)
\r
1514 #if defined ( USE_MATRIX_TEST )
\r
1515 definitelyIdentityMatrix=false;
\r
1521 template <class T>
\r
1522 inline bool CMatrix4<T>::operator==(const CMatrix4<T> &other) const
\r
1524 #if defined ( USE_MATRIX_TEST )
\r
1525 if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
\r
1528 for (s32 i = 0; i < 16; ++i)
\r
1529 if (M[i] != other.M[i])
\r
1536 template <class T>
\r
1537 inline bool CMatrix4<T>::operator!=(const CMatrix4<T> &other) const
\r
1539 return !(*this == other);
\r
1543 // Builds a right-handed perspective projection matrix based on a field of view
\r
1544 template <class T>
\r
1545 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovRH(
\r
1546 f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1548 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
\r
1549 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
\r
1550 const T w = static_cast<T>(h / aspectRatio);
\r
1552 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1573 if ( zClipFromZero ) // DirectX version
\r
1575 M[10] = (T)(zFar/(zNear-zFar));
\r
1576 M[14] = (T)(zNear*zFar/(zNear-zFar));
\r
1578 else // OpenGL version
\r
1580 M[10] = (T)((zFar+zNear)/(zNear-zFar));
\r
1581 M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
\r
1584 #if defined ( USE_MATRIX_TEST )
\r
1585 definitelyIdentityMatrix=false;
\r
1591 // Builds a left-handed perspective projection matrix based on a field of view
\r
1592 template <class T>
\r
1593 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovLH(
\r
1594 f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1596 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
\r
1597 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
\r
1598 const T w = static_cast<T>(h / aspectRatio);
\r
1600 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1621 if ( zClipFromZero ) // DirectX version
\r
1623 M[10] = (T)(zFar/(zFar-zNear));
\r
1624 M[14] = (T)(-zNear*zFar/(zFar-zNear));
\r
1626 else // OpenGL version
\r
1628 M[10] = (T)((zFar+zNear)/(zFar-zNear));
\r
1629 M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
\r
1632 #if defined ( USE_MATRIX_TEST )
\r
1633 definitelyIdentityMatrix=false;
\r
1639 // Builds a left-handed perspective projection matrix based on a field of view, with far plane culling at infinity
\r
1640 template <class T>
\r
1641 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovInfinityLH(
\r
1642 f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon)
\r
1644 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
\r
1645 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
\r
1646 const T w = static_cast<T>(h / aspectRatio);
\r
1660 M[10] = (T)(1.f-epsilon);
\r
1665 M[14] = (T)(zNear*(epsilon-1.f));
\r
1668 #if defined ( USE_MATRIX_TEST )
\r
1669 definitelyIdentityMatrix=false;
\r
1675 // Builds a left-handed orthogonal projection matrix.
\r
1676 template <class T>
\r
1677 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoLH(
\r
1678 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1680 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
\r
1681 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
\r
1682 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1683 M[0] = (T)(2/widthOfViewVolume);
\r
1689 M[5] = (T)(2/heightOfViewVolume);
\r
1703 if ( zClipFromZero )
\r
1705 M[10] = (T)(1/(zFar-zNear));
\r
1706 M[14] = (T)(zNear/(zNear-zFar));
\r
1710 M[10] = (T)(2/(zFar-zNear));
\r
1711 M[14] = (T)-(zFar+zNear)/(zFar-zNear);
\r
1714 #if defined ( USE_MATRIX_TEST )
\r
1715 definitelyIdentityMatrix=false;
\r
1721 // Builds a right-handed orthogonal projection matrix.
\r
1722 template <class T>
\r
1723 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoRH(
\r
1724 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1726 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
\r
1727 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
\r
1728 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1729 M[0] = (T)(2/widthOfViewVolume);
\r
1735 M[5] = (T)(2/heightOfViewVolume);
\r
1749 if ( zClipFromZero )
\r
1751 M[10] = (T)(1/(zNear-zFar));
\r
1752 M[14] = (T)(zNear/(zNear-zFar));
\r
1756 M[10] = (T)(2/(zNear-zFar));
\r
1757 M[14] = (T)-(zFar+zNear)/(zFar-zNear);
\r
1760 #if defined ( USE_MATRIX_TEST )
\r
1761 definitelyIdentityMatrix=false;
\r
1767 // Builds a right-handed perspective projection matrix.
\r
1768 template <class T>
\r
1769 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveRH(
\r
1770 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1772 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
\r
1773 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
\r
1774 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1775 M[0] = (T)(2*zNear/widthOfViewVolume);
\r
1781 M[5] = (T)(2*zNear/heightOfViewVolume);
\r
1795 if ( zClipFromZero ) // DirectX version
\r
1797 M[10] = (T)(zFar/(zNear-zFar));
\r
1798 M[14] = (T)(zNear*zFar/(zNear-zFar));
\r
1800 else // OpenGL version
\r
1802 M[10] = (T)((zFar+zNear)/(zNear-zFar));
\r
1803 M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
\r
1806 #if defined ( USE_MATRIX_TEST )
\r
1807 definitelyIdentityMatrix=false;
\r
1813 // Builds a left-handed perspective projection matrix.
\r
1814 template <class T>
\r
1815 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveLH(
\r
1816 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1818 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
\r
1819 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
\r
1820 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1821 M[0] = (T)(2*zNear/widthOfViewVolume);
\r
1827 M[5] = (T)(2*zNear/heightOfViewVolume);
\r
1838 //M[14] = (T)(zNear*zFar/(zNear-zFar));
\r
1841 if ( zClipFromZero ) // DirectX version
\r
1843 M[10] = (T)(zFar/(zFar-zNear));
\r
1844 M[14] = (T)(zNear*zFar/(zNear-zFar));
\r
1846 else // OpenGL version
\r
1848 M[10] = (T)((zFar+zNear)/(zFar-zNear));
\r
1849 M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
\r
1852 #if defined ( USE_MATRIX_TEST )
\r
1853 definitelyIdentityMatrix=false;
\r
1859 // Builds a matrix that flattens geometry into a plane.
\r
1860 template <class T>
\r
1861 inline CMatrix4<T>& CMatrix4<T>::buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point)
\r
1863 plane.Normal.normalize();
\r
1864 const f32 d = plane.Normal.dotProduct(light);
\r
1866 M[ 0] = (T)(-plane.Normal.X * light.X + d);
\r
1867 M[ 1] = (T)(-plane.Normal.X * light.Y);
\r
1868 M[ 2] = (T)(-plane.Normal.X * light.Z);
\r
1869 M[ 3] = (T)(-plane.Normal.X * point);
\r
1871 M[ 4] = (T)(-plane.Normal.Y * light.X);
\r
1872 M[ 5] = (T)(-plane.Normal.Y * light.Y + d);
\r
1873 M[ 6] = (T)(-plane.Normal.Y * light.Z);
\r
1874 M[ 7] = (T)(-plane.Normal.Y * point);
\r
1876 M[ 8] = (T)(-plane.Normal.Z * light.X);
\r
1877 M[ 9] = (T)(-plane.Normal.Z * light.Y);
\r
1878 M[10] = (T)(-plane.Normal.Z * light.Z + d);
\r
1879 M[11] = (T)(-plane.Normal.Z * point);
\r
1881 M[12] = (T)(-plane.D * light.X);
\r
1882 M[13] = (T)(-plane.D * light.Y);
\r
1883 M[14] = (T)(-plane.D * light.Z);
\r
1884 M[15] = (T)(-plane.D * point + d);
\r
1885 #if defined ( USE_MATRIX_TEST )
\r
1886 definitelyIdentityMatrix=false;
\r
1891 // Builds a left-handed look-at matrix.
\r
1892 template <class T>
\r
1893 inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixLH(
\r
1894 const vector3df& position,
\r
1895 const vector3df& target,
\r
1896 const vector3df& upVector)
\r
1898 vector3df zaxis = target - position;
\r
1899 zaxis.normalize();
\r
1901 vector3df xaxis = upVector.crossProduct(zaxis);
\r
1902 xaxis.normalize();
\r
1904 vector3df yaxis = zaxis.crossProduct(xaxis);
\r
1906 M[0] = (T)xaxis.X;
\r
1907 M[1] = (T)yaxis.X;
\r
1908 M[2] = (T)zaxis.X;
\r
1911 M[4] = (T)xaxis.Y;
\r
1912 M[5] = (T)yaxis.Y;
\r
1913 M[6] = (T)zaxis.Y;
\r
1916 M[8] = (T)xaxis.Z;
\r
1917 M[9] = (T)yaxis.Z;
\r
1918 M[10] = (T)zaxis.Z;
\r
1921 M[12] = (T)-xaxis.dotProduct(position);
\r
1922 M[13] = (T)-yaxis.dotProduct(position);
\r
1923 M[14] = (T)-zaxis.dotProduct(position);
\r
1925 #if defined ( USE_MATRIX_TEST )
\r
1926 definitelyIdentityMatrix=false;
\r
1932 // Builds a right-handed look-at matrix.
\r
1933 template <class T>
\r
1934 inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixRH(
\r
1935 const vector3df& position,
\r
1936 const vector3df& target,
\r
1937 const vector3df& upVector)
\r
1939 vector3df zaxis = position - target;
\r
1940 zaxis.normalize();
\r
1942 vector3df xaxis = upVector.crossProduct(zaxis);
\r
1943 xaxis.normalize();
\r
1945 vector3df yaxis = zaxis.crossProduct(xaxis);
\r
1947 M[0] = (T)xaxis.X;
\r
1948 M[1] = (T)yaxis.X;
\r
1949 M[2] = (T)zaxis.X;
\r
1952 M[4] = (T)xaxis.Y;
\r
1953 M[5] = (T)yaxis.Y;
\r
1954 M[6] = (T)zaxis.Y;
\r
1957 M[8] = (T)xaxis.Z;
\r
1958 M[9] = (T)yaxis.Z;
\r
1959 M[10] = (T)zaxis.Z;
\r
1962 M[12] = (T)-xaxis.dotProduct(position);
\r
1963 M[13] = (T)-yaxis.dotProduct(position);
\r
1964 M[14] = (T)-zaxis.dotProduct(position);
\r
1966 #if defined ( USE_MATRIX_TEST )
\r
1967 definitelyIdentityMatrix=false;
\r
1973 // creates a new matrix as interpolated matrix from this and the passed one.
\r
1974 template <class T>
\r
1975 inline CMatrix4<T> CMatrix4<T>::interpolate(const core::CMatrix4<T>& b, f32 time) const
\r
1977 CMatrix4<T> mat ( EM4CONST_NOTHING );
\r
1979 for (u32 i=0; i < 16; i += 4)
\r
1981 mat.M[i+0] = (T)(M[i+0] + ( b.M[i+0] - M[i+0] ) * time);
\r
1982 mat.M[i+1] = (T)(M[i+1] + ( b.M[i+1] - M[i+1] ) * time);
\r
1983 mat.M[i+2] = (T)(M[i+2] + ( b.M[i+2] - M[i+2] ) * time);
\r
1984 mat.M[i+3] = (T)(M[i+3] + ( b.M[i+3] - M[i+3] ) * time);
\r
1990 // returns transposed matrix
\r
1991 template <class T>
\r
1992 inline CMatrix4<T> CMatrix4<T>::getTransposed() const
\r
1994 CMatrix4<T> t ( EM4CONST_NOTHING );
\r
1995 getTransposed ( t );
\r
2000 // returns transposed matrix
\r
2001 template <class T>
\r
2002 inline void CMatrix4<T>::getTransposed( CMatrix4<T>& o ) const
\r
2023 #if defined ( USE_MATRIX_TEST )
\r
2024 o.definitelyIdentityMatrix=definitelyIdentityMatrix;
\r
2029 // used to scale <-1,-1><1,1> to viewport
\r
2030 template <class T>
\r
2031 inline CMatrix4<T>& CMatrix4<T>::buildNDCToDCMatrix( const core::rect<s32>& viewport, f32 zScale)
\r
2033 const f32 scaleX = (viewport.getWidth() - 0.75f ) * 0.5f;
\r
2034 const f32 scaleY = -(viewport.getHeight() - 0.75f ) * 0.5f;
\r
2036 const f32 dx = -0.5f + ( (viewport.UpperLeftCorner.X + viewport.LowerRightCorner.X ) * 0.5f );
\r
2037 const f32 dy = -0.5f + ( (viewport.UpperLeftCorner.Y + viewport.LowerRightCorner.Y ) * 0.5f );
\r
2042 return setScale(core::vector3d<T>((T)scaleX, (T)scaleY, (T)zScale));
\r
2045 //! Builds a matrix that rotates from one vector to another
\r
2046 /** \param from: vector to rotate from
\r
2047 \param to: vector to rotate to
\r
2049 http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/index.htm
\r
2051 template <class T>
\r
2052 inline CMatrix4<T>& CMatrix4<T>::buildRotateFromTo(const core::vector3df& from, const core::vector3df& to)
\r
2055 core::vector3df f(from);
\r
2056 core::vector3df t(to);
\r
2060 // axis multiplication by sin
\r
2061 core::vector3df vs(t.crossProduct(f));
\r
2063 // axis of rotation
\r
2064 core::vector3df v(vs);
\r
2068 T ca = f.dotProduct(t);
\r
2070 core::vector3df vt(v * (1 - ca));
\r
2072 M[0] = vt.X * v.X + ca;
\r
2073 M[5] = vt.Y * v.Y + ca;
\r
2074 M[10] = vt.Z * v.Z + ca;
\r
2080 M[1] = vt.X - vs.Z;
\r
2081 M[2] = vt.Z + vs.Y;
\r
2084 M[4] = vt.X + vs.Z;
\r
2085 M[6] = vt.Y - vs.X;
\r
2088 M[8] = vt.Z - vs.Y;
\r
2089 M[9] = vt.Y + vs.X;
\r
2100 //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis
\r
2101 /** \param camPos: viewer position in world coord
\r
2102 \param center: object position in world-coord, rotation pivot
\r
2103 \param translation: object final translation from center
\r
2104 \param axis: axis to rotate about
\r
2105 \param from: source vector to rotate from
\r
2107 template <class T>
\r
2108 inline void CMatrix4<T>::buildAxisAlignedBillboard(
\r
2109 const core::vector3df& camPos,
\r
2110 const core::vector3df& center,
\r
2111 const core::vector3df& translation,
\r
2112 const core::vector3df& axis,
\r
2113 const core::vector3df& from)
\r
2115 // axis of rotation
\r
2116 core::vector3df up = axis;
\r
2118 const core::vector3df forward = (camPos - center).normalize();
\r
2119 const core::vector3df right = up.crossProduct(forward).normalize();
\r
2121 // correct look vector
\r
2122 const core::vector3df look = right.crossProduct(up);
\r
2125 // axis multiplication by sin
\r
2126 const core::vector3df vs = look.crossProduct(from);
\r
2129 const f32 ca = from.dotProduct(look);
\r
2131 core::vector3df vt(up * (1.f - ca));
\r
2133 M[0] = static_cast<T>(vt.X * up.X + ca);
\r
2134 M[5] = static_cast<T>(vt.Y * up.Y + ca);
\r
2135 M[10] = static_cast<T>(vt.Z * up.Z + ca);
\r
2141 M[1] = static_cast<T>(vt.X - vs.Z);
\r
2142 M[2] = static_cast<T>(vt.Z + vs.Y);
\r
2145 M[4] = static_cast<T>(vt.X + vs.Z);
\r
2146 M[6] = static_cast<T>(vt.Y - vs.X);
\r
2149 M[8] = static_cast<T>(vt.Z - vs.Y);
\r
2150 M[9] = static_cast<T>(vt.Y + vs.X);
\r
2153 setRotationCenter(center, translation);
\r
2157 //! Builds a combined matrix which translate to a center before rotation and translate afterward
\r
2158 template <class T>
\r
2159 inline void CMatrix4<T>::setRotationCenter(const core::vector3df& center, const core::vector3df& translation)
\r
2161 M[12] = -M[0]*center.X - M[4]*center.Y - M[8]*center.Z + (center.X - translation.X );
\r
2162 M[13] = -M[1]*center.X - M[5]*center.Y - M[9]*center.Z + (center.Y - translation.Y );
\r
2163 M[14] = -M[2]*center.X - M[6]*center.Y - M[10]*center.Z + (center.Z - translation.Z );
\r
2165 #if defined ( USE_MATRIX_TEST )
\r
2166 definitelyIdentityMatrix=false;
\r
2171 Generate texture coordinates as linear functions so that:
\r
2172 u = Ux*x + Uy*y + Uz*z + Uw
\r
2173 v = Vx*x + Vy*y + Vz*z + Vw
\r
2174 The matrix M for this case is:
\r
2182 template <class T>
\r
2183 inline CMatrix4<T>& CMatrix4<T>::buildTextureTransform( f32 rotateRad,
\r
2184 const core::vector2df &rotatecenter,
\r
2185 const core::vector2df &translate,
\r
2186 const core::vector2df &scale)
\r
2188 const f32 c = cosf(rotateRad);
\r
2189 const f32 s = sinf(rotateRad);
\r
2191 M[0] = (T)(c * scale.X);
\r
2192 M[1] = (T)(s * scale.Y);
\r
2196 M[4] = (T)(-s * scale.X);
\r
2197 M[5] = (T)(c * scale.Y);
\r
2201 M[8] = (T)(c * scale.X * rotatecenter.X + -s * rotatecenter.Y + translate.X);
\r
2202 M[9] = (T)(s * scale.Y * rotatecenter.X + c * rotatecenter.Y + translate.Y);
\r
2210 #if defined ( USE_MATRIX_TEST )
\r
2211 definitelyIdentityMatrix=false;
\r
2217 // rotate about z axis, center ( 0.5, 0.5 )
\r
2218 template <class T>
\r
2219 inline CMatrix4<T>& CMatrix4<T>::setTextureRotationCenter( f32 rotateRad )
\r
2221 const f32 c = cosf(rotateRad);
\r
2222 const f32 s = sinf(rotateRad);
\r
2229 M[8] = (T)(0.5f * ( s - c) + 0.5f);
\r
2230 M[9] = (T)(-0.5f * ( s + c) + 0.5f);
\r
2232 #if defined ( USE_MATRIX_TEST )
\r
2233 definitelyIdentityMatrix = definitelyIdentityMatrix && (rotateRad==0.0f);
\r
2239 template <class T>
\r
2240 inline CMatrix4<T>& CMatrix4<T>::setTextureTranslate ( f32 x, f32 y )
\r
2245 #if defined ( USE_MATRIX_TEST )
\r
2246 definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f);
\r
2251 template <class T>
\r
2252 inline void CMatrix4<T>::getTextureTranslate(f32& x, f32& y) const
\r
2258 template <class T>
\r
2259 inline CMatrix4<T>& CMatrix4<T>::setTextureTranslateTransposed ( f32 x, f32 y )
\r
2264 #if defined ( USE_MATRIX_TEST )
\r
2265 definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f);
\r
2270 template <class T>
\r
2271 inline CMatrix4<T>& CMatrix4<T>::setTextureScale ( f32 sx, f32 sy )
\r
2275 #if defined ( USE_MATRIX_TEST )
\r
2276 definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
\r
2281 template <class T>
\r
2282 inline void CMatrix4<T>::getTextureScale ( f32& sx, f32& sy ) const
\r
2288 template <class T>
\r
2289 inline CMatrix4<T>& CMatrix4<T>::setTextureScaleCenter( f32 sx, f32 sy )
\r
2293 M[8] = (T)(0.5f - 0.5f * sx);
\r
2294 M[9] = (T)(0.5f - 0.5f * sy);
\r
2296 #if defined ( USE_MATRIX_TEST )
\r
2297 definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
\r
2303 // sets all matrix data members at once
\r
2304 template <class T>
\r
2305 inline CMatrix4<T>& CMatrix4<T>::setM(const T* data)
\r
2307 memcpy(M,data, 16*sizeof(T));
\r
2309 #if defined ( USE_MATRIX_TEST )
\r
2310 definitelyIdentityMatrix=false;
\r
2316 // sets if the matrix is definitely identity matrix
\r
2317 template <class T>
\r
2318 inline void CMatrix4<T>::setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix)
\r
2320 #if defined ( USE_MATRIX_TEST )
\r
2321 definitelyIdentityMatrix = isDefinitelyIdentityMatrix;
\r
2323 (void)isDefinitelyIdentityMatrix; // prevent compiler warning
\r
2328 // gets if the matrix is definitely identity matrix
\r
2329 template <class T>
\r
2330 inline bool CMatrix4<T>::getDefinitelyIdentityMatrix() const
\r
2332 #if defined ( USE_MATRIX_TEST )
\r
2333 return definitelyIdentityMatrix;
\r
2340 //! Compare two matrices using the equal method
\r
2341 template <class T>
\r
2342 inline bool CMatrix4<T>::equals(const core::CMatrix4<T>& other, const T tolerance) const
\r
2344 #if defined ( USE_MATRIX_TEST )
\r
2345 if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
\r
2348 for (s32 i = 0; i < 16; ++i)
\r
2349 if (!core::equals(M[i],other.M[i], tolerance))
\r
2356 // Multiply by scalar.
\r
2357 template <class T>
\r
2358 inline CMatrix4<T> operator*(const T scalar, const CMatrix4<T>& mat)
\r
2360 return mat*scalar;
\r
2364 //! Typedef for f32 matrix
\r
2365 typedef CMatrix4<f32> matrix4;
\r
2367 //! global const identity matrix
\r
2368 IRRLICHT_API extern const matrix4 IdentityMatrix;
\r
2370 } // end namespace core
\r
2371 } // end namespace irr
\r