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 an 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 /** Like calling: (*this) = (*this) * other
\r
156 CMatrix4<T>& operator*=(const CMatrix4<T>& other);
\r
158 //! Multiply by scalar.
\r
159 CMatrix4<T> operator*(const T& scalar) const;
\r
161 //! Multiply by scalar.
\r
162 CMatrix4<T>& operator*=(const T& scalar);
\r
164 //! Set matrix to identity.
\r
165 inline CMatrix4<T>& makeIdentity();
\r
167 //! Returns true if the matrix is the identity matrix
\r
168 inline bool isIdentity() const;
\r
170 //! Returns true if the matrix is orthogonal
\r
171 inline bool isOrthogonal() const;
\r
173 //! Returns true if the matrix is the identity matrix
\r
174 bool isIdentity_integer_base () const;
\r
176 //! Set the translation of the current matrix. Will erase any previous values.
\r
177 CMatrix4<T>& setTranslation( const vector3d<T>& translation );
\r
179 //! Gets the current translation
\r
180 vector3d<T> getTranslation() const;
\r
182 //! Set the inverse translation of the current matrix. Will erase any previous values.
\r
183 CMatrix4<T>& setInverseTranslation( const vector3d<T>& translation );
\r
185 //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
\r
186 inline CMatrix4<T>& setRotationRadians( const vector3d<T>& rotation );
\r
188 //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified.
\r
189 CMatrix4<T>& setRotationDegrees( const vector3d<T>& rotation );
\r
191 //! Get the rotation, as set by setRotation() when you already know the scale used to create the matrix
\r
192 /** NOTE: The scale needs to be the correct one used to create this matrix.
\r
193 You can _not_ use the result of getScale(), but have to save your scale
\r
194 variable in another place (like ISceneNode does).
\r
195 NOTE: No scale value can be 0 or the result is undefined.
\r
196 NOTE: It does not necessarily return the *same* Euler angles as those set by setRotationDegrees(),
\r
197 but the rotation will be equivalent, i.e. will have the same result when used to rotate a vector or node.
\r
198 NOTE: It will (usually) give wrong results when further transformations have been added in the matrix (like shear).
\r
199 WARNING: There have been troubles with this function over the years and we may still have missed some corner cases.
\r
200 It's generally safer to keep the rotation and scale you used to create the matrix around and work with those.
\r
202 core::vector3d<T> getRotationDegrees(const vector3d<T>& scale) const;
\r
204 //! Returns the rotation, as set by setRotation().
\r
205 /** NOTE: You will have the same end-rotation as used in setRotation, but it might not use the same axis values.
\r
206 NOTE: This only works correct if no other matrix operations have been done on the inner 3x3 matrix besides
\r
207 setting rotation (so no scale/shear). Thought it (probably) works as long as scale doesn't flip handedness.
\r
208 NOTE: It does not necessarily return the *same* Euler angles as those set by setRotationDegrees(),
\r
209 but the rotation will be equivalent, i.e. will have the same result when used to rotate a vector or node.
\r
211 core::vector3d<T> getRotationDegrees() const;
\r
213 //! Make an inverted rotation matrix from Euler angles.
\r
214 /** The 4th row and column are unmodified. */
\r
215 inline CMatrix4<T>& setInverseRotationRadians( const vector3d<T>& rotation );
\r
217 //! Make an inverted rotation matrix from Euler angles.
\r
218 /** The 4th row and column are unmodified. */
\r
219 inline CMatrix4<T>& setInverseRotationDegrees( const vector3d<T>& rotation );
\r
221 //! Make a rotation matrix from angle and axis, assuming left handed rotation.
\r
222 /** The 4th row and column are unmodified. */
\r
223 inline CMatrix4<T>& setRotationAxisRadians(const T& angle, const vector3d<T>& axis);
\r
226 CMatrix4<T>& setScale( const vector3d<T>& scale );
\r
229 CMatrix4<T>& setScale( const T scale ) { return setScale(core::vector3d<T>(scale,scale,scale)); }
\r
232 core::vector3d<T> getScale() const;
\r
234 //! Translate a vector by the inverse of the translation part of this matrix.
\r
235 void inverseTranslateVect( vector3df& vect ) const;
\r
237 //! Rotate a vector by the inverse of the rotation part of this matrix.
\r
238 void inverseRotateVect( vector3df& vect ) const;
\r
240 //! Rotate a vector by the rotation part of this matrix.
\r
241 void rotateVect( vector3df& vect ) const;
\r
243 //! An alternate transform vector method, writing into a second vector
\r
244 void rotateVect(core::vector3df& out, const core::vector3df& in) const;
\r
246 //! An alternate transform vector method, writing into an array of 3 floats
\r
247 void rotateVect(T *out,const core::vector3df &in) const;
\r
249 //! Transforms the vector by this matrix
\r
250 /** This operation is performed as if the vector was 4d with the 4th component =1 */
\r
251 void transformVect( vector3df& vect) const;
\r
253 //! Transforms input vector by this matrix and stores result in output vector
\r
254 /** This operation is performed as if the vector was 4d with the 4th component =1 */
\r
255 void transformVect( vector3df& out, const vector3df& in ) const;
\r
257 //! An alternate transform vector method, writing into an array of 4 floats
\r
258 /** This operation is performed as if the vector was 4d with the 4th component =1.
\r
259 NOTE: out[3] will be written to (4th vector component)*/
\r
260 void transformVect(T *out,const core::vector3df &in) const;
\r
262 //! An alternate transform vector method, reading from and writing to an array of 3 floats
\r
263 /** This operation is performed as if the vector was 4d with the 4th component =1
\r
264 NOTE: out[3] will be written to (4th vector component)*/
\r
265 void transformVec3(T *out, const T * in) const;
\r
267 //! An alternate transform vector method, reading from and writing to an array of 4 floats
\r
268 void transformVec4(T *out, const T * in) const;
\r
270 //! Translate a vector by the translation part of this matrix.
\r
271 /** This operation is performed as if the vector was 4d with the 4th component =1 */
\r
272 void translateVect( vector3df& vect ) const;
\r
274 //! Transforms a plane by this matrix
\r
275 void transformPlane( core::plane3d<f32> &plane) const;
\r
277 //! Transforms a plane by this matrix
\r
278 void transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const;
\r
280 //! Transforms a axis aligned bounding box
\r
281 /** The result box of this operation may not be accurate at all. For
\r
282 correct results, use transformBoxEx() */
\r
283 void transformBox(core::aabbox3d<f32>& box) const;
\r
285 //! Transforms a axis aligned bounding box
\r
286 /** The result box of this operation should be accurate, but this operation
\r
287 is slower than transformBox(). */
\r
288 void transformBoxEx(core::aabbox3d<f32>& box) const;
\r
290 //! Multiplies this matrix by a 1x4 matrix
\r
291 void multiplyWith1x4Matrix(T* matrix) const;
\r
293 //! Calculates inverse of matrix. Slow.
\r
294 /** \return Returns false if there is no inverse matrix.*/
\r
295 bool makeInverse();
\r
298 //! Inverts a primitive matrix which only contains a translation and a rotation
\r
299 /** \param out: where result matrix is written to. */
\r
300 bool getInversePrimitive ( CMatrix4<T>& out ) const;
\r
302 //! Gets the inverse matrix of this one
\r
303 /** \param out: where result matrix is written to.
\r
304 \return Returns false if there is no inverse matrix. */
\r
305 bool getInverse(CMatrix4<T>& out) const;
\r
307 //! Builds a right-handed perspective projection matrix based on a field of view
\r
308 //\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
309 CMatrix4<T>& buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
311 //! Builds a left-handed perspective projection matrix based on a field of view
\r
312 CMatrix4<T>& buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
314 //! Builds a left-handed perspective projection matrix based on a field of view, with far plane at infinity
\r
315 CMatrix4<T>& buildProjectionMatrixPerspectiveFovInfinityLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon=0);
\r
317 //! Builds a right-handed perspective projection matrix.
\r
318 CMatrix4<T>& buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
320 //! Builds a left-handed perspective projection matrix.
\r
321 CMatrix4<T>& buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
323 //! Builds a left-handed orthogonal projection matrix.
\r
324 //\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
325 CMatrix4<T>& buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
327 //! Builds a right-handed orthogonal projection matrix.
\r
328 CMatrix4<T>& buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero=true);
\r
330 //! Builds a left-handed look-at matrix.
\r
331 CMatrix4<T>& buildCameraLookAtMatrixLH(
\r
332 const vector3df& position,
\r
333 const vector3df& target,
\r
334 const vector3df& upVector);
\r
336 //! Builds a right-handed look-at matrix.
\r
337 CMatrix4<T>& buildCameraLookAtMatrixRH(
\r
338 const vector3df& position,
\r
339 const vector3df& target,
\r
340 const vector3df& upVector);
\r
342 //! Builds a matrix that flattens geometry into a plane.
\r
343 /** \param light: light source
\r
344 \param plane: plane into which the geometry if flattened into
\r
345 \param point: value between 0 and 1, describing the light source.
\r
346 If this is 1, it is a point light, if it is 0, it is a directional light. */
\r
347 CMatrix4<T>& buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point=1.0f);
\r
349 //! Builds a matrix which transforms a normalized Device Coordinate to Device Coordinates.
\r
350 /** Used to scale <-1,-1><1,1> to viewport, for example from <-1,-1> <1,1> to the viewport <0,0><0,640> */
\r
351 CMatrix4<T>& buildNDCToDCMatrix( const core::rect<s32>& area, f32 zScale);
\r
353 //! Creates a new matrix as interpolated matrix from two other ones.
\r
354 /** \param b: other matrix to interpolate with
\r
355 \param time: Must be a value between 0 and 1. */
\r
356 CMatrix4<T> interpolate(const core::CMatrix4<T>& b, f32 time) const;
\r
358 //! Gets transposed matrix
\r
359 CMatrix4<T> getTransposed() const;
\r
361 //! Gets transposed matrix
\r
362 inline void getTransposed( CMatrix4<T>& dest ) const;
\r
364 //! Builds a matrix that rotates from one vector to another
\r
365 /** \param from: vector to rotate from
\r
366 \param to: vector to rotate to
\r
368 CMatrix4<T>& buildRotateFromTo(const core::vector3df& from, const core::vector3df& to);
\r
370 //! Builds a combined matrix which translates to a center before rotation and translates from origin afterwards
\r
371 /** \param center Position to rotate around
\r
372 \param translate Translation applied after the rotation
\r
374 void setRotationCenter(const core::vector3df& center, const core::vector3df& translate);
\r
376 //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis
\r
377 /** \param camPos: viewer position in world coo
\r
378 \param center: object position in world-coo and rotation pivot
\r
379 \param translation: object final translation from center
\r
380 \param axis: axis to rotate about
\r
381 \param from: source vector to rotate from
\r
383 void buildAxisAlignedBillboard(const core::vector3df& camPos,
\r
384 const core::vector3df& center,
\r
385 const core::vector3df& translation,
\r
386 const core::vector3df& axis,
\r
387 const core::vector3df& from);
\r
390 construct 2D Texture transformations
\r
391 rotate about center, scale, and transform.
\r
393 //! Set to a texture transformation matrix with the given parameters.
\r
394 CMatrix4<T>& buildTextureTransform( f32 rotateRad,
\r
395 const core::vector2df &rotatecenter,
\r
396 const core::vector2df &translate,
\r
397 const core::vector2df &scale);
\r
399 //! Set texture transformation rotation
\r
400 /** Rotate about z axis, recenter at (0.5,0.5).
\r
401 Doesn't clear other elements than those affected
\r
402 \param radAngle Angle in radians
\r
403 \return Altered matrix */
\r
404 CMatrix4<T>& setTextureRotationCenter( f32 radAngle );
\r
406 //! Set texture transformation translation
\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>& setTextureTranslate( f32 x, f32 y );
\r
413 //! Get texture transformation translation
\r
414 /** \param x returns offset on x axis
\r
415 \param y returns offset on y axis */
\r
416 void getTextureTranslate( f32& x, f32& y ) const;
\r
418 //! Set texture transformation translation, using a transposed representation
\r
419 /** Doesn't clear other elements than those affected.
\r
420 \param x Offset on x axis
\r
421 \param y Offset on y axis
\r
422 \return Altered matrix */
\r
423 CMatrix4<T>& setTextureTranslateTransposed( f32 x, f32 y );
\r
425 //! Set texture transformation scale
\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>& setTextureScale( f32 sx, f32 sy );
\r
432 //! Get texture transformation scale
\r
433 /** \param sx Returns x axis scale factor
\r
434 \param sy Returns y axis scale factor */
\r
435 void getTextureScale( f32& sx, f32& sy ) const;
\r
437 //! Set texture transformation scale, and recenter at (0.5,0.5)
\r
438 /** Doesn't clear other elements than those affected.
\r
439 \param sx Scale factor on x axis
\r
440 \param sy Scale factor on y axis
\r
441 \return Altered matrix. */
\r
442 CMatrix4<T>& setTextureScaleCenter( f32 sx, f32 sy );
\r
444 //! Sets all matrix data members at once
\r
445 CMatrix4<T>& setM(const T* data);
\r
447 //! Sets if the matrix is definitely identity matrix
\r
448 void setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix);
\r
450 //! Gets if the matrix is definitely identity matrix
\r
451 bool getDefinitelyIdentityMatrix() const;
\r
453 //! Compare two matrices using the equal method
\r
454 bool equals(const core::CMatrix4<T>& other, const T tolerance=(T)ROUNDING_ERROR_f64) const;
\r
457 //! Matrix data, stored in row-major order
\r
459 #if defined ( USE_MATRIX_TEST )
\r
460 //! Flag is this matrix is identity matrix
\r
461 mutable u32 definitelyIdentityMatrix;
\r
463 #if defined ( USE_MATRIX_TEST_DEBUG )
\r
470 // Default constructor
\r
472 inline CMatrix4<T>::CMatrix4( eConstructor constructor )
\r
473 #if defined ( USE_MATRIX_TEST )
\r
474 : definitelyIdentityMatrix(BIT_UNTESTED)
\r
476 #if defined ( USE_MATRIX_TEST_DEBUG )
\r
477 ,id ( MTest.ID++), calls ( 0 )
\r
480 switch ( constructor )
\r
482 case EM4CONST_NOTHING:
\r
483 case EM4CONST_COPY:
\r
485 case EM4CONST_IDENTITY:
\r
486 case EM4CONST_INVERSE:
\r
493 // Copy constructor
\r
495 inline CMatrix4<T>::CMatrix4( const CMatrix4<T>& other, eConstructor constructor)
\r
496 #if defined ( USE_MATRIX_TEST )
\r
497 : definitelyIdentityMatrix(BIT_UNTESTED)
\r
499 #if defined ( USE_MATRIX_TEST_DEBUG )
\r
500 ,id ( MTest.ID++), calls ( 0 )
\r
503 switch ( constructor )
\r
505 case EM4CONST_IDENTITY:
\r
508 case EM4CONST_NOTHING:
\r
510 case EM4CONST_COPY:
\r
513 case EM4CONST_TRANSPOSED:
\r
514 other.getTransposed(*this);
\r
516 case EM4CONST_INVERSE:
\r
517 if (!other.getInverse(*this))
\r
518 memset(M, 0, 16*sizeof(T));
\r
520 case EM4CONST_INVERSE_TRANSPOSED:
\r
521 if (!other.getInverse(*this))
\r
522 memset(M, 0, 16*sizeof(T));
\r
524 *this=getTransposed();
\r
529 //! Add another matrix.
\r
531 inline CMatrix4<T> CMatrix4<T>::operator+(const CMatrix4<T>& other) const
\r
533 CMatrix4<T> temp ( EM4CONST_NOTHING );
\r
535 temp[0] = M[0]+other[0];
\r
536 temp[1] = M[1]+other[1];
\r
537 temp[2] = M[2]+other[2];
\r
538 temp[3] = M[3]+other[3];
\r
539 temp[4] = M[4]+other[4];
\r
540 temp[5] = M[5]+other[5];
\r
541 temp[6] = M[6]+other[6];
\r
542 temp[7] = M[7]+other[7];
\r
543 temp[8] = M[8]+other[8];
\r
544 temp[9] = M[9]+other[9];
\r
545 temp[10] = M[10]+other[10];
\r
546 temp[11] = M[11]+other[11];
\r
547 temp[12] = M[12]+other[12];
\r
548 temp[13] = M[13]+other[13];
\r
549 temp[14] = M[14]+other[14];
\r
550 temp[15] = M[15]+other[15];
\r
555 //! Add another matrix.
\r
557 inline CMatrix4<T>& CMatrix4<T>::operator+=(const CMatrix4<T>& other)
\r
579 //! Subtract another matrix.
\r
581 inline CMatrix4<T> CMatrix4<T>::operator-(const CMatrix4<T>& other) const
\r
583 CMatrix4<T> temp ( EM4CONST_NOTHING );
\r
585 temp[0] = M[0]-other[0];
\r
586 temp[1] = M[1]-other[1];
\r
587 temp[2] = M[2]-other[2];
\r
588 temp[3] = M[3]-other[3];
\r
589 temp[4] = M[4]-other[4];
\r
590 temp[5] = M[5]-other[5];
\r
591 temp[6] = M[6]-other[6];
\r
592 temp[7] = M[7]-other[7];
\r
593 temp[8] = M[8]-other[8];
\r
594 temp[9] = M[9]-other[9];
\r
595 temp[10] = M[10]-other[10];
\r
596 temp[11] = M[11]-other[11];
\r
597 temp[12] = M[12]-other[12];
\r
598 temp[13] = M[13]-other[13];
\r
599 temp[14] = M[14]-other[14];
\r
600 temp[15] = M[15]-other[15];
\r
605 //! Subtract another matrix.
\r
607 inline CMatrix4<T>& CMatrix4<T>::operator-=(const CMatrix4<T>& other)
\r
629 //! Multiply by scalar.
\r
631 inline CMatrix4<T> CMatrix4<T>::operator*(const T& scalar) const
\r
633 CMatrix4<T> temp ( EM4CONST_NOTHING );
\r
635 temp[0] = M[0]*scalar;
\r
636 temp[1] = M[1]*scalar;
\r
637 temp[2] = M[2]*scalar;
\r
638 temp[3] = M[3]*scalar;
\r
639 temp[4] = M[4]*scalar;
\r
640 temp[5] = M[5]*scalar;
\r
641 temp[6] = M[6]*scalar;
\r
642 temp[7] = M[7]*scalar;
\r
643 temp[8] = M[8]*scalar;
\r
644 temp[9] = M[9]*scalar;
\r
645 temp[10] = M[10]*scalar;
\r
646 temp[11] = M[11]*scalar;
\r
647 temp[12] = M[12]*scalar;
\r
648 temp[13] = M[13]*scalar;
\r
649 temp[14] = M[14]*scalar;
\r
650 temp[15] = M[15]*scalar;
\r
655 //! Multiply by scalar.
\r
657 inline CMatrix4<T>& CMatrix4<T>::operator*=(const T& scalar)
\r
679 //! Multiply by another matrix.
\r
681 inline CMatrix4<T>& CMatrix4<T>::operator*=(const CMatrix4<T>& other)
\r
683 #if defined ( USE_MATRIX_TEST )
\r
684 // do checks on your own in order to avoid copy creation
\r
685 if ( !other.isIdentity() )
\r
687 if ( this->isIdentity() )
\r
689 return (*this = other);
\r
693 CMatrix4<T> temp ( *this );
\r
694 return setbyproduct_nocheck( temp, other );
\r
699 CMatrix4<T> temp ( *this );
\r
700 return setbyproduct_nocheck( temp, other );
\r
704 //! multiply by another matrix
\r
705 // set this matrix to the product of two other matrices
\r
706 // goal is to reduce stack use and copy
\r
708 inline CMatrix4<T>& CMatrix4<T>::setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b )
\r
710 const T *m1 = other_a.M;
\r
711 const T *m2 = other_b.M;
\r
713 M[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
\r
714 M[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
\r
715 M[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
\r
716 M[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
\r
718 M[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
\r
719 M[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
\r
720 M[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
\r
721 M[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
\r
723 M[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
\r
724 M[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
\r
725 M[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
\r
726 M[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
\r
728 M[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
\r
729 M[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
\r
730 M[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
\r
731 M[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
\r
732 #if defined ( USE_MATRIX_TEST )
\r
733 definitelyIdentityMatrix=false;
\r
739 //! multiply by another matrix
\r
740 // set this matrix to the product of two other matrices
\r
741 // goal is to reduce stack use and copy
\r
743 inline CMatrix4<T>& CMatrix4<T>::setbyproduct(const CMatrix4<T>& other_a, const CMatrix4<T>& other_b )
\r
745 #if defined ( USE_MATRIX_TEST )
\r
746 if ( other_a.isIdentity () )
\r
747 return (*this = other_b);
\r
749 if ( other_b.isIdentity () )
\r
750 return (*this = other_a);
\r
752 return setbyproduct_nocheck(other_a,other_b);
\r
754 return setbyproduct_nocheck(other_a,other_b);
\r
758 //! multiply by another matrix
\r
760 inline CMatrix4<T> CMatrix4<T>::operator*(const CMatrix4<T>& m2) const
\r
762 #if defined ( USE_MATRIX_TEST )
\r
763 // Testing purpose..
\r
764 if ( this->isIdentity() )
\r
766 if ( m2.isIdentity() )
\r
770 CMatrix4<T> m3 ( EM4CONST_NOTHING );
\r
774 m3[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3];
\r
775 m3[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3];
\r
776 m3[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3];
\r
777 m3[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3];
\r
779 m3[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7];
\r
780 m3[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7];
\r
781 m3[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7];
\r
782 m3[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7];
\r
784 m3[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11];
\r
785 m3[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11];
\r
786 m3[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11];
\r
787 m3[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11];
\r
789 m3[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15];
\r
790 m3[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15];
\r
791 m3[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
\r
792 m3[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
\r
799 inline vector3d<T> CMatrix4<T>::getTranslation() const
\r
801 return vector3d<T>(M[12], M[13], M[14]);
\r
806 inline CMatrix4<T>& CMatrix4<T>::setTranslation( 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>::setInverseTranslation( const vector3d<T>& translation )
\r
820 M[12] = -translation.X;
\r
821 M[13] = -translation.Y;
\r
822 M[14] = -translation.Z;
\r
823 #if defined ( USE_MATRIX_TEST )
\r
824 definitelyIdentityMatrix=false;
\r
830 inline CMatrix4<T>& CMatrix4<T>::setScale( const vector3d<T>& scale )
\r
835 #if defined ( USE_MATRIX_TEST )
\r
836 definitelyIdentityMatrix=false;
\r
841 //! Returns the absolute values of the scales of the matrix.
\r
843 Note: You only get back original values if the matrix only set the scale.
\r
844 Otherwise the result is a scale you can use to normalize the matrix axes,
\r
845 but it's usually no longer what you did set with setScale.
\r
848 inline vector3d<T> CMatrix4<T>::getScale() const
\r
850 // See http://www.robertblum.com/articles/2005/02/14/decomposing-matrices
\r
852 // Deal with the 0 rotation case first
\r
853 // Prior to Irrlicht 1.6, we always returned this value.
\r
854 if(core::iszero(M[1]) && core::iszero(M[2]) &&
\r
855 core::iszero(M[4]) && core::iszero(M[6]) &&
\r
856 core::iszero(M[8]) && core::iszero(M[9]))
\r
857 return vector3d<T>(M[0], M[5], M[10]);
\r
859 // We have to do the full calculation.
\r
860 return vector3d<T>(sqrtf(M[0] * M[0] + M[1] * M[1] + M[2] * M[2]),
\r
861 sqrtf(M[4] * M[4] + M[5] * M[5] + M[6] * M[6]),
\r
862 sqrtf(M[8] * M[8] + M[9] * M[9] + M[10] * M[10]));
\r
866 inline CMatrix4<T>& CMatrix4<T>::setRotationDegrees( const vector3d<T>& rotation )
\r
868 return setRotationRadians( rotation * core::DEGTORAD );
\r
872 inline CMatrix4<T>& CMatrix4<T>::setInverseRotationDegrees( const vector3d<T>& rotation )
\r
874 return setInverseRotationRadians( rotation * core::DEGTORAD );
\r
878 inline CMatrix4<T>& CMatrix4<T>::setRotationRadians( const vector3d<T>& rotation )
\r
880 const f64 cr = cos( rotation.X );
\r
881 const f64 sr = sin( rotation.X );
\r
882 const f64 cp = cos( rotation.Y );
\r
883 const f64 sp = sin( rotation.Y );
\r
884 const f64 cy = cos( rotation.Z );
\r
885 const f64 sy = sin( rotation.Z );
\r
887 M[0] = (T)( cp*cy );
\r
888 M[1] = (T)( cp*sy );
\r
891 const f64 srsp = sr*sp;
\r
892 const f64 crsp = cr*sp;
\r
894 M[4] = (T)( srsp*cy-cr*sy );
\r
895 M[5] = (T)( srsp*sy+cr*cy );
\r
896 M[6] = (T)( sr*cp );
\r
898 M[8] = (T)( crsp*cy+sr*sy );
\r
899 M[9] = (T)( crsp*sy-sr*cy );
\r
900 M[10] = (T)( cr*cp );
\r
901 #if defined ( USE_MATRIX_TEST )
\r
902 definitelyIdentityMatrix=false;
\r
908 //! Returns a rotation which (mostly) works in combination with the given scale
\r
910 This code was originally written by by Chev (assuming no scaling back then,
\r
911 we can be blamed for all problems added by regarding scale)
\r
914 inline core::vector3d<T> CMatrix4<T>::getRotationDegrees(const vector3d<T>& scale_) const
\r
916 const CMatrix4<T> &mat = *this;
\r
917 const core::vector3d<f64> scale(core::iszero(scale_.X) ? FLT_MAX : scale_.X , core::iszero(scale_.Y) ? FLT_MAX : scale_.Y, core::iszero(scale_.Z) ? FLT_MAX : scale_.Z);
\r
918 const core::vector3d<f64> invScale(core::reciprocal(scale.X),core::reciprocal(scale.Y),core::reciprocal(scale.Z));
\r
920 f64 Y = -asin(core::clamp(mat[2]*invScale.X, -1.0, 1.0));
\r
921 const f64 C = cos(Y);
\r
924 f64 rotx, roty, X, Z;
\r
926 if (!core::iszero((T)C))
\r
928 const f64 invC = core::reciprocal(C);
\r
929 rotx = mat[10] * invC * invScale.Z;
\r
930 roty = mat[6] * invC * invScale.Y;
\r
931 X = atan2( roty, rotx ) * RADTODEG64;
\r
932 rotx = mat[0] * invC * invScale.X;
\r
933 roty = mat[1] * invC * invScale.X;
\r
934 Z = atan2( roty, rotx ) * RADTODEG64;
\r
939 rotx = mat[5] * invScale.Y;
\r
940 roty = -mat[4] * invScale.Y;
\r
941 Z = atan2( roty, rotx ) * RADTODEG64;
\r
944 // fix values that get below zero
\r
945 if (X < 0.0) X += 360.0;
\r
946 if (Y < 0.0) Y += 360.0;
\r
947 if (Z < 0.0) Z += 360.0;
\r
949 return vector3d<T>((T)X,(T)Y,(T)Z);
\r
952 //! Returns a rotation that is equivalent to that set by setRotationDegrees().
\r
954 inline core::vector3d<T> CMatrix4<T>::getRotationDegrees() const
\r
956 // Note: Using getScale() here make it look like it could do matrix decomposition.
\r
957 // It can't! It works (or should work) as long as rotation doesn't flip the handedness
\r
958 // aka scale swapping 1 or 3 axes. (I think we could catch that as well by comparing
\r
959 // crossproduct of first 2 axes to direction of third axis, but TODO)
\r
960 // And maybe it should also offer the solution for the simple calculation
\r
961 // without regarding scaling as Irrlicht did before 1.7
\r
962 core::vector3d<T> scale(getScale());
\r
964 // We assume the matrix uses rotations instead of negative scaling 2 axes.
\r
965 // Otherwise it fails even for some simple cases, like rotating around
\r
966 // 2 axes by 180° which getScale thinks is a negative scaling.
\r
967 if (scale.Y<0 && scale.Z<0)
\r
972 else if (scale.X<0 && scale.Z<0)
\r
977 else if (scale.X<0 && scale.Y<0)
\r
983 return getRotationDegrees(scale);
\r
987 //! Sets matrix to rotation matrix of inverse angles given as parameters
\r
989 inline CMatrix4<T>& CMatrix4<T>::setInverseRotationRadians( const vector3d<T>& rotation )
\r
991 f64 cr = cos( rotation.X );
\r
992 f64 sr = sin( rotation.X );
\r
993 f64 cp = cos( rotation.Y );
\r
994 f64 sp = sin( rotation.Y );
\r
995 f64 cy = cos( rotation.Z );
\r
996 f64 sy = sin( rotation.Z );
\r
998 M[0] = (T)( cp*cy );
\r
999 M[4] = (T)( cp*sy );
\r
1000 M[8] = (T)( -sp );
\r
1005 M[1] = (T)( srsp*cy-cr*sy );
\r
1006 M[5] = (T)( srsp*sy+cr*cy );
\r
1007 M[9] = (T)( sr*cp );
\r
1009 M[2] = (T)( crsp*cy+sr*sy );
\r
1010 M[6] = (T)( crsp*sy-sr*cy );
\r
1011 M[10] = (T)( cr*cp );
\r
1012 #if defined ( USE_MATRIX_TEST )
\r
1013 definitelyIdentityMatrix=false;
\r
1018 //! Sets matrix to rotation matrix defined by axis and angle, assuming LH rotation
\r
1019 template <class T>
\r
1020 inline CMatrix4<T>& CMatrix4<T>::setRotationAxisRadians( const T& angle, const vector3d<T>& axis )
\r
1022 const f64 c = cos(angle);
\r
1023 const f64 s = sin(angle);
\r
1024 const f64 t = 1.0 - c;
\r
1026 const f64 tx = t * axis.X;
\r
1027 const f64 ty = t * axis.Y;
\r
1028 const f64 tz = t * axis.Z;
\r
1030 const f64 sx = s * axis.X;
\r
1031 const f64 sy = s * axis.Y;
\r
1032 const f64 sz = s * axis.Z;
\r
1034 M[0] = (T)(tx * axis.X + c);
\r
1035 M[1] = (T)(tx * axis.Y + sz);
\r
1036 M[2] = (T)(tx * axis.Z - sy);
\r
1038 M[4] = (T)(ty * axis.X - sz);
\r
1039 M[5] = (T)(ty * axis.Y + c);
\r
1040 M[6] = (T)(ty * axis.Z + sx);
\r
1042 M[8] = (T)(tz * axis.X + sy);
\r
1043 M[9] = (T)(tz * axis.Y - sx);
\r
1044 M[10] = (T)(tz * axis.Z + c);
\r
1046 #if defined ( USE_MATRIX_TEST )
\r
1047 definitelyIdentityMatrix=false;
\r
1055 template <class T>
\r
1056 inline CMatrix4<T>& CMatrix4<T>::makeIdentity()
\r
1058 memset(M, 0, 16*sizeof(T));
\r
1059 M[0] = M[5] = M[10] = M[15] = (T)1;
\r
1060 #if defined ( USE_MATRIX_TEST )
\r
1061 definitelyIdentityMatrix=true;
\r
1068 check identity with epsilon
\r
1069 solve floating range problems..
\r
1071 template <class T>
\r
1072 inline bool CMatrix4<T>::isIdentity() const
\r
1074 #if defined ( USE_MATRIX_TEST )
\r
1075 if (definitelyIdentityMatrix)
\r
1078 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
1081 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
1084 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
1087 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
1090 if (!core::equals( M[ 0], (T)1 ) ||
\r
1091 !core::equals( M[ 5], (T)1 ) ||
\r
1092 !core::equals( M[10], (T)1 ) ||
\r
1093 !core::equals( M[15], (T)1 ))
\r
1096 for (s32 i=0; i<4; ++i)
\r
1097 for (s32 j=0; j<4; ++j)
\r
1098 if ((j != i) && (!iszero((*this)(i,j))))
\r
1101 #if defined ( USE_MATRIX_TEST )
\r
1102 definitelyIdentityMatrix=true;
\r
1108 /* Check orthogonality of matrix. */
\r
1109 template <class T>
\r
1110 inline bool CMatrix4<T>::isOrthogonal() const
\r
1112 T dp=M[0] * M[4 ] + M[1] * M[5 ] + M[2 ] * M[6 ] + M[3 ] * M[7 ];
\r
1115 dp = M[0] * M[8 ] + M[1] * M[9 ] + M[2 ] * M[10] + M[3 ] * M[11];
\r
1118 dp = M[0] * M[12] + M[1] * M[13] + M[2 ] * M[14] + M[3 ] * M[15];
\r
1121 dp = M[4] * M[8 ] + M[5] * M[9 ] + M[6 ] * M[10] + M[7 ] * M[11];
\r
1124 dp = M[4] * M[12] + M[5] * M[13] + M[6 ] * M[14] + M[7 ] * M[15];
\r
1127 dp = M[8] * M[12] + M[9] * M[13] + M[10] * M[14] + M[11] * M[15];
\r
1128 return (iszero(dp));
\r
1133 doesn't solve floating range problems..
\r
1134 but takes care on +/- 0 on translation because we are changing it..
\r
1135 reducing floating point branches
\r
1136 but it needs the floats in memory..
\r
1138 template <class T>
\r
1139 inline bool CMatrix4<T>::isIdentity_integer_base() const
\r
1141 #if defined ( USE_MATRIX_TEST )
\r
1142 if (definitelyIdentityMatrix)
\r
1145 if(IR(M[0])!=F32_VALUE_1) return false;
\r
1146 if(IR(M[1])!=0) return false;
\r
1147 if(IR(M[2])!=0) return false;
\r
1148 if(IR(M[3])!=0) return false;
\r
1150 if(IR(M[4])!=0) return false;
\r
1151 if(IR(M[5])!=F32_VALUE_1) return false;
\r
1152 if(IR(M[6])!=0) return false;
\r
1153 if(IR(M[7])!=0) return false;
\r
1155 if(IR(M[8])!=0) return false;
\r
1156 if(IR(M[9])!=0) return false;
\r
1157 if(IR(M[10])!=F32_VALUE_1) return false;
\r
1158 if(IR(M[11])!=0) return false;
\r
1160 if(IR(M[12])!=0) return false;
\r
1161 if(IR(M[13])!=0) return false;
\r
1162 if(IR(M[13])!=0) return false;
\r
1163 if(IR(M[15])!=F32_VALUE_1) return false;
\r
1165 #if defined ( USE_MATRIX_TEST )
\r
1166 definitelyIdentityMatrix=true;
\r
1172 template <class T>
\r
1173 inline void CMatrix4<T>::rotateVect( vector3df& vect ) const
\r
1175 vector3d<T> tmp(static_cast<T>(vect.X), static_cast<T>(vect.Y), static_cast<T>(vect.Z));
\r
1176 vect.X = static_cast<f32>(tmp.X*M[0] + tmp.Y*M[4] + tmp.Z*M[8]);
\r
1177 vect.Y = static_cast<f32>(tmp.X*M[1] + tmp.Y*M[5] + tmp.Z*M[9]);
\r
1178 vect.Z = static_cast<f32>(tmp.X*M[2] + tmp.Y*M[6] + tmp.Z*M[10]);
\r
1181 //! An alternate transform vector method, writing into a second vector
\r
1182 template <class T>
\r
1183 inline void CMatrix4<T>::rotateVect(core::vector3df& out, const core::vector3df& in) const
\r
1185 out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
\r
1186 out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
\r
1187 out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
\r
1190 //! An alternate transform vector method, writing into an array of 3 floats
\r
1191 template <class T>
\r
1192 inline void CMatrix4<T>::rotateVect(T *out, const core::vector3df& in) const
\r
1194 out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8];
\r
1195 out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9];
\r
1196 out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10];
\r
1199 template <class T>
\r
1200 inline void CMatrix4<T>::inverseRotateVect( vector3df& vect ) const
\r
1202 vector3d<T> tmp(static_cast<T>(vect.X), static_cast<T>(vect.Y), static_cast<T>(vect.Z));
\r
1203 vect.X = static_cast<f32>(tmp.X*M[0] + tmp.Y*M[1] + tmp.Z*M[2]);
\r
1204 vect.Y = static_cast<f32>(tmp.X*M[4] + tmp.Y*M[5] + tmp.Z*M[6]);
\r
1205 vect.Z = static_cast<f32>(tmp.X*M[8] + tmp.Y*M[9] + tmp.Z*M[10]);
\r
1208 template <class T>
\r
1209 inline void CMatrix4<T>::transformVect( vector3df& vect) const
\r
1213 vector[0] = vect.X*M[0] + vect.Y*M[4] + vect.Z*M[8] + M[12];
\r
1214 vector[1] = vect.X*M[1] + vect.Y*M[5] + vect.Z*M[9] + M[13];
\r
1215 vector[2] = vect.X*M[2] + vect.Y*M[6] + vect.Z*M[10] + M[14];
\r
1217 vect.X = static_cast<f32>(vector[0]);
\r
1218 vect.Y = static_cast<f32>(vector[1]);
\r
1219 vect.Z = static_cast<f32>(vector[2]);
\r
1222 template <class T>
\r
1223 inline void CMatrix4<T>::transformVect( vector3df& out, const vector3df& in) const
\r
1225 out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
\r
1226 out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
\r
1227 out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
\r
1231 template <class T>
\r
1232 inline void CMatrix4<T>::transformVect(T *out, const core::vector3df &in) const
\r
1234 out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12];
\r
1235 out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13];
\r
1236 out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14];
\r
1237 out[3] = in.X*M[3] + in.Y*M[7] + in.Z*M[11] + M[15];
\r
1240 template <class T>
\r
1241 inline void CMatrix4<T>::transformVec3(T *out, const T * in) const
\r
1243 out[0] = in[0]*M[0] + in[1]*M[4] + in[2]*M[8] + M[12];
\r
1244 out[1] = in[0]*M[1] + in[1]*M[5] + in[2]*M[9] + M[13];
\r
1245 out[2] = in[0]*M[2] + in[1]*M[6] + in[2]*M[10] + M[14];
\r
1248 template <class T>
\r
1249 inline void CMatrix4<T>::transformVec4(T *out, const T * in) const
\r
1251 out[0] = in[0]*M[0] + in[1]*M[4] + in[2]*M[8] + in[3]*M[12];
\r
1252 out[1] = in[0]*M[1] + in[1]*M[5] + in[2]*M[9] + in[3]*M[13];
\r
1253 out[2] = in[0]*M[2] + in[1]*M[6] + in[2]*M[10] + in[3]*M[14];
\r
1254 out[3] = in[0]*M[3] + in[1]*M[7] + in[2]*M[11] + in[3]*M[15];
\r
1258 //! Transforms a plane by this matrix
\r
1259 template <class T>
\r
1260 inline void CMatrix4<T>::transformPlane( core::plane3d<f32> &plane) const
\r
1263 // Transform the plane member point, i.e. rotate, translate and scale it.
\r
1264 transformVect(member, plane.getMemberPoint());
\r
1266 // Transform the normal by the transposed inverse of the matrix
\r
1267 CMatrix4<T> transposedInverse(*this, EM4CONST_INVERSE_TRANSPOSED);
\r
1268 vector3df normal = plane.Normal;
\r
1269 transposedInverse.rotateVect(normal);
\r
1270 plane.setPlane(member, normal.normalize());
\r
1273 //! Transforms a plane by this matrix
\r
1274 template <class T>
\r
1275 inline void CMatrix4<T>::transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const
\r
1278 transformPlane( out );
\r
1281 //! Transforms the edge-points of a bounding box
\r
1282 //! Deprecated as it's usually not what people need (regards only 2 corners, but other corners might be outside the box after transformation)
\r
1283 //! Use transformBoxEx instead.
\r
1284 template <class T>
\r
1285 _IRR_DEPRECATED_ inline void CMatrix4<T>::transformBox(core::aabbox3d<f32>& box) const
\r
1287 #if defined ( USE_MATRIX_TEST )
\r
1292 transformVect(box.MinEdge);
\r
1293 transformVect(box.MaxEdge);
\r
1297 //! Transforms a axis aligned bounding box more accurately than transformBox()
\r
1298 template <class T>
\r
1299 inline void CMatrix4<T>::transformBoxEx(core::aabbox3d<f32>& box) const
\r
1301 #if defined ( USE_MATRIX_TEST )
\r
1306 const f32 Amin[3] = {box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z};
\r
1307 const f32 Amax[3] = {box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z};
\r
1312 Bmin[0] = Bmax[0] = M[12];
\r
1313 Bmin[1] = Bmax[1] = M[13];
\r
1314 Bmin[2] = Bmax[2] = M[14];
\r
1316 const CMatrix4<T> &m = *this;
\r
1318 for (u32 i = 0; i < 3; ++i)
\r
1320 for (u32 j = 0; j < 3; ++j)
\r
1322 const f32 a = m(j,i) * Amin[j];
\r
1323 const f32 b = m(j,i) * Amax[j];
\r
1338 box.MinEdge.X = Bmin[0];
\r
1339 box.MinEdge.Y = Bmin[1];
\r
1340 box.MinEdge.Z = Bmin[2];
\r
1342 box.MaxEdge.X = Bmax[0];
\r
1343 box.MaxEdge.Y = Bmax[1];
\r
1344 box.MaxEdge.Z = Bmax[2];
\r
1348 //! Multiplies this matrix by a 1x4 matrix
\r
1349 template <class T>
\r
1350 inline void CMatrix4<T>::multiplyWith1x4Matrix(T* matrix) const
\r
1360 mat[0] = matrix[0];
\r
1361 mat[1] = matrix[1];
\r
1362 mat[2] = matrix[2];
\r
1363 mat[3] = matrix[3];
\r
1365 matrix[0] = M[0]*mat[0] + M[4]*mat[1] + M[8]*mat[2] + M[12]*mat[3];
\r
1366 matrix[1] = M[1]*mat[0] + M[5]*mat[1] + M[9]*mat[2] + M[13]*mat[3];
\r
1367 matrix[2] = M[2]*mat[0] + M[6]*mat[1] + M[10]*mat[2] + M[14]*mat[3];
\r
1368 matrix[3] = M[3]*mat[0] + M[7]*mat[1] + M[11]*mat[2] + M[15]*mat[3];
\r
1371 template <class T>
\r
1372 inline void CMatrix4<T>::inverseTranslateVect( vector3df& vect ) const
\r
1374 vect.X = vect.X-M[12];
\r
1375 vect.Y = vect.Y-M[13];
\r
1376 vect.Z = vect.Z-M[14];
\r
1379 template <class T>
\r
1380 inline void CMatrix4<T>::translateVect( vector3df& vect ) const
\r
1382 vect.X = vect.X+M[12];
\r
1383 vect.Y = vect.Y+M[13];
\r
1384 vect.Z = vect.Z+M[14];
\r
1388 template <class T>
\r
1389 inline bool CMatrix4<T>::getInverse(CMatrix4<T>& out) const
\r
1391 /// Calculates the inverse of this Matrix
\r
1392 /// The inverse is calculated using Cramers rule.
\r
1393 /// If no inverse exists then 'false' is returned.
\r
1395 #if defined ( USE_MATRIX_TEST )
\r
1396 if ( this->isIdentity() )
\r
1402 const CMatrix4<T> &m = *this;
\r
1404 f32 d = (m[0] * m[5] - m[1] * m[4]) * (m[10] * m[15] - m[11] * m[14]) -
\r
1405 (m[0] * m[6] - m[2] * m[4]) * (m[9] * m[15] - m[11] * m[13]) +
\r
1406 (m[0] * m[7] - m[3] * m[4]) * (m[9] * m[14] - m[10] * m[13]) +
\r
1407 (m[1] * m[6] - m[2] * m[5]) * (m[8] * m[15] - m[11] * m[12]) -
\r
1408 (m[1] * m[7] - m[3] * m[5]) * (m[8] * m[14] - m[10] * m[12]) +
\r
1409 (m[2] * m[7] - m[3] * m[6]) * (m[8] * m[13] - m[9] * m[12]);
\r
1411 if( core::iszero ( d, FLT_MIN ) )
\r
1414 d = core::reciprocal ( d );
\r
1416 out[0] = d * (m[5] * (m[10] * m[15] - m[11] * m[14]) +
\r
1417 m[6] * (m[11] * m[13] - m[9] * m[15]) +
\r
1418 m[7] * (m[9] * m[14] - m[10] * m[13]));
\r
1419 out[1] = d * (m[9] * (m[2] * m[15] - m[3] * m[14]) +
\r
1420 m[10] * (m[3] * m[13] - m[1] * m[15]) +
\r
1421 m[11] * (m[1] * m[14] - m[2] * m[13]));
\r
1422 out[2] = d * (m[13] * (m[2] * m[7] - m[3] * m[6]) +
\r
1423 m[14] * (m[3] * m[5] - m[1] * m[7]) +
\r
1424 m[15] * (m[1] * m[6] - m[2] * m[5]));
\r
1425 out[3] = d * (m[1] * (m[7] * m[10] - m[6] * m[11]) +
\r
1426 m[2] * (m[5] * m[11] - m[7] * m[9]) +
\r
1427 m[3] * (m[6] * m[9] - m[5] * m[10]));
\r
1428 out[4] = d * (m[6] * (m[8] * m[15] - m[11] * m[12]) +
\r
1429 m[7] * (m[10] * m[12] - m[8] * m[14]) +
\r
1430 m[4] * (m[11] * m[14] - m[10] * m[15]));
\r
1431 out[5] = d * (m[10] * (m[0] * m[15] - m[3] * m[12]) +
\r
1432 m[11] * (m[2] * m[12] - m[0] * m[14]) +
\r
1433 m[8] * (m[3] * m[14] - m[2] * m[15]));
\r
1434 out[6] = d * (m[14] * (m[0] * m[7] - m[3] * m[4]) +
\r
1435 m[15] * (m[2] * m[4] - m[0] * m[6]) +
\r
1436 m[12] * (m[3] * m[6] - m[2] * m[7]));
\r
1437 out[7] = d * (m[2] * (m[7] * m[8] - m[4] * m[11]) +
\r
1438 m[3] * (m[4] * m[10] - m[6] * m[8]) +
\r
1439 m[0] * (m[6] * m[11] - m[7] * m[10]));
\r
1440 out[8] = d * (m[7] * (m[8] * m[13] - m[9] * m[12]) +
\r
1441 m[4] * (m[9] * m[15] - m[11] * m[13]) +
\r
1442 m[5] * (m[11] * m[12] - m[8] * m[15]));
\r
1443 out[9] = d * (m[11] * (m[0] * m[13] - m[1] * m[12]) +
\r
1444 m[8] * (m[1] * m[15] - m[3] * m[13]) +
\r
1445 m[9] * (m[3] * m[12] - m[0] * m[15]));
\r
1446 out[10] = d * (m[15] * (m[0] * m[5] - m[1] * m[4]) +
\r
1447 m[12] * (m[1] * m[7] - m[3] * m[5]) +
\r
1448 m[13] * (m[3] * m[4] - m[0] * m[7]));
\r
1449 out[11] = d * (m[3] * (m[5] * m[8] - m[4] * m[9]) +
\r
1450 m[0] * (m[7] * m[9] - m[5] * m[11]) +
\r
1451 m[1] * (m[4] * m[11] - m[7] * m[8]));
\r
1452 out[12] = d * (m[4] * (m[10] * m[13] - m[9] * m[14]) +
\r
1453 m[5] * (m[8] * m[14] - m[10] * m[12]) +
\r
1454 m[6] * (m[9] * m[12] - m[8] * m[13]));
\r
1455 out[13] = d * (m[8] * (m[2] * m[13] - m[1] * m[14]) +
\r
1456 m[9] * (m[0] * m[14] - m[2] * m[12]) +
\r
1457 m[10] * (m[1] * m[12] - m[0] * m[13]));
\r
1458 out[14] = d * (m[12] * (m[2] * m[5] - m[1] * m[6]) +
\r
1459 m[13] * (m[0] * m[6] - m[2] * m[4]) +
\r
1460 m[14] * (m[1] * m[4] - m[0] * m[5]));
\r
1461 out[15] = d * (m[0] * (m[5] * m[10] - m[6] * m[9]) +
\r
1462 m[1] * (m[6] * m[8] - m[4] * m[10]) +
\r
1463 m[2] * (m[4] * m[9] - m[5] * m[8]));
\r
1465 #if defined ( USE_MATRIX_TEST )
\r
1466 out.definitelyIdentityMatrix = definitelyIdentityMatrix;
\r
1472 //! Inverts a primitive matrix which only contains a translation and a rotation
\r
1473 //! \param out: where result matrix is written to.
\r
1474 template <class T>
\r
1475 inline bool CMatrix4<T>::getInversePrimitive ( CMatrix4<T>& out ) const
\r
1489 out.M[10] = M[10];
\r
1492 out.M[12] = (T)-(M[12]*M[0] + M[13]*M[1] + M[14]*M[2]);
\r
1493 out.M[13] = (T)-(M[12]*M[4] + M[13]*M[5] + M[14]*M[6]);
\r
1494 out.M[14] = (T)-(M[12]*M[8] + M[13]*M[9] + M[14]*M[10]);
\r
1497 #if defined ( USE_MATRIX_TEST )
\r
1498 out.definitelyIdentityMatrix = definitelyIdentityMatrix;
\r
1505 template <class T>
\r
1506 inline bool CMatrix4<T>::makeInverse()
\r
1508 #if defined ( USE_MATRIX_TEST )
\r
1509 if (definitelyIdentityMatrix)
\r
1512 CMatrix4<T> temp ( EM4CONST_NOTHING );
\r
1514 if (getInverse(temp))
\r
1524 template <class T>
\r
1525 inline CMatrix4<T>& CMatrix4<T>::operator=(const T& scalar)
\r
1527 for (s32 i = 0; i < 16; ++i)
\r
1530 #if defined ( USE_MATRIX_TEST )
\r
1531 definitelyIdentityMatrix=false;
\r
1537 template <class T>
\r
1538 inline bool CMatrix4<T>::operator==(const CMatrix4<T> &other) const
\r
1540 #if defined ( USE_MATRIX_TEST )
\r
1541 if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
\r
1544 for (s32 i = 0; i < 16; ++i)
\r
1545 if (M[i] != other.M[i])
\r
1552 template <class T>
\r
1553 inline bool CMatrix4<T>::operator!=(const CMatrix4<T> &other) const
\r
1555 return !(*this == other);
\r
1559 // Builds a right-handed perspective projection matrix based on a field of view
\r
1560 template <class T>
\r
1561 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovRH(
\r
1562 f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1564 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
\r
1565 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
\r
1566 const T w = static_cast<T>(h / aspectRatio);
\r
1568 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1589 if ( zClipFromZero ) // DirectX version
\r
1591 M[10] = (T)(zFar/(zNear-zFar));
\r
1592 M[14] = (T)(zNear*zFar/(zNear-zFar));
\r
1594 else // OpenGL version
\r
1596 M[10] = (T)((zFar+zNear)/(zNear-zFar));
\r
1597 M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
\r
1600 #if defined ( USE_MATRIX_TEST )
\r
1601 definitelyIdentityMatrix=false;
\r
1607 // Builds a left-handed perspective projection matrix based on a field of view
\r
1608 template <class T>
\r
1609 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovLH(
\r
1610 f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1612 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
\r
1613 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
\r
1614 const T w = static_cast<T>(h / aspectRatio);
\r
1616 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1637 if ( zClipFromZero ) // DirectX version
\r
1639 M[10] = (T)(zFar/(zFar-zNear));
\r
1640 M[14] = (T)(-zNear*zFar/(zFar-zNear));
\r
1642 else // OpenGL version
\r
1644 M[10] = (T)((zFar+zNear)/(zFar-zNear));
\r
1645 M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
\r
1648 #if defined ( USE_MATRIX_TEST )
\r
1649 definitelyIdentityMatrix=false;
\r
1655 // Builds a left-handed perspective projection matrix based on a field of view, with far plane culling at infinity
\r
1656 template <class T>
\r
1657 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovInfinityLH(
\r
1658 f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon)
\r
1660 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5));
\r
1661 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero
\r
1662 const T w = static_cast<T>(h / aspectRatio);
\r
1676 M[10] = (T)(1.f-epsilon);
\r
1681 M[14] = (T)(zNear*(epsilon-1.f));
\r
1684 #if defined ( USE_MATRIX_TEST )
\r
1685 definitelyIdentityMatrix=false;
\r
1691 // Builds a left-handed orthogonal projection matrix.
\r
1692 template <class T>
\r
1693 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoLH(
\r
1694 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1696 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
\r
1697 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
\r
1698 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1699 M[0] = (T)(2/widthOfViewVolume);
\r
1705 M[5] = (T)(2/heightOfViewVolume);
\r
1719 if ( zClipFromZero )
\r
1721 M[10] = (T)(1/(zFar-zNear));
\r
1722 M[14] = (T)(zNear/(zNear-zFar));
\r
1726 M[10] = (T)(2/(zFar-zNear));
\r
1727 M[14] = (T)-(zFar+zNear)/(zFar-zNear);
\r
1730 #if defined ( USE_MATRIX_TEST )
\r
1731 definitelyIdentityMatrix=false;
\r
1737 // Builds a right-handed orthogonal projection matrix.
\r
1738 template <class T>
\r
1739 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoRH(
\r
1740 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1742 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
\r
1743 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
\r
1744 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1745 M[0] = (T)(2/widthOfViewVolume);
\r
1751 M[5] = (T)(2/heightOfViewVolume);
\r
1765 if ( zClipFromZero )
\r
1767 M[10] = (T)(1/(zNear-zFar));
\r
1768 M[14] = (T)(zNear/(zNear-zFar));
\r
1772 M[10] = (T)(2/(zNear-zFar));
\r
1773 M[14] = (T)-(zFar+zNear)/(zFar-zNear);
\r
1776 #if defined ( USE_MATRIX_TEST )
\r
1777 definitelyIdentityMatrix=false;
\r
1783 // Builds a right-handed perspective projection matrix.
\r
1784 template <class T>
\r
1785 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveRH(
\r
1786 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1788 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
\r
1789 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
\r
1790 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1791 M[0] = (T)(2*zNear/widthOfViewVolume);
\r
1797 M[5] = (T)(2*zNear/heightOfViewVolume);
\r
1811 if ( zClipFromZero ) // DirectX version
\r
1813 M[10] = (T)(zFar/(zNear-zFar));
\r
1814 M[14] = (T)(zNear*zFar/(zNear-zFar));
\r
1816 else // OpenGL version
\r
1818 M[10] = (T)((zFar+zNear)/(zNear-zFar));
\r
1819 M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
\r
1822 #if defined ( USE_MATRIX_TEST )
\r
1823 definitelyIdentityMatrix=false;
\r
1829 // Builds a left-handed perspective projection matrix.
\r
1830 template <class T>
\r
1831 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveLH(
\r
1832 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar, bool zClipFromZero)
\r
1834 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero
\r
1835 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero
\r
1836 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero
\r
1837 M[0] = (T)(2*zNear/widthOfViewVolume);
\r
1843 M[5] = (T)(2*zNear/heightOfViewVolume);
\r
1854 //M[14] = (T)(zNear*zFar/(zNear-zFar));
\r
1857 if ( zClipFromZero ) // DirectX version
\r
1859 M[10] = (T)(zFar/(zFar-zNear));
\r
1860 M[14] = (T)(zNear*zFar/(zNear-zFar));
\r
1862 else // OpenGL version
\r
1864 M[10] = (T)((zFar+zNear)/(zFar-zNear));
\r
1865 M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar));
\r
1868 #if defined ( USE_MATRIX_TEST )
\r
1869 definitelyIdentityMatrix=false;
\r
1875 // Builds a matrix that flattens geometry into a plane.
\r
1876 template <class T>
\r
1877 inline CMatrix4<T>& CMatrix4<T>::buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point)
\r
1879 plane.Normal.normalize();
\r
1880 const f32 d = plane.Normal.dotProduct(light);
\r
1882 M[ 0] = (T)(-plane.Normal.X * light.X + d);
\r
1883 M[ 1] = (T)(-plane.Normal.X * light.Y);
\r
1884 M[ 2] = (T)(-plane.Normal.X * light.Z);
\r
1885 M[ 3] = (T)(-plane.Normal.X * point);
\r
1887 M[ 4] = (T)(-plane.Normal.Y * light.X);
\r
1888 M[ 5] = (T)(-plane.Normal.Y * light.Y + d);
\r
1889 M[ 6] = (T)(-plane.Normal.Y * light.Z);
\r
1890 M[ 7] = (T)(-plane.Normal.Y * point);
\r
1892 M[ 8] = (T)(-plane.Normal.Z * light.X);
\r
1893 M[ 9] = (T)(-plane.Normal.Z * light.Y);
\r
1894 M[10] = (T)(-plane.Normal.Z * light.Z + d);
\r
1895 M[11] = (T)(-plane.Normal.Z * point);
\r
1897 M[12] = (T)(-plane.D * light.X);
\r
1898 M[13] = (T)(-plane.D * light.Y);
\r
1899 M[14] = (T)(-plane.D * light.Z);
\r
1900 M[15] = (T)(-plane.D * point + d);
\r
1901 #if defined ( USE_MATRIX_TEST )
\r
1902 definitelyIdentityMatrix=false;
\r
1907 // Builds a left-handed look-at matrix.
\r
1908 template <class T>
\r
1909 inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixLH(
\r
1910 const vector3df& position,
\r
1911 const vector3df& target,
\r
1912 const vector3df& upVector)
\r
1914 vector3df zaxis = target - position;
\r
1915 zaxis.normalize();
\r
1917 vector3df xaxis = upVector.crossProduct(zaxis);
\r
1918 xaxis.normalize();
\r
1920 vector3df yaxis = zaxis.crossProduct(xaxis);
\r
1922 M[0] = (T)xaxis.X;
\r
1923 M[1] = (T)yaxis.X;
\r
1924 M[2] = (T)zaxis.X;
\r
1927 M[4] = (T)xaxis.Y;
\r
1928 M[5] = (T)yaxis.Y;
\r
1929 M[6] = (T)zaxis.Y;
\r
1932 M[8] = (T)xaxis.Z;
\r
1933 M[9] = (T)yaxis.Z;
\r
1934 M[10] = (T)zaxis.Z;
\r
1937 M[12] = (T)-xaxis.dotProduct(position);
\r
1938 M[13] = (T)-yaxis.dotProduct(position);
\r
1939 M[14] = (T)-zaxis.dotProduct(position);
\r
1941 #if defined ( USE_MATRIX_TEST )
\r
1942 definitelyIdentityMatrix=false;
\r
1948 // Builds a right-handed look-at matrix.
\r
1949 template <class T>
\r
1950 inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixRH(
\r
1951 const vector3df& position,
\r
1952 const vector3df& target,
\r
1953 const vector3df& upVector)
\r
1955 vector3df zaxis = position - target;
\r
1956 zaxis.normalize();
\r
1958 vector3df xaxis = upVector.crossProduct(zaxis);
\r
1959 xaxis.normalize();
\r
1961 vector3df yaxis = zaxis.crossProduct(xaxis);
\r
1963 M[0] = (T)xaxis.X;
\r
1964 M[1] = (T)yaxis.X;
\r
1965 M[2] = (T)zaxis.X;
\r
1968 M[4] = (T)xaxis.Y;
\r
1969 M[5] = (T)yaxis.Y;
\r
1970 M[6] = (T)zaxis.Y;
\r
1973 M[8] = (T)xaxis.Z;
\r
1974 M[9] = (T)yaxis.Z;
\r
1975 M[10] = (T)zaxis.Z;
\r
1978 M[12] = (T)-xaxis.dotProduct(position);
\r
1979 M[13] = (T)-yaxis.dotProduct(position);
\r
1980 M[14] = (T)-zaxis.dotProduct(position);
\r
1982 #if defined ( USE_MATRIX_TEST )
\r
1983 definitelyIdentityMatrix=false;
\r
1989 // creates a new matrix as interpolated matrix from this and the passed one.
\r
1990 template <class T>
\r
1991 inline CMatrix4<T> CMatrix4<T>::interpolate(const core::CMatrix4<T>& b, f32 time) const
\r
1993 CMatrix4<T> mat ( EM4CONST_NOTHING );
\r
1995 for (u32 i=0; i < 16; i += 4)
\r
1997 mat.M[i+0] = (T)(M[i+0] + ( b.M[i+0] - M[i+0] ) * time);
\r
1998 mat.M[i+1] = (T)(M[i+1] + ( b.M[i+1] - M[i+1] ) * time);
\r
1999 mat.M[i+2] = (T)(M[i+2] + ( b.M[i+2] - M[i+2] ) * time);
\r
2000 mat.M[i+3] = (T)(M[i+3] + ( b.M[i+3] - M[i+3] ) * time);
\r
2006 // returns transposed matrix
\r
2007 template <class T>
\r
2008 inline CMatrix4<T> CMatrix4<T>::getTransposed() const
\r
2010 CMatrix4<T> t ( EM4CONST_NOTHING );
\r
2011 getTransposed ( t );
\r
2016 // returns transposed matrix
\r
2017 template <class T>
\r
2018 inline void CMatrix4<T>::getTransposed( CMatrix4<T>& o ) const
\r
2039 #if defined ( USE_MATRIX_TEST )
\r
2040 o.definitelyIdentityMatrix=definitelyIdentityMatrix;
\r
2045 // used to scale <-1,-1><1,1> to viewport
\r
2046 template <class T>
\r
2047 inline CMatrix4<T>& CMatrix4<T>::buildNDCToDCMatrix( const core::rect<s32>& viewport, f32 zScale)
\r
2049 const f32 scaleX = (viewport.getWidth() - 0.75f ) * 0.5f;
\r
2050 const f32 scaleY = -(viewport.getHeight() - 0.75f ) * 0.5f;
\r
2052 const f32 dx = -0.5f + ( (viewport.UpperLeftCorner.X + viewport.LowerRightCorner.X ) * 0.5f );
\r
2053 const f32 dy = -0.5f + ( (viewport.UpperLeftCorner.Y + viewport.LowerRightCorner.Y ) * 0.5f );
\r
2058 return setScale(core::vector3d<T>((T)scaleX, (T)scaleY, (T)zScale));
\r
2061 //! Builds a matrix that rotates from one vector to another
\r
2062 /** \param from: vector to rotate from
\r
2063 \param to: vector to rotate to
\r
2065 http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/index.htm
\r
2067 template <class T>
\r
2068 inline CMatrix4<T>& CMatrix4<T>::buildRotateFromTo(const core::vector3df& from, const core::vector3df& to)
\r
2071 core::vector3df f(from);
\r
2072 core::vector3df t(to);
\r
2076 // axis multiplication by sin
\r
2077 core::vector3df vs(t.crossProduct(f));
\r
2079 // axis of rotation
\r
2080 core::vector3df v(vs);
\r
2084 T ca = f.dotProduct(t);
\r
2086 core::vector3df vt(v * (1 - ca));
\r
2088 M[0] = vt.X * v.X + ca;
\r
2089 M[5] = vt.Y * v.Y + ca;
\r
2090 M[10] = vt.Z * v.Z + ca;
\r
2096 M[1] = vt.X - vs.Z;
\r
2097 M[2] = vt.Z + vs.Y;
\r
2100 M[4] = vt.X + vs.Z;
\r
2101 M[6] = vt.Y - vs.X;
\r
2104 M[8] = vt.Z - vs.Y;
\r
2105 M[9] = vt.Y + vs.X;
\r
2116 //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis
\r
2117 /** \param camPos: viewer position in world coord
\r
2118 \param center: object position in world-coord, rotation pivot
\r
2119 \param translation: object final translation from center
\r
2120 \param axis: axis to rotate about
\r
2121 \param from: source vector to rotate from
\r
2123 template <class T>
\r
2124 inline void CMatrix4<T>::buildAxisAlignedBillboard(
\r
2125 const core::vector3df& camPos,
\r
2126 const core::vector3df& center,
\r
2127 const core::vector3df& translation,
\r
2128 const core::vector3df& axis,
\r
2129 const core::vector3df& from)
\r
2131 // axis of rotation
\r
2132 core::vector3df up = axis;
\r
2134 const core::vector3df forward = (camPos - center).normalize();
\r
2135 const core::vector3df right = up.crossProduct(forward).normalize();
\r
2137 // correct look vector
\r
2138 const core::vector3df look = right.crossProduct(up);
\r
2141 // axis multiplication by sin
\r
2142 const core::vector3df vs = look.crossProduct(from);
\r
2145 const f32 ca = from.dotProduct(look);
\r
2147 core::vector3df vt(up * (1.f - ca));
\r
2149 M[0] = static_cast<T>(vt.X * up.X + ca);
\r
2150 M[5] = static_cast<T>(vt.Y * up.Y + ca);
\r
2151 M[10] = static_cast<T>(vt.Z * up.Z + ca);
\r
2157 M[1] = static_cast<T>(vt.X - vs.Z);
\r
2158 M[2] = static_cast<T>(vt.Z + vs.Y);
\r
2161 M[4] = static_cast<T>(vt.X + vs.Z);
\r
2162 M[6] = static_cast<T>(vt.Y - vs.X);
\r
2165 M[8] = static_cast<T>(vt.Z - vs.Y);
\r
2166 M[9] = static_cast<T>(vt.Y + vs.X);
\r
2169 setRotationCenter(center, translation);
\r
2173 //! Builds a combined matrix which translate to a center before rotation and translate afterward
\r
2174 template <class T>
\r
2175 inline void CMatrix4<T>::setRotationCenter(const core::vector3df& center, const core::vector3df& translation)
\r
2177 M[12] = -M[0]*center.X - M[4]*center.Y - M[8]*center.Z + (center.X - translation.X );
\r
2178 M[13] = -M[1]*center.X - M[5]*center.Y - M[9]*center.Z + (center.Y - translation.Y );
\r
2179 M[14] = -M[2]*center.X - M[6]*center.Y - M[10]*center.Z + (center.Z - translation.Z );
\r
2181 #if defined ( USE_MATRIX_TEST )
\r
2182 definitelyIdentityMatrix=false;
\r
2187 Generate texture coordinates as linear functions so that:
\r
2188 u = Ux*x + Uy*y + Uz*z + Uw
\r
2189 v = Vx*x + Vy*y + Vz*z + Vw
\r
2190 The matrix M for this case is:
\r
2198 template <class T>
\r
2199 inline CMatrix4<T>& CMatrix4<T>::buildTextureTransform( f32 rotateRad,
\r
2200 const core::vector2df &rotatecenter,
\r
2201 const core::vector2df &translate,
\r
2202 const core::vector2df &scale)
\r
2204 const f32 c = cosf(rotateRad);
\r
2205 const f32 s = sinf(rotateRad);
\r
2207 M[0] = (T)(c * scale.X);
\r
2208 M[1] = (T)(s * scale.Y);
\r
2212 M[4] = (T)(-s * scale.X);
\r
2213 M[5] = (T)(c * scale.Y);
\r
2217 M[8] = (T)(c * scale.X * rotatecenter.X + -s * rotatecenter.Y + translate.X);
\r
2218 M[9] = (T)(s * scale.Y * rotatecenter.X + c * rotatecenter.Y + translate.Y);
\r
2226 #if defined ( USE_MATRIX_TEST )
\r
2227 definitelyIdentityMatrix=false;
\r
2233 // rotate about z axis, center ( 0.5, 0.5 )
\r
2234 template <class T>
\r
2235 inline CMatrix4<T>& CMatrix4<T>::setTextureRotationCenter( f32 rotateRad )
\r
2237 const f32 c = cosf(rotateRad);
\r
2238 const f32 s = sinf(rotateRad);
\r
2245 M[8] = (T)(0.5f * ( s - c) + 0.5f);
\r
2246 M[9] = (T)(-0.5f * ( s + c) + 0.5f);
\r
2248 #if defined ( USE_MATRIX_TEST )
\r
2249 definitelyIdentityMatrix = definitelyIdentityMatrix && (rotateRad==0.0f);
\r
2255 template <class T>
\r
2256 inline CMatrix4<T>& CMatrix4<T>::setTextureTranslate ( f32 x, f32 y )
\r
2261 #if defined ( USE_MATRIX_TEST )
\r
2262 definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f);
\r
2267 template <class T>
\r
2268 inline void CMatrix4<T>::getTextureTranslate(f32& x, f32& y) const
\r
2274 template <class T>
\r
2275 inline CMatrix4<T>& CMatrix4<T>::setTextureTranslateTransposed ( f32 x, f32 y )
\r
2280 #if defined ( USE_MATRIX_TEST )
\r
2281 definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f);
\r
2286 template <class T>
\r
2287 inline CMatrix4<T>& CMatrix4<T>::setTextureScale ( f32 sx, f32 sy )
\r
2291 #if defined ( USE_MATRIX_TEST )
\r
2292 definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
\r
2297 template <class T>
\r
2298 inline void CMatrix4<T>::getTextureScale ( f32& sx, f32& sy ) const
\r
2304 template <class T>
\r
2305 inline CMatrix4<T>& CMatrix4<T>::setTextureScaleCenter( f32 sx, f32 sy )
\r
2309 M[8] = (T)(0.5f - 0.5f * sx);
\r
2310 M[9] = (T)(0.5f - 0.5f * sy);
\r
2312 #if defined ( USE_MATRIX_TEST )
\r
2313 definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f);
\r
2319 // sets all matrix data members at once
\r
2320 template <class T>
\r
2321 inline CMatrix4<T>& CMatrix4<T>::setM(const T* data)
\r
2323 memcpy(M,data, 16*sizeof(T));
\r
2325 #if defined ( USE_MATRIX_TEST )
\r
2326 definitelyIdentityMatrix=false;
\r
2332 // sets if the matrix is definitely identity matrix
\r
2333 template <class T>
\r
2334 inline void CMatrix4<T>::setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix)
\r
2336 #if defined ( USE_MATRIX_TEST )
\r
2337 definitelyIdentityMatrix = isDefinitelyIdentityMatrix;
\r
2339 (void)isDefinitelyIdentityMatrix; // prevent compiler warning
\r
2344 // gets if the matrix is definitely identity matrix
\r
2345 template <class T>
\r
2346 inline bool CMatrix4<T>::getDefinitelyIdentityMatrix() const
\r
2348 #if defined ( USE_MATRIX_TEST )
\r
2349 return definitelyIdentityMatrix;
\r
2356 //! Compare two matrices using the equal method
\r
2357 template <class T>
\r
2358 inline bool CMatrix4<T>::equals(const core::CMatrix4<T>& other, const T tolerance) const
\r
2360 #if defined ( USE_MATRIX_TEST )
\r
2361 if (definitelyIdentityMatrix && other.definitelyIdentityMatrix)
\r
2364 for (s32 i = 0; i < 16; ++i)
\r
2365 if (!core::equals(M[i],other.M[i], tolerance))
\r
2372 // Multiply by scalar.
\r
2373 template <class T>
\r
2374 inline CMatrix4<T> operator*(const T scalar, const CMatrix4<T>& mat)
\r
2376 return mat*scalar;
\r
2380 //! Typedef for f32 matrix
\r
2381 typedef CMatrix4<f32> matrix4;
\r
2383 //! global const identity matrix
\r
2384 IRRLICHT_API extern const matrix4 IdentityMatrix;
\r
2386 } // end namespace core
\r
2387 } // end namespace irr
\r