1 // Copyright (C) 2002-2012 Nikolaus Gebhardt 2 // This file is part of the "Irrlicht Engine". 3 // For conditions of distribution and use, see copyright notice in irrlicht.h 4 5 #ifndef __IRR_MATRIX_H_INCLUDED__ 6 #define __IRR_MATRIX_H_INCLUDED__ 7 8 #include "irrMath.h" 9 #include "vector3d.h" 10 #include "vector2d.h" 11 #include "plane3d.h" 12 #include "aabbox3d.h" 13 #include "rect.h" 14 #include "irrString.h" 15 16 // enable this to keep track of changes to the matrix 17 // and make simpler identity check for seldomly changing matrices 18 // otherwise identity check will always compare the elements 19 //#define USE_MATRIX_TEST 20 21 // this is only for debugging purposes 22 //#define USE_MATRIX_TEST_DEBUG 23 24 #if defined( USE_MATRIX_TEST_DEBUG ) 25 26 struct MatrixTest 27 { MatrixTestMatrixTest28 MatrixTest () : ID(0), Calls(0) {} 29 char buf[256]; 30 int Calls; 31 int ID; 32 }; 33 static MatrixTest MTest; 34 35 #endif 36 37 namespace irr 38 { 39 namespace core 40 { 41 42 //! 4x4 matrix. Mostly used as transformation matrix for 3d calculations. 43 /** The matrix is a D3D style matrix, row major with translations in the 4th row. */ 44 template <class T> 45 class CMatrix4 46 { 47 public: 48 49 //! Constructor Flags 50 enum eConstructor 51 { 52 EM4CONST_NOTHING = 0, 53 EM4CONST_COPY, 54 EM4CONST_IDENTITY, 55 EM4CONST_TRANSPOSED, 56 EM4CONST_INVERSE, 57 EM4CONST_INVERSE_TRANSPOSED 58 }; 59 60 //! Default constructor 61 /** \param constructor Choose the initialization style */ 62 CMatrix4( eConstructor constructor = EM4CONST_IDENTITY ); 63 //! Copy constructor 64 /** \param other Other matrix to copy from 65 \param constructor Choose the initialization style */ 66 CMatrix4(const CMatrix4<T>& other, eConstructor constructor = EM4CONST_COPY); 67 68 //! Simple operator for directly accessing every element of the matrix. operator()69 T& operator()(const s32 row, const s32 col) 70 { 71 #if defined ( USE_MATRIX_TEST ) 72 definitelyIdentityMatrix=false; 73 #endif 74 return M[ row * 4 + col ]; 75 } 76 77 //! Simple operator for directly accessing every element of the matrix. operator()78 const T& operator()(const s32 row, const s32 col) const { return M[row * 4 + col]; } 79 80 //! Simple operator for linearly accessing every element of the matrix. 81 T& operator[](u32 index) 82 { 83 #if defined ( USE_MATRIX_TEST ) 84 definitelyIdentityMatrix=false; 85 #endif 86 return M[index]; 87 } 88 89 //! Simple operator for linearly accessing every element of the matrix. 90 const T& operator[](u32 index) const { return M[index]; } 91 92 //! Sets this matrix equal to the other matrix. 93 inline CMatrix4<T>& operator=(const CMatrix4<T> &other); 94 95 //! Sets all elements of this matrix to the value. 96 inline CMatrix4<T>& operator=(const T& scalar); 97 98 //! Returns pointer to internal array pointer()99 const T* pointer() const { return M; } pointer()100 T* pointer() 101 { 102 #if defined ( USE_MATRIX_TEST ) 103 definitelyIdentityMatrix=false; 104 #endif 105 return M; 106 } 107 108 //! Returns true if other matrix is equal to this matrix. 109 bool operator==(const CMatrix4<T> &other) const; 110 111 //! Returns true if other matrix is not equal to this matrix. 112 bool operator!=(const CMatrix4<T> &other) const; 113 114 //! Add another matrix. 115 CMatrix4<T> operator+(const CMatrix4<T>& other) const; 116 117 //! Add another matrix. 118 CMatrix4<T>& operator+=(const CMatrix4<T>& other); 119 120 //! Subtract another matrix. 121 CMatrix4<T> operator-(const CMatrix4<T>& other) const; 122 123 //! Subtract another matrix. 124 CMatrix4<T>& operator-=(const CMatrix4<T>& other); 125 126 //! set this matrix to the product of two matrices 127 /** Calculate b*a */ 128 inline CMatrix4<T>& setbyproduct(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b ); 129 130 //! Set this matrix to the product of two matrices 131 /** Calculate b*a, no optimization used, 132 use it if you know you never have a identity matrix */ 133 CMatrix4<T>& setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b ); 134 135 //! Multiply by another matrix. 136 /** Calculate other*this */ 137 CMatrix4<T> operator*(const CMatrix4<T>& other) const; 138 139 //! Multiply by another matrix. 140 /** Calculate and return other*this */ 141 CMatrix4<T>& operator*=(const CMatrix4<T>& other); 142 143 //! Multiply by scalar. 144 CMatrix4<T> operator*(const T& scalar) const; 145 146 //! Multiply by scalar. 147 CMatrix4<T>& operator*=(const T& scalar); 148 149 //! Set matrix to identity. 150 inline CMatrix4<T>& makeIdentity(); 151 152 //! Returns true if the matrix is the identity matrix 153 inline bool isIdentity() const; 154 155 //! Returns true if the matrix is orthogonal 156 inline bool isOrthogonal() const; 157 158 //! Returns true if the matrix is the identity matrix 159 bool isIdentity_integer_base () const; 160 161 //! Set the translation of the current matrix. Will erase any previous values. 162 CMatrix4<T>& setTranslation( const vector3d<T>& translation ); 163 164 //! Gets the current translation 165 vector3d<T> getTranslation() const; 166 167 //! Set the inverse translation of the current matrix. Will erase any previous values. 168 CMatrix4<T>& setInverseTranslation( const vector3d<T>& translation ); 169 170 //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified. 171 inline CMatrix4<T>& setRotationRadians( const vector3d<T>& rotation ); 172 173 //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified. 174 CMatrix4<T>& setRotationDegrees( const vector3d<T>& rotation ); 175 176 //! Returns the rotation, as set by setRotation(). 177 /** This code was orginally written by by Chev. */ 178 core::vector3d<T> getRotationDegrees() const; 179 180 //! Make an inverted rotation matrix from Euler angles. 181 /** The 4th row and column are unmodified. */ 182 inline CMatrix4<T>& setInverseRotationRadians( const vector3d<T>& rotation ); 183 184 //! Make an inverted rotation matrix from Euler angles. 185 /** The 4th row and column are unmodified. */ 186 inline CMatrix4<T>& setInverseRotationDegrees( const vector3d<T>& rotation ); 187 188 //! Make a rotation matrix from angle and axis, assuming left handed rotation. 189 /** The 4th row and column are unmodified. */ 190 inline CMatrix4<T>& setRotationAxisRadians(const T& angle, const vector3d<T>& axis); 191 192 //! Set Scale 193 CMatrix4<T>& setScale( const vector3d<T>& scale ); 194 195 //! Set Scale setScale(const T scale)196 CMatrix4<T>& setScale( const T scale ) { return setScale(core::vector3d<T>(scale,scale,scale)); } 197 198 //! Get Scale 199 core::vector3d<T> getScale() const; 200 201 //! Translate a vector by the inverse of the translation part of this matrix. 202 void inverseTranslateVect( vector3df& vect ) const; 203 204 //! Rotate a vector by the inverse of the rotation part of this matrix. 205 void inverseRotateVect( vector3df& vect ) const; 206 207 //! Rotate a vector by the rotation part of this matrix. 208 void rotateVect( vector3df& vect ) const; 209 210 //! An alternate transform vector method, writing into a second vector 211 void rotateVect(core::vector3df& out, const core::vector3df& in) const; 212 213 //! An alternate transform vector method, writing into an array of 3 floats 214 void rotateVect(T *out,const core::vector3df &in) const; 215 216 //! Transforms the vector by this matrix 217 void transformVect( vector3df& vect) const; 218 219 //! Transforms input vector by this matrix and stores result in output vector 220 void transformVect( vector3df& out, const vector3df& in ) const; 221 222 //! An alternate transform vector method, writing into an array of 4 floats 223 void transformVect(T *out,const core::vector3df &in) const; 224 225 //! An alternate transform vector method, reading from and writing to an array of 3 floats 226 void transformVec3(T *out, const T * in) const; 227 228 //! Translate a vector by the translation part of this matrix. 229 void translateVect( vector3df& vect ) const; 230 231 //! Transforms a plane by this matrix 232 void transformPlane( core::plane3d<f32> &plane) const; 233 234 //! Transforms a plane by this matrix 235 void transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const; 236 237 //! Transforms a axis aligned bounding box 238 /** The result box of this operation may not be accurate at all. For 239 correct results, use transformBoxEx() */ 240 void transformBox(core::aabbox3d<f32>& box) const; 241 242 //! Transforms a axis aligned bounding box 243 /** The result box of this operation should by accurate, but this operation 244 is slower than transformBox(). */ 245 void transformBoxEx(core::aabbox3d<f32>& box) const; 246 247 //! Multiplies this matrix by a 1x4 matrix 248 void multiplyWith1x4Matrix(T* matrix) const; 249 250 //! Calculates inverse of matrix. Slow. 251 /** \return Returns false if there is no inverse matrix.*/ 252 bool makeInverse(); 253 254 255 //! Inverts a primitive matrix which only contains a translation and a rotation 256 /** \param out: where result matrix is written to. */ 257 bool getInversePrimitive ( CMatrix4<T>& out ) const; 258 259 //! Gets the inversed matrix of this one 260 /** \param out: where result matrix is written to. 261 \return Returns false if there is no inverse matrix. */ 262 bool getInverse(CMatrix4<T>& out) const; 263 264 //! Builds a right-handed perspective projection matrix based on a field of view 265 CMatrix4<T>& buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar); 266 267 //! Builds a left-handed perspective projection matrix based on a field of view 268 CMatrix4<T>& buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar); 269 270 //! Builds a left-handed perspective projection matrix based on a field of view, with far plane at infinity 271 CMatrix4<T>& buildProjectionMatrixPerspectiveFovInfinityLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon=0); 272 273 //! Builds a right-handed perspective projection matrix. 274 CMatrix4<T>& buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar); 275 276 //! Builds a left-handed perspective projection matrix. 277 CMatrix4<T>& buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar); 278 279 //! Builds a left-handed orthogonal projection matrix. 280 CMatrix4<T>& buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar); 281 282 //! Builds a right-handed orthogonal projection matrix. 283 CMatrix4<T>& buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar); 284 285 //! Builds a left-handed look-at matrix. 286 CMatrix4<T>& buildCameraLookAtMatrixLH( 287 const vector3df& position, 288 const vector3df& target, 289 const vector3df& upVector); 290 291 //! Builds a right-handed look-at matrix. 292 CMatrix4<T>& buildCameraLookAtMatrixRH( 293 const vector3df& position, 294 const vector3df& target, 295 const vector3df& upVector); 296 297 //! Builds a matrix that flattens geometry into a plane. 298 /** \param light: light source 299 \param plane: plane into which the geometry if flattened into 300 \param point: value between 0 and 1, describing the light source. 301 If this is 1, it is a point light, if it is 0, it is a directional light. */ 302 CMatrix4<T>& buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point=1.0f); 303 304 //! Builds a matrix which transforms a normalized Device Coordinate to Device Coordinates. 305 /** Used to scale <-1,-1><1,1> to viewport, for example from <-1,-1> <1,1> to the viewport <0,0><0,640> */ 306 CMatrix4<T>& buildNDCToDCMatrix( const core::rect<s32>& area, f32 zScale); 307 308 //! Creates a new matrix as interpolated matrix from two other ones. 309 /** \param b: other matrix to interpolate with 310 \param time: Must be a value between 0 and 1. */ 311 CMatrix4<T> interpolate(const core::CMatrix4<T>& b, f32 time) const; 312 313 //! Gets transposed matrix 314 CMatrix4<T> getTransposed() const; 315 316 //! Gets transposed matrix 317 inline void getTransposed( CMatrix4<T>& dest ) const; 318 319 //! Builds a matrix that rotates from one vector to another 320 /** \param from: vector to rotate from 321 \param to: vector to rotate to 322 */ 323 CMatrix4<T>& buildRotateFromTo(const core::vector3df& from, const core::vector3df& to); 324 325 //! Builds a combined matrix which translates to a center before rotation and translates from origin afterwards 326 /** \param center Position to rotate around 327 \param translate Translation applied after the rotation 328 */ 329 void setRotationCenter(const core::vector3df& center, const core::vector3df& translate); 330 331 //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis 332 /** \param camPos: viewer position in world coo 333 \param center: object position in world-coo and rotation pivot 334 \param translation: object final translation from center 335 \param axis: axis to rotate about 336 \param from: source vector to rotate from 337 */ 338 void buildAxisAlignedBillboard(const core::vector3df& camPos, 339 const core::vector3df& center, 340 const core::vector3df& translation, 341 const core::vector3df& axis, 342 const core::vector3df& from); 343 344 /* 345 construct 2D Texture transformations 346 rotate about center, scale, and transform. 347 */ 348 //! Set to a texture transformation matrix with the given parameters. 349 CMatrix4<T>& buildTextureTransform( f32 rotateRad, 350 const core::vector2df &rotatecenter, 351 const core::vector2df &translate, 352 const core::vector2df &scale); 353 354 //! Set texture transformation rotation 355 /** Rotate about z axis, recenter at (0.5,0.5). 356 Doesn't clear other elements than those affected 357 \param radAngle Angle in radians 358 \return Altered matrix */ 359 CMatrix4<T>& setTextureRotationCenter( f32 radAngle ); 360 361 //! Set texture transformation translation 362 /** Doesn't clear other elements than those affected. 363 \param x Offset on x axis 364 \param y Offset on y axis 365 \return Altered matrix */ 366 CMatrix4<T>& setTextureTranslate( f32 x, f32 y ); 367 368 //! Set texture transformation translation, using a transposed representation 369 /** Doesn't clear other elements than those affected. 370 \param x Offset on x axis 371 \param y Offset on y axis 372 \return Altered matrix */ 373 CMatrix4<T>& setTextureTranslateTransposed( f32 x, f32 y ); 374 375 //! Set texture transformation scale 376 /** Doesn't clear other elements than those affected. 377 \param sx Scale factor on x axis 378 \param sy Scale factor on y axis 379 \return Altered matrix. */ 380 CMatrix4<T>& setTextureScale( f32 sx, f32 sy ); 381 382 //! Set texture transformation scale, and recenter at (0.5,0.5) 383 /** Doesn't clear other elements than those affected. 384 \param sx Scale factor on x axis 385 \param sy Scale factor on y axis 386 \return Altered matrix. */ 387 CMatrix4<T>& setTextureScaleCenter( f32 sx, f32 sy ); 388 389 //! Sets all matrix data members at once 390 CMatrix4<T>& setM(const T* data); 391 392 //! Sets if the matrix is definitely identity matrix 393 void setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix); 394 395 //! Gets if the matrix is definitely identity matrix 396 bool getDefinitelyIdentityMatrix() const; 397 398 //! Compare two matrices using the equal method 399 bool equals(const core::CMatrix4<T>& other, const T tolerance=(T)ROUNDING_ERROR_f64) const; 400 401 private: 402 //! Matrix data, stored in row-major order 403 T M[16]; 404 #if defined ( USE_MATRIX_TEST ) 405 //! Flag is this matrix is identity matrix 406 mutable u32 definitelyIdentityMatrix; 407 #endif 408 #if defined ( USE_MATRIX_TEST_DEBUG ) 409 u32 id; 410 mutable u32 calls; 411 #endif 412 413 }; 414 415 // Default constructor 416 template <class T> CMatrix4(eConstructor constructor)417 inline CMatrix4<T>::CMatrix4( eConstructor constructor ) 418 #if defined ( USE_MATRIX_TEST ) 419 : definitelyIdentityMatrix(BIT_UNTESTED) 420 #endif 421 #if defined ( USE_MATRIX_TEST_DEBUG ) 422 ,id ( MTest.ID++), calls ( 0 ) 423 #endif 424 { 425 switch ( constructor ) 426 { 427 case EM4CONST_NOTHING: 428 case EM4CONST_COPY: 429 break; 430 case EM4CONST_IDENTITY: 431 case EM4CONST_INVERSE: 432 default: 433 makeIdentity(); 434 break; 435 } 436 } 437 438 // Copy constructor 439 template <class T> CMatrix4(const CMatrix4<T> & other,eConstructor constructor)440 inline CMatrix4<T>::CMatrix4( const CMatrix4<T>& other, eConstructor constructor) 441 #if defined ( USE_MATRIX_TEST ) 442 : definitelyIdentityMatrix(BIT_UNTESTED) 443 #endif 444 #if defined ( USE_MATRIX_TEST_DEBUG ) 445 ,id ( MTest.ID++), calls ( 0 ) 446 #endif 447 { 448 switch ( constructor ) 449 { 450 case EM4CONST_IDENTITY: 451 makeIdentity(); 452 break; 453 case EM4CONST_NOTHING: 454 break; 455 case EM4CONST_COPY: 456 *this = other; 457 break; 458 case EM4CONST_TRANSPOSED: 459 other.getTransposed(*this); 460 break; 461 case EM4CONST_INVERSE: 462 if (!other.getInverse(*this)) 463 memset(M, 0, 16*sizeof(T)); 464 break; 465 case EM4CONST_INVERSE_TRANSPOSED: 466 if (!other.getInverse(*this)) 467 memset(M, 0, 16*sizeof(T)); 468 else 469 *this=getTransposed(); 470 break; 471 } 472 } 473 474 //! Add another matrix. 475 template <class T> 476 inline CMatrix4<T> CMatrix4<T>::operator+(const CMatrix4<T>& other) const 477 { 478 CMatrix4<T> temp ( EM4CONST_NOTHING ); 479 480 temp[0] = M[0]+other[0]; 481 temp[1] = M[1]+other[1]; 482 temp[2] = M[2]+other[2]; 483 temp[3] = M[3]+other[3]; 484 temp[4] = M[4]+other[4]; 485 temp[5] = M[5]+other[5]; 486 temp[6] = M[6]+other[6]; 487 temp[7] = M[7]+other[7]; 488 temp[8] = M[8]+other[8]; 489 temp[9] = M[9]+other[9]; 490 temp[10] = M[10]+other[10]; 491 temp[11] = M[11]+other[11]; 492 temp[12] = M[12]+other[12]; 493 temp[13] = M[13]+other[13]; 494 temp[14] = M[14]+other[14]; 495 temp[15] = M[15]+other[15]; 496 497 return temp; 498 } 499 500 //! Add another matrix. 501 template <class T> 502 inline CMatrix4<T>& CMatrix4<T>::operator+=(const CMatrix4<T>& other) 503 { 504 M[0]+=other[0]; 505 M[1]+=other[1]; 506 M[2]+=other[2]; 507 M[3]+=other[3]; 508 M[4]+=other[4]; 509 M[5]+=other[5]; 510 M[6]+=other[6]; 511 M[7]+=other[7]; 512 M[8]+=other[8]; 513 M[9]+=other[9]; 514 M[10]+=other[10]; 515 M[11]+=other[11]; 516 M[12]+=other[12]; 517 M[13]+=other[13]; 518 M[14]+=other[14]; 519 M[15]+=other[15]; 520 521 return *this; 522 } 523 524 //! Subtract another matrix. 525 template <class T> 526 inline CMatrix4<T> CMatrix4<T>::operator-(const CMatrix4<T>& other) const 527 { 528 CMatrix4<T> temp ( EM4CONST_NOTHING ); 529 530 temp[0] = M[0]-other[0]; 531 temp[1] = M[1]-other[1]; 532 temp[2] = M[2]-other[2]; 533 temp[3] = M[3]-other[3]; 534 temp[4] = M[4]-other[4]; 535 temp[5] = M[5]-other[5]; 536 temp[6] = M[6]-other[6]; 537 temp[7] = M[7]-other[7]; 538 temp[8] = M[8]-other[8]; 539 temp[9] = M[9]-other[9]; 540 temp[10] = M[10]-other[10]; 541 temp[11] = M[11]-other[11]; 542 temp[12] = M[12]-other[12]; 543 temp[13] = M[13]-other[13]; 544 temp[14] = M[14]-other[14]; 545 temp[15] = M[15]-other[15]; 546 547 return temp; 548 } 549 550 //! Subtract another matrix. 551 template <class T> 552 inline CMatrix4<T>& CMatrix4<T>::operator-=(const CMatrix4<T>& other) 553 { 554 M[0]-=other[0]; 555 M[1]-=other[1]; 556 M[2]-=other[2]; 557 M[3]-=other[3]; 558 M[4]-=other[4]; 559 M[5]-=other[5]; 560 M[6]-=other[6]; 561 M[7]-=other[7]; 562 M[8]-=other[8]; 563 M[9]-=other[9]; 564 M[10]-=other[10]; 565 M[11]-=other[11]; 566 M[12]-=other[12]; 567 M[13]-=other[13]; 568 M[14]-=other[14]; 569 M[15]-=other[15]; 570 571 return *this; 572 } 573 574 //! Multiply by scalar. 575 template <class T> 576 inline CMatrix4<T> CMatrix4<T>::operator*(const T& scalar) const 577 { 578 CMatrix4<T> temp ( EM4CONST_NOTHING ); 579 580 temp[0] = M[0]*scalar; 581 temp[1] = M[1]*scalar; 582 temp[2] = M[2]*scalar; 583 temp[3] = M[3]*scalar; 584 temp[4] = M[4]*scalar; 585 temp[5] = M[5]*scalar; 586 temp[6] = M[6]*scalar; 587 temp[7] = M[7]*scalar; 588 temp[8] = M[8]*scalar; 589 temp[9] = M[9]*scalar; 590 temp[10] = M[10]*scalar; 591 temp[11] = M[11]*scalar; 592 temp[12] = M[12]*scalar; 593 temp[13] = M[13]*scalar; 594 temp[14] = M[14]*scalar; 595 temp[15] = M[15]*scalar; 596 597 return temp; 598 } 599 600 //! Multiply by scalar. 601 template <class T> 602 inline CMatrix4<T>& CMatrix4<T>::operator*=(const T& scalar) 603 { 604 M[0]*=scalar; 605 M[1]*=scalar; 606 M[2]*=scalar; 607 M[3]*=scalar; 608 M[4]*=scalar; 609 M[5]*=scalar; 610 M[6]*=scalar; 611 M[7]*=scalar; 612 M[8]*=scalar; 613 M[9]*=scalar; 614 M[10]*=scalar; 615 M[11]*=scalar; 616 M[12]*=scalar; 617 M[13]*=scalar; 618 M[14]*=scalar; 619 M[15]*=scalar; 620 621 return *this; 622 } 623 624 //! Multiply by another matrix. 625 template <class T> 626 inline CMatrix4<T>& CMatrix4<T>::operator*=(const CMatrix4<T>& other) 627 { 628 #if defined ( USE_MATRIX_TEST ) 629 // do checks on your own in order to avoid copy creation 630 if ( !other.isIdentity() ) 631 { 632 if ( this->isIdentity() ) 633 { 634 return (*this = other); 635 } 636 else 637 { 638 CMatrix4<T> temp ( *this ); 639 return setbyproduct_nocheck( temp, other ); 640 } 641 } 642 return *this; 643 #else 644 CMatrix4<T> temp ( *this ); 645 return setbyproduct_nocheck( temp, other ); 646 #endif 647 } 648 649 //! multiply by another matrix 650 // set this matrix to the product of two other matrices 651 // goal is to reduce stack use and copy 652 template <class T> setbyproduct_nocheck(const CMatrix4<T> & other_a,const CMatrix4<T> & other_b)653 inline CMatrix4<T>& CMatrix4<T>::setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b ) 654 { 655 const T *m1 = other_a.M; 656 const T *m2 = other_b.M; 657 658 M[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3]; 659 M[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3]; 660 M[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3]; 661 M[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3]; 662 663 M[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7]; 664 M[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7]; 665 M[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7]; 666 M[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7]; 667 668 M[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11]; 669 M[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11]; 670 M[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11]; 671 M[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11]; 672 673 M[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15]; 674 M[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15]; 675 M[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15]; 676 M[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15]; 677 #if defined ( USE_MATRIX_TEST ) 678 definitelyIdentityMatrix=false; 679 #endif 680 return *this; 681 } 682 683 684 //! multiply by another matrix 685 // set this matrix to the product of two other matrices 686 // goal is to reduce stack use and copy 687 template <class T> setbyproduct(const CMatrix4<T> & other_a,const CMatrix4<T> & other_b)688 inline CMatrix4<T>& CMatrix4<T>::setbyproduct(const CMatrix4<T>& other_a, const CMatrix4<T>& other_b ) 689 { 690 #if defined ( USE_MATRIX_TEST ) 691 if ( other_a.isIdentity () ) 692 return (*this = other_b); 693 else 694 if ( other_b.isIdentity () ) 695 return (*this = other_a); 696 else 697 return setbyproduct_nocheck(other_a,other_b); 698 #else 699 return setbyproduct_nocheck(other_a,other_b); 700 #endif 701 } 702 703 //! multiply by another matrix 704 template <class T> 705 inline CMatrix4<T> CMatrix4<T>::operator*(const CMatrix4<T>& m2) const 706 { 707 #if defined ( USE_MATRIX_TEST ) 708 // Testing purpose.. 709 if ( this->isIdentity() ) 710 return m2; 711 if ( m2.isIdentity() ) 712 return *this; 713 #endif 714 715 CMatrix4<T> m3 ( EM4CONST_NOTHING ); 716 717 const T *m1 = M; 718 719 m3[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3]; 720 m3[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3]; 721 m3[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3]; 722 m3[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3]; 723 724 m3[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7]; 725 m3[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7]; 726 m3[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7]; 727 m3[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7]; 728 729 m3[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11]; 730 m3[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11]; 731 m3[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11]; 732 m3[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11]; 733 734 m3[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15]; 735 m3[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15]; 736 m3[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15]; 737 m3[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15]; 738 return m3; 739 } 740 741 742 743 template <class T> getTranslation()744 inline vector3d<T> CMatrix4<T>::getTranslation() const 745 { 746 return vector3d<T>(M[12], M[13], M[14]); 747 } 748 749 750 template <class T> setTranslation(const vector3d<T> & translation)751 inline CMatrix4<T>& CMatrix4<T>::setTranslation( const vector3d<T>& translation ) 752 { 753 M[12] = translation.X; 754 M[13] = translation.Y; 755 M[14] = translation.Z; 756 #if defined ( USE_MATRIX_TEST ) 757 definitelyIdentityMatrix=false; 758 #endif 759 return *this; 760 } 761 762 template <class T> setInverseTranslation(const vector3d<T> & translation)763 inline CMatrix4<T>& CMatrix4<T>::setInverseTranslation( const vector3d<T>& translation ) 764 { 765 M[12] = -translation.X; 766 M[13] = -translation.Y; 767 M[14] = -translation.Z; 768 #if defined ( USE_MATRIX_TEST ) 769 definitelyIdentityMatrix=false; 770 #endif 771 return *this; 772 } 773 774 template <class T> setScale(const vector3d<T> & scale)775 inline CMatrix4<T>& CMatrix4<T>::setScale( const vector3d<T>& scale ) 776 { 777 M[0] = scale.X; 778 M[5] = scale.Y; 779 M[10] = scale.Z; 780 #if defined ( USE_MATRIX_TEST ) 781 definitelyIdentityMatrix=false; 782 #endif 783 return *this; 784 } 785 786 //! Returns the absolute values of the scales of the matrix. 787 /** 788 Note that this returns the absolute (positive) values unless only scale is set. 789 Unfortunately it does not appear to be possible to extract any original negative 790 values. The best that we could do would be to arbitrarily make one scale 791 negative if one or three of them were negative. 792 FIXME - return the original values. 793 */ 794 template <class T> getScale()795 inline vector3d<T> CMatrix4<T>::getScale() const 796 { 797 // See http://www.robertblum.com/articles/2005/02/14/decomposing-matrices 798 799 // Deal with the 0 rotation case first 800 // Prior to Irrlicht 1.6, we always returned this value. 801 if(core::iszero(M[1]) && core::iszero(M[2]) && 802 core::iszero(M[4]) && core::iszero(M[6]) && 803 core::iszero(M[8]) && core::iszero(M[9])) 804 return vector3d<T>(M[0], M[5], M[10]); 805 806 // We have to do the full calculation. 807 return vector3d<T>(sqrtf(M[0] * M[0] + M[1] * M[1] + M[2] * M[2]), 808 sqrtf(M[4] * M[4] + M[5] * M[5] + M[6] * M[6]), 809 sqrtf(M[8] * M[8] + M[9] * M[9] + M[10] * M[10])); 810 } 811 812 template <class T> setRotationDegrees(const vector3d<T> & rotation)813 inline CMatrix4<T>& CMatrix4<T>::setRotationDegrees( const vector3d<T>& rotation ) 814 { 815 return setRotationRadians( rotation * core::DEGTORAD ); 816 } 817 818 template <class T> setInverseRotationDegrees(const vector3d<T> & rotation)819 inline CMatrix4<T>& CMatrix4<T>::setInverseRotationDegrees( const vector3d<T>& rotation ) 820 { 821 return setInverseRotationRadians( rotation * core::DEGTORAD ); 822 } 823 824 template <class T> setRotationRadians(const vector3d<T> & rotation)825 inline CMatrix4<T>& CMatrix4<T>::setRotationRadians( const vector3d<T>& rotation ) 826 { 827 const f64 cr = cos( rotation.X ); 828 const f64 sr = sin( rotation.X ); 829 const f64 cp = cos( rotation.Y ); 830 const f64 sp = sin( rotation.Y ); 831 const f64 cy = cos( rotation.Z ); 832 const f64 sy = sin( rotation.Z ); 833 834 M[0] = (T)( cp*cy ); 835 M[1] = (T)( cp*sy ); 836 M[2] = (T)( -sp ); 837 838 const f64 srsp = sr*sp; 839 const f64 crsp = cr*sp; 840 841 M[4] = (T)( srsp*cy-cr*sy ); 842 M[5] = (T)( srsp*sy+cr*cy ); 843 M[6] = (T)( sr*cp ); 844 845 M[8] = (T)( crsp*cy+sr*sy ); 846 M[9] = (T)( crsp*sy-sr*cy ); 847 M[10] = (T)( cr*cp ); 848 #if defined ( USE_MATRIX_TEST ) 849 definitelyIdentityMatrix=false; 850 #endif 851 return *this; 852 } 853 854 855 //! Returns a rotation that is equivalent to that set by setRotationDegrees(). 856 /** This code was sent in by Chev. Note that it does not necessarily return 857 the *same* Euler angles as those set by setRotationDegrees(), but the rotation will 858 be equivalent, i.e. will have the same result when used to rotate a vector or node. */ 859 template <class T> getRotationDegrees()860 inline core::vector3d<T> CMatrix4<T>::getRotationDegrees() const 861 { 862 const CMatrix4<T> &mat = *this; 863 core::vector3d<T> scale = getScale(); 864 // we need to check for negative scale on to axes, which would bring up wrong results 865 if (scale.Y<0 && scale.Z<0) 866 { 867 scale.Y =-scale.Y; 868 scale.Z =-scale.Z; 869 } 870 else if (scale.X<0 && scale.Z<0) 871 { 872 scale.X =-scale.X; 873 scale.Z =-scale.Z; 874 } 875 else if (scale.X<0 && scale.Y<0) 876 { 877 scale.X =-scale.X; 878 scale.Y =-scale.Y; 879 } 880 const core::vector3d<f64> invScale(core::reciprocal(scale.X),core::reciprocal(scale.Y),core::reciprocal(scale.Z)); 881 882 f64 Y = -asin(core::clamp(mat[2]*invScale.X, -1.0, 1.0)); 883 const f64 C = cos(Y); 884 Y *= RADTODEG64; 885 886 f64 rotx, roty, X, Z; 887 888 if (!core::iszero(C)) 889 { 890 const f64 invC = core::reciprocal(C); 891 rotx = mat[10] * invC * invScale.Z; 892 roty = mat[6] * invC * invScale.Y; 893 X = atan2( roty, rotx ) * RADTODEG64; 894 rotx = mat[0] * invC * invScale.X; 895 roty = mat[1] * invC * invScale.X; 896 Z = atan2( roty, rotx ) * RADTODEG64; 897 } 898 else 899 { 900 X = 0.0; 901 rotx = mat[5] * invScale.Y; 902 roty = -mat[4] * invScale.Y; 903 Z = atan2( roty, rotx ) * RADTODEG64; 904 } 905 906 // fix values that get below zero 907 if (X < 0.0) X += 360.0; 908 if (Y < 0.0) Y += 360.0; 909 if (Z < 0.0) Z += 360.0; 910 911 return vector3d<T>((T)X,(T)Y,(T)Z); 912 } 913 914 915 //! Sets matrix to rotation matrix of inverse angles given as parameters 916 template <class T> setInverseRotationRadians(const vector3d<T> & rotation)917 inline CMatrix4<T>& CMatrix4<T>::setInverseRotationRadians( const vector3d<T>& rotation ) 918 { 919 f64 cr = cos( rotation.X ); 920 f64 sr = sin( rotation.X ); 921 f64 cp = cos( rotation.Y ); 922 f64 sp = sin( rotation.Y ); 923 f64 cy = cos( rotation.Z ); 924 f64 sy = sin( rotation.Z ); 925 926 M[0] = (T)( cp*cy ); 927 M[4] = (T)( cp*sy ); 928 M[8] = (T)( -sp ); 929 930 f64 srsp = sr*sp; 931 f64 crsp = cr*sp; 932 933 M[1] = (T)( srsp*cy-cr*sy ); 934 M[5] = (T)( srsp*sy+cr*cy ); 935 M[9] = (T)( sr*cp ); 936 937 M[2] = (T)( crsp*cy+sr*sy ); 938 M[6] = (T)( crsp*sy-sr*cy ); 939 M[10] = (T)( cr*cp ); 940 #if defined ( USE_MATRIX_TEST ) 941 definitelyIdentityMatrix=false; 942 #endif 943 return *this; 944 } 945 946 //! Sets matrix to rotation matrix defined by axis and angle, assuming LH rotation 947 template <class T> setRotationAxisRadians(const T & angle,const vector3d<T> & axis)948 inline CMatrix4<T>& CMatrix4<T>::setRotationAxisRadians( const T& angle, const vector3d<T>& axis ) 949 { 950 const f64 c = cos(angle); 951 const f64 s = sin(angle); 952 const f64 t = 1.0 - c; 953 954 const f64 tx = t * axis.X; 955 const f64 ty = t * axis.Y; 956 const f64 tz = t * axis.Z; 957 958 const f64 sx = s * axis.X; 959 const f64 sy = s * axis.Y; 960 const f64 sz = s * axis.Z; 961 962 M[0] = (T)(tx * axis.X + c); 963 M[1] = (T)(tx * axis.Y + sz); 964 M[2] = (T)(tx * axis.Z - sy); 965 966 M[4] = (T)(ty * axis.X - sz); 967 M[5] = (T)(ty * axis.Y + c); 968 M[6] = (T)(ty * axis.Z + sx); 969 970 M[8] = (T)(tz * axis.X + sy); 971 M[9] = (T)(tz * axis.Y - sx); 972 M[10] = (T)(tz * axis.Z + c); 973 974 #if defined ( USE_MATRIX_TEST ) 975 definitelyIdentityMatrix=false; 976 #endif 977 return *this; 978 } 979 980 981 /*! 982 */ 983 template <class T> makeIdentity()984 inline CMatrix4<T>& CMatrix4<T>::makeIdentity() 985 { 986 memset(M, 0, 16*sizeof(T)); 987 M[0] = M[5] = M[10] = M[15] = (T)1; 988 #if defined ( USE_MATRIX_TEST ) 989 definitelyIdentityMatrix=true; 990 #endif 991 return *this; 992 } 993 994 995 /* 996 check identity with epsilon 997 solve floating range problems.. 998 */ 999 template <class T> isIdentity()1000 inline bool CMatrix4<T>::isIdentity() const 1001 { 1002 #if defined ( USE_MATRIX_TEST ) 1003 if (definitelyIdentityMatrix) 1004 return true; 1005 #endif 1006 if (!core::equals( M[12], (T)0 ) || !core::equals( M[13], (T)0 ) || !core::equals( M[14], (T)0 ) || !core::equals( M[15], (T)1 )) 1007 return false; 1008 1009 if (!core::equals( M[ 0], (T)1 ) || !core::equals( M[ 1], (T)0 ) || !core::equals( M[ 2], (T)0 ) || !core::equals( M[ 3], (T)0 )) 1010 return false; 1011 1012 if (!core::equals( M[ 4], (T)0 ) || !core::equals( M[ 5], (T)1 ) || !core::equals( M[ 6], (T)0 ) || !core::equals( M[ 7], (T)0 )) 1013 return false; 1014 1015 if (!core::equals( M[ 8], (T)0 ) || !core::equals( M[ 9], (T)0 ) || !core::equals( M[10], (T)1 ) || !core::equals( M[11], (T)0 )) 1016 return false; 1017 /* 1018 if (!core::equals( M[ 0], (T)1 ) || 1019 !core::equals( M[ 5], (T)1 ) || 1020 !core::equals( M[10], (T)1 ) || 1021 !core::equals( M[15], (T)1 )) 1022 return false; 1023 1024 for (s32 i=0; i<4; ++i) 1025 for (s32 j=0; j<4; ++j) 1026 if ((j != i) && (!iszero((*this)(i,j)))) 1027 return false; 1028 */ 1029 #if defined ( USE_MATRIX_TEST ) 1030 definitelyIdentityMatrix=true; 1031 #endif 1032 return true; 1033 } 1034 1035 1036 /* Check orthogonality of matrix. */ 1037 template <class T> isOrthogonal()1038 inline bool CMatrix4<T>::isOrthogonal() const 1039 { 1040 T dp=M[0] * M[4 ] + M[1] * M[5 ] + M[2 ] * M[6 ] + M[3 ] * M[7 ]; 1041 if (!iszero(dp)) 1042 return false; 1043 dp = M[0] * M[8 ] + M[1] * M[9 ] + M[2 ] * M[10] + M[3 ] * M[11]; 1044 if (!iszero(dp)) 1045 return false; 1046 dp = M[0] * M[12] + M[1] * M[13] + M[2 ] * M[14] + M[3 ] * M[15]; 1047 if (!iszero(dp)) 1048 return false; 1049 dp = M[4] * M[8 ] + M[5] * M[9 ] + M[6 ] * M[10] + M[7 ] * M[11]; 1050 if (!iszero(dp)) 1051 return false; 1052 dp = M[4] * M[12] + M[5] * M[13] + M[6 ] * M[14] + M[7 ] * M[15]; 1053 if (!iszero(dp)) 1054 return false; 1055 dp = M[8] * M[12] + M[9] * M[13] + M[10] * M[14] + M[11] * M[15]; 1056 return (iszero(dp)); 1057 } 1058 1059 1060 /* 1061 doesn't solve floating range problems.. 1062 but takes care on +/- 0 on translation because we are changing it.. 1063 reducing floating point branches 1064 but it needs the floats in memory.. 1065 */ 1066 template <class T> isIdentity_integer_base()1067 inline bool CMatrix4<T>::isIdentity_integer_base() const 1068 { 1069 #if defined ( USE_MATRIX_TEST ) 1070 if (definitelyIdentityMatrix) 1071 return true; 1072 #endif 1073 if(IR(M[0])!=F32_VALUE_1) return false; 1074 if(IR(M[1])!=0) return false; 1075 if(IR(M[2])!=0) return false; 1076 if(IR(M[3])!=0) return false; 1077 1078 if(IR(M[4])!=0) return false; 1079 if(IR(M[5])!=F32_VALUE_1) return false; 1080 if(IR(M[6])!=0) return false; 1081 if(IR(M[7])!=0) return false; 1082 1083 if(IR(M[8])!=0) return false; 1084 if(IR(M[9])!=0) return false; 1085 if(IR(M[10])!=F32_VALUE_1) return false; 1086 if(IR(M[11])!=0) return false; 1087 1088 if(IR(M[12])!=0) return false; 1089 if(IR(M[13])!=0) return false; 1090 if(IR(M[13])!=0) return false; 1091 if(IR(M[15])!=F32_VALUE_1) return false; 1092 1093 #if defined ( USE_MATRIX_TEST ) 1094 definitelyIdentityMatrix=true; 1095 #endif 1096 return true; 1097 } 1098 1099 1100 template <class T> rotateVect(vector3df & vect)1101 inline void CMatrix4<T>::rotateVect( vector3df& vect ) const 1102 { 1103 vector3df tmp = vect; 1104 vect.X = tmp.X*M[0] + tmp.Y*M[4] + tmp.Z*M[8]; 1105 vect.Y = tmp.X*M[1] + tmp.Y*M[5] + tmp.Z*M[9]; 1106 vect.Z = tmp.X*M[2] + tmp.Y*M[6] + tmp.Z*M[10]; 1107 } 1108 1109 //! An alternate transform vector method, writing into a second vector 1110 template <class T> rotateVect(core::vector3df & out,const core::vector3df & in)1111 inline void CMatrix4<T>::rotateVect(core::vector3df& out, const core::vector3df& in) const 1112 { 1113 out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8]; 1114 out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9]; 1115 out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10]; 1116 } 1117 1118 //! An alternate transform vector method, writing into an array of 3 floats 1119 template <class T> rotateVect(T * out,const core::vector3df & in)1120 inline void CMatrix4<T>::rotateVect(T *out, const core::vector3df& in) const 1121 { 1122 out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8]; 1123 out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9]; 1124 out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10]; 1125 } 1126 1127 template <class T> inverseRotateVect(vector3df & vect)1128 inline void CMatrix4<T>::inverseRotateVect( vector3df& vect ) const 1129 { 1130 vector3df tmp = vect; 1131 vect.X = tmp.X*M[0] + tmp.Y*M[1] + tmp.Z*M[2]; 1132 vect.Y = tmp.X*M[4] + tmp.Y*M[5] + tmp.Z*M[6]; 1133 vect.Z = tmp.X*M[8] + tmp.Y*M[9] + tmp.Z*M[10]; 1134 } 1135 1136 template <class T> transformVect(vector3df & vect)1137 inline void CMatrix4<T>::transformVect( vector3df& vect) const 1138 { 1139 f32 vector[3]; 1140 1141 vector[0] = vect.X*M[0] + vect.Y*M[4] + vect.Z*M[8] + M[12]; 1142 vector[1] = vect.X*M[1] + vect.Y*M[5] + vect.Z*M[9] + M[13]; 1143 vector[2] = vect.X*M[2] + vect.Y*M[6] + vect.Z*M[10] + M[14]; 1144 1145 vect.X = vector[0]; 1146 vect.Y = vector[1]; 1147 vect.Z = vector[2]; 1148 } 1149 1150 template <class T> transformVect(vector3df & out,const vector3df & in)1151 inline void CMatrix4<T>::transformVect( vector3df& out, const vector3df& in) const 1152 { 1153 out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12]; 1154 out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13]; 1155 out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14]; 1156 } 1157 1158 1159 template <class T> transformVect(T * out,const core::vector3df & in)1160 inline void CMatrix4<T>::transformVect(T *out, const core::vector3df &in) const 1161 { 1162 out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12]; 1163 out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13]; 1164 out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14]; 1165 out[3] = in.X*M[3] + in.Y*M[7] + in.Z*M[11] + M[15]; 1166 } 1167 1168 template <class T> transformVec3(T * out,const T * in)1169 inline void CMatrix4<T>::transformVec3(T *out, const T * in) const 1170 { 1171 out[0] = in[0]*M[0] + in[1]*M[4] + in[2]*M[8] + M[12]; 1172 out[1] = in[0]*M[1] + in[1]*M[5] + in[2]*M[9] + M[13]; 1173 out[2] = in[0]*M[2] + in[1]*M[6] + in[2]*M[10] + M[14]; 1174 } 1175 1176 1177 //! Transforms a plane by this matrix 1178 template <class T> transformPlane(core::plane3d<f32> & plane)1179 inline void CMatrix4<T>::transformPlane( core::plane3d<f32> &plane) const 1180 { 1181 vector3df member; 1182 // Transform the plane member point, i.e. rotate, translate and scale it. 1183 transformVect(member, plane.getMemberPoint()); 1184 1185 // Transform the normal by the transposed inverse of the matrix 1186 CMatrix4<T> transposedInverse(*this, EM4CONST_INVERSE_TRANSPOSED); 1187 vector3df normal = plane.Normal; 1188 transposedInverse.transformVect(normal); 1189 1190 plane.setPlane(member, normal); 1191 } 1192 1193 //! Transforms a plane by this matrix 1194 template <class T> transformPlane(const core::plane3d<f32> & in,core::plane3d<f32> & out)1195 inline void CMatrix4<T>::transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const 1196 { 1197 out = in; 1198 transformPlane( out ); 1199 } 1200 1201 //! Transforms the edge-points of a bounding box 1202 //! Deprecated as it's usually not what people need (regards only 2 corners, but other corners might be outside the box after transformation) 1203 //! Use transformBoxEx instead. 1204 template <class T> transformBox(core::aabbox3d<f32> & box)1205 _IRR_DEPRECATED_ inline void CMatrix4<T>::transformBox(core::aabbox3d<f32>& box) const 1206 { 1207 #if defined ( USE_MATRIX_TEST ) 1208 if (isIdentity()) 1209 return; 1210 #endif 1211 1212 transformVect(box.MinEdge); 1213 transformVect(box.MaxEdge); 1214 box.repair(); 1215 } 1216 1217 //! Transforms a axis aligned bounding box more accurately than transformBox() 1218 template <class T> transformBoxEx(core::aabbox3d<f32> & box)1219 inline void CMatrix4<T>::transformBoxEx(core::aabbox3d<f32>& box) const 1220 { 1221 #if defined ( USE_MATRIX_TEST ) 1222 if (isIdentity()) 1223 return; 1224 #endif 1225 1226 const f32 Amin[3] = {box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z}; 1227 const f32 Amax[3] = {box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z}; 1228 1229 f32 Bmin[3]; 1230 f32 Bmax[3]; 1231 1232 Bmin[0] = Bmax[0] = M[12]; 1233 Bmin[1] = Bmax[1] = M[13]; 1234 Bmin[2] = Bmax[2] = M[14]; 1235 1236 const CMatrix4<T> &m = *this; 1237 1238 for (u32 i = 0; i < 3; ++i) 1239 { 1240 for (u32 j = 0; j < 3; ++j) 1241 { 1242 const f32 a = m(j,i) * Amin[j]; 1243 const f32 b = m(j,i) * Amax[j]; 1244 1245 if (a < b) 1246 { 1247 Bmin[i] += a; 1248 Bmax[i] += b; 1249 } 1250 else 1251 { 1252 Bmin[i] += b; 1253 Bmax[i] += a; 1254 } 1255 } 1256 } 1257 1258 box.MinEdge.X = Bmin[0]; 1259 box.MinEdge.Y = Bmin[1]; 1260 box.MinEdge.Z = Bmin[2]; 1261 1262 box.MaxEdge.X = Bmax[0]; 1263 box.MaxEdge.Y = Bmax[1]; 1264 box.MaxEdge.Z = Bmax[2]; 1265 } 1266 1267 1268 //! Multiplies this matrix by a 1x4 matrix 1269 template <class T> multiplyWith1x4Matrix(T * matrix)1270 inline void CMatrix4<T>::multiplyWith1x4Matrix(T* matrix) const 1271 { 1272 /* 1273 0 1 2 3 1274 4 5 6 7 1275 8 9 10 11 1276 12 13 14 15 1277 */ 1278 1279 T mat[4]; 1280 mat[0] = matrix[0]; 1281 mat[1] = matrix[1]; 1282 mat[2] = matrix[2]; 1283 mat[3] = matrix[3]; 1284 1285 matrix[0] = M[0]*mat[0] + M[4]*mat[1] + M[8]*mat[2] + M[12]*mat[3]; 1286 matrix[1] = M[1]*mat[0] + M[5]*mat[1] + M[9]*mat[2] + M[13]*mat[3]; 1287 matrix[2] = M[2]*mat[0] + M[6]*mat[1] + M[10]*mat[2] + M[14]*mat[3]; 1288 matrix[3] = M[3]*mat[0] + M[7]*mat[1] + M[11]*mat[2] + M[15]*mat[3]; 1289 } 1290 1291 template <class T> inverseTranslateVect(vector3df & vect)1292 inline void CMatrix4<T>::inverseTranslateVect( vector3df& vect ) const 1293 { 1294 vect.X = vect.X-M[12]; 1295 vect.Y = vect.Y-M[13]; 1296 vect.Z = vect.Z-M[14]; 1297 } 1298 1299 template <class T> translateVect(vector3df & vect)1300 inline void CMatrix4<T>::translateVect( vector3df& vect ) const 1301 { 1302 vect.X = vect.X+M[12]; 1303 vect.Y = vect.Y+M[13]; 1304 vect.Z = vect.Z+M[14]; 1305 } 1306 1307 1308 template <class T> getInverse(CMatrix4<T> & out)1309 inline bool CMatrix4<T>::getInverse(CMatrix4<T>& out) const 1310 { 1311 /// Calculates the inverse of this Matrix 1312 /// The inverse is calculated using Cramers rule. 1313 /// If no inverse exists then 'false' is returned. 1314 1315 #if defined ( USE_MATRIX_TEST ) 1316 if ( this->isIdentity() ) 1317 { 1318 out=*this; 1319 return true; 1320 } 1321 #endif 1322 const CMatrix4<T> &m = *this; 1323 1324 f32 d = (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) * (m(2, 2) * m(3, 3) - m(2, 3) * m(3, 2)) - 1325 (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) + 1326 (m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1)) + 1327 (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) - 1328 (m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) + 1329 (m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0)); 1330 1331 if( core::iszero ( d, FLT_MIN ) ) 1332 return false; 1333 1334 d = core::reciprocal ( d ); 1335 1336 out(0, 0) = d * (m(1, 1) * (m(2, 2) * m(3, 3) - m(2, 3) * m(3, 2)) + 1337 m(1, 2) * (m(2, 3) * m(3, 1) - m(2, 1) * m(3, 3)) + 1338 m(1, 3) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1))); 1339 out(0, 1) = d * (m(2, 1) * (m(0, 2) * m(3, 3) - m(0, 3) * m(3, 2)) + 1340 m(2, 2) * (m(0, 3) * m(3, 1) - m(0, 1) * m(3, 3)) + 1341 m(2, 3) * (m(0, 1) * m(3, 2) - m(0, 2) * m(3, 1))); 1342 out(0, 2) = d * (m(3, 1) * (m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) + 1343 m(3, 2) * (m(0, 3) * m(1, 1) - m(0, 1) * m(1, 3)) + 1344 m(3, 3) * (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1))); 1345 out(0, 3) = d * (m(0, 1) * (m(1, 3) * m(2, 2) - m(1, 2) * m(2, 3)) + 1346 m(0, 2) * (m(1, 1) * m(2, 3) - m(1, 3) * m(2, 1)) + 1347 m(0, 3) * (m(1, 2) * m(2, 1) - m(1, 1) * m(2, 2))); 1348 out(1, 0) = d * (m(1, 2) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) + 1349 m(1, 3) * (m(2, 2) * m(3, 0) - m(2, 0) * m(3, 2)) + 1350 m(1, 0) * (m(2, 3) * m(3, 2) - m(2, 2) * m(3, 3))); 1351 out(1, 1) = d * (m(2, 2) * (m(0, 0) * m(3, 3) - m(0, 3) * m(3, 0)) + 1352 m(2, 3) * (m(0, 2) * m(3, 0) - m(0, 0) * m(3, 2)) + 1353 m(2, 0) * (m(0, 3) * m(3, 2) - m(0, 2) * m(3, 3))); 1354 out(1, 2) = d * (m(3, 2) * (m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) + 1355 m(3, 3) * (m(0, 2) * m(1, 0) - m(0, 0) * m(1, 2)) + 1356 m(3, 0) * (m(0, 3) * m(1, 2) - m(0, 2) * m(1, 3))); 1357 out(1, 3) = d * (m(0, 2) * (m(1, 3) * m(2, 0) - m(1, 0) * m(2, 3)) + 1358 m(0, 3) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) + 1359 m(0, 0) * (m(1, 2) * m(2, 3) - m(1, 3) * m(2, 2))); 1360 out(2, 0) = d * (m(1, 3) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0)) + 1361 m(1, 0) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) + 1362 m(1, 1) * (m(2, 3) * m(3, 0) - m(2, 0) * m(3, 3))); 1363 out(2, 1) = d * (m(2, 3) * (m(0, 0) * m(3, 1) - m(0, 1) * m(3, 0)) + 1364 m(2, 0) * (m(0, 1) * m(3, 3) - m(0, 3) * m(3, 1)) + 1365 m(2, 1) * (m(0, 3) * m(3, 0) - m(0, 0) * m(3, 3))); 1366 out(2, 2) = d * (m(3, 3) * (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) + 1367 m(3, 0) * (m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) + 1368 m(3, 1) * (m(0, 3) * m(1, 0) - m(0, 0) * m(1, 3))); 1369 out(2, 3) = d * (m(0, 3) * (m(1, 1) * m(2, 0) - m(1, 0) * m(2, 1)) + 1370 m(0, 0) * (m(1, 3) * m(2, 1) - m(1, 1) * m(2, 3)) + 1371 m(0, 1) * (m(1, 0) * m(2, 3) - m(1, 3) * m(2, 0))); 1372 out(3, 0) = d * (m(1, 0) * (m(2, 2) * m(3, 1) - m(2, 1) * m(3, 2)) + 1373 m(1, 1) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) + 1374 m(1, 2) * (m(2, 1) * m(3, 0) - m(2, 0) * m(3, 1))); 1375 out(3, 1) = d * (m(2, 0) * (m(0, 2) * m(3, 1) - m(0, 1) * m(3, 2)) + 1376 m(2, 1) * (m(0, 0) * m(3, 2) - m(0, 2) * m(3, 0)) + 1377 m(2, 2) * (m(0, 1) * m(3, 0) - m(0, 0) * m(3, 1))); 1378 out(3, 2) = d * (m(3, 0) * (m(0, 2) * m(1, 1) - m(0, 1) * m(1, 2)) + 1379 m(3, 1) * (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) + 1380 m(3, 2) * (m(0, 1) * m(1, 0) - m(0, 0) * m(1, 1))); 1381 out(3, 3) = d * (m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) + 1382 m(0, 1) * (m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2)) + 1383 m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0))); 1384 1385 #if defined ( USE_MATRIX_TEST ) 1386 out.definitelyIdentityMatrix = definitelyIdentityMatrix; 1387 #endif 1388 return true; 1389 } 1390 1391 1392 //! Inverts a primitive matrix which only contains a translation and a rotation 1393 //! \param out: where result matrix is written to. 1394 template <class T> getInversePrimitive(CMatrix4<T> & out)1395 inline bool CMatrix4<T>::getInversePrimitive ( CMatrix4<T>& out ) const 1396 { 1397 out.M[0 ] = M[0]; 1398 out.M[1 ] = M[4]; 1399 out.M[2 ] = M[8]; 1400 out.M[3 ] = 0; 1401 1402 out.M[4 ] = M[1]; 1403 out.M[5 ] = M[5]; 1404 out.M[6 ] = M[9]; 1405 out.M[7 ] = 0; 1406 1407 out.M[8 ] = M[2]; 1408 out.M[9 ] = M[6]; 1409 out.M[10] = M[10]; 1410 out.M[11] = 0; 1411 1412 out.M[12] = (T)-(M[12]*M[0] + M[13]*M[1] + M[14]*M[2]); 1413 out.M[13] = (T)-(M[12]*M[4] + M[13]*M[5] + M[14]*M[6]); 1414 out.M[14] = (T)-(M[12]*M[8] + M[13]*M[9] + M[14]*M[10]); 1415 out.M[15] = 1; 1416 1417 #if defined ( USE_MATRIX_TEST ) 1418 out.definitelyIdentityMatrix = definitelyIdentityMatrix; 1419 #endif 1420 return true; 1421 } 1422 1423 /*! 1424 */ 1425 template <class T> makeInverse()1426 inline bool CMatrix4<T>::makeInverse() 1427 { 1428 #if defined ( USE_MATRIX_TEST ) 1429 if (definitelyIdentityMatrix) 1430 return true; 1431 #endif 1432 CMatrix4<T> temp ( EM4CONST_NOTHING ); 1433 1434 if (getInverse(temp)) 1435 { 1436 *this = temp; 1437 return true; 1438 } 1439 1440 return false; 1441 } 1442 1443 1444 template <class T> 1445 inline CMatrix4<T>& CMatrix4<T>::operator=(const CMatrix4<T> &other) 1446 { 1447 if (this==&other) 1448 return *this; 1449 memcpy(M, other.M, 16*sizeof(T)); 1450 #if defined ( USE_MATRIX_TEST ) 1451 definitelyIdentityMatrix=other.definitelyIdentityMatrix; 1452 #endif 1453 return *this; 1454 } 1455 1456 1457 template <class T> 1458 inline CMatrix4<T>& CMatrix4<T>::operator=(const T& scalar) 1459 { 1460 for (s32 i = 0; i < 16; ++i) 1461 M[i]=scalar; 1462 1463 #if defined ( USE_MATRIX_TEST ) 1464 definitelyIdentityMatrix=false; 1465 #endif 1466 return *this; 1467 } 1468 1469 1470 template <class T> 1471 inline bool CMatrix4<T>::operator==(const CMatrix4<T> &other) const 1472 { 1473 #if defined ( USE_MATRIX_TEST ) 1474 if (definitelyIdentityMatrix && other.definitelyIdentityMatrix) 1475 return true; 1476 #endif 1477 for (s32 i = 0; i < 16; ++i) 1478 if (M[i] != other.M[i]) 1479 return false; 1480 1481 return true; 1482 } 1483 1484 1485 template <class T> 1486 inline bool CMatrix4<T>::operator!=(const CMatrix4<T> &other) const 1487 { 1488 return !(*this == other); 1489 } 1490 1491 1492 // Builds a right-handed perspective projection matrix based on a field of view 1493 template <class T> buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians,f32 aspectRatio,f32 zNear,f32 zFar)1494 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovRH( 1495 f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar) 1496 { 1497 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5)); 1498 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero 1499 const T w = static_cast<T>(h / aspectRatio); 1500 1501 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero 1502 M[0] = w; 1503 M[1] = 0; 1504 M[2] = 0; 1505 M[3] = 0; 1506 1507 M[4] = 0; 1508 M[5] = (T)h; 1509 M[6] = 0; 1510 M[7] = 0; 1511 1512 M[8] = 0; 1513 M[9] = 0; 1514 M[10] = (T)(zFar/(zNear-zFar)); // DirectX version 1515 // M[10] = (T)(zFar+zNear/(zNear-zFar)); // OpenGL version 1516 M[11] = -1; 1517 1518 M[12] = 0; 1519 M[13] = 0; 1520 M[14] = (T)(zNear*zFar/(zNear-zFar)); // DirectX version 1521 // M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar)); // OpenGL version 1522 M[15] = 0; 1523 1524 #if defined ( USE_MATRIX_TEST ) 1525 definitelyIdentityMatrix=false; 1526 #endif 1527 return *this; 1528 } 1529 1530 1531 // Builds a left-handed perspective projection matrix based on a field of view 1532 template <class T> buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians,f32 aspectRatio,f32 zNear,f32 zFar)1533 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovLH( 1534 f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar) 1535 { 1536 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5)); 1537 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero 1538 const T w = static_cast<T>(h / aspectRatio); 1539 1540 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero 1541 M[0] = w; 1542 M[1] = 0; 1543 M[2] = 0; 1544 M[3] = 0; 1545 1546 M[4] = 0; 1547 M[5] = (T)h; 1548 M[6] = 0; 1549 M[7] = 0; 1550 1551 M[8] = 0; 1552 M[9] = 0; 1553 M[10] = (T)(zFar/(zFar-zNear)); 1554 M[11] = 1; 1555 1556 M[12] = 0; 1557 M[13] = 0; 1558 M[14] = (T)(-zNear*zFar/(zFar-zNear)); 1559 M[15] = 0; 1560 1561 #if defined ( USE_MATRIX_TEST ) 1562 definitelyIdentityMatrix=false; 1563 #endif 1564 return *this; 1565 } 1566 1567 1568 // Builds a left-handed perspective projection matrix based on a field of view, with far plane culling at infinity 1569 template <class T> buildProjectionMatrixPerspectiveFovInfinityLH(f32 fieldOfViewRadians,f32 aspectRatio,f32 zNear,f32 epsilon)1570 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovInfinityLH( 1571 f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon) 1572 { 1573 const f64 h = reciprocal(tan(fieldOfViewRadians*0.5)); 1574 _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero 1575 const T w = static_cast<T>(h / aspectRatio); 1576 1577 M[0] = w; 1578 M[1] = 0; 1579 M[2] = 0; 1580 M[3] = 0; 1581 1582 M[4] = 0; 1583 M[5] = (T)h; 1584 M[6] = 0; 1585 M[7] = 0; 1586 1587 M[8] = 0; 1588 M[9] = 0; 1589 M[10] = (T)(1.f-epsilon); 1590 M[11] = 1; 1591 1592 M[12] = 0; 1593 M[13] = 0; 1594 M[14] = (T)(zNear*(epsilon-1.f)); 1595 M[15] = 0; 1596 1597 #if defined ( USE_MATRIX_TEST ) 1598 definitelyIdentityMatrix=false; 1599 #endif 1600 return *this; 1601 } 1602 1603 1604 // Builds a left-handed orthogonal projection matrix. 1605 template <class T> buildProjectionMatrixOrthoLH(f32 widthOfViewVolume,f32 heightOfViewVolume,f32 zNear,f32 zFar)1606 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoLH( 1607 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar) 1608 { 1609 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero 1610 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero 1611 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero 1612 M[0] = (T)(2/widthOfViewVolume); 1613 M[1] = 0; 1614 M[2] = 0; 1615 M[3] = 0; 1616 1617 M[4] = 0; 1618 M[5] = (T)(2/heightOfViewVolume); 1619 M[6] = 0; 1620 M[7] = 0; 1621 1622 M[8] = 0; 1623 M[9] = 0; 1624 M[10] = (T)(1/(zFar-zNear)); 1625 M[11] = 0; 1626 1627 M[12] = 0; 1628 M[13] = 0; 1629 M[14] = (T)(zNear/(zNear-zFar)); 1630 M[15] = 1; 1631 1632 #if defined ( USE_MATRIX_TEST ) 1633 definitelyIdentityMatrix=false; 1634 #endif 1635 return *this; 1636 } 1637 1638 1639 // Builds a right-handed orthogonal projection matrix. 1640 template <class T> buildProjectionMatrixOrthoRH(f32 widthOfViewVolume,f32 heightOfViewVolume,f32 zNear,f32 zFar)1641 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoRH( 1642 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar) 1643 { 1644 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero 1645 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero 1646 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero 1647 M[0] = (T)(2/widthOfViewVolume); 1648 M[1] = 0; 1649 M[2] = 0; 1650 M[3] = 0; 1651 1652 M[4] = 0; 1653 M[5] = (T)(2/heightOfViewVolume); 1654 M[6] = 0; 1655 M[7] = 0; 1656 1657 M[8] = 0; 1658 M[9] = 0; 1659 M[10] = (T)(1/(zNear-zFar)); 1660 M[11] = 0; 1661 1662 M[12] = 0; 1663 M[13] = 0; 1664 M[14] = (T)(zNear/(zNear-zFar)); 1665 M[15] = 1; 1666 1667 #if defined ( USE_MATRIX_TEST ) 1668 definitelyIdentityMatrix=false; 1669 #endif 1670 return *this; 1671 } 1672 1673 1674 // Builds a right-handed perspective projection matrix. 1675 template <class T> buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume,f32 heightOfViewVolume,f32 zNear,f32 zFar)1676 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveRH( 1677 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar) 1678 { 1679 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero 1680 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero 1681 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero 1682 M[0] = (T)(2*zNear/widthOfViewVolume); 1683 M[1] = 0; 1684 M[2] = 0; 1685 M[3] = 0; 1686 1687 M[4] = 0; 1688 M[5] = (T)(2*zNear/heightOfViewVolume); 1689 M[6] = 0; 1690 M[7] = 0; 1691 1692 M[8] = 0; 1693 M[9] = 0; 1694 M[10] = (T)(zFar/(zNear-zFar)); 1695 M[11] = -1; 1696 1697 M[12] = 0; 1698 M[13] = 0; 1699 M[14] = (T)(zNear*zFar/(zNear-zFar)); 1700 M[15] = 0; 1701 1702 #if defined ( USE_MATRIX_TEST ) 1703 definitelyIdentityMatrix=false; 1704 #endif 1705 return *this; 1706 } 1707 1708 1709 // Builds a left-handed perspective projection matrix. 1710 template <class T> buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume,f32 heightOfViewVolume,f32 zNear,f32 zFar)1711 inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveLH( 1712 f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar) 1713 { 1714 _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero 1715 _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero 1716 _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero 1717 M[0] = (T)(2*zNear/widthOfViewVolume); 1718 M[1] = 0; 1719 M[2] = 0; 1720 M[3] = 0; 1721 1722 M[4] = 0; 1723 M[5] = (T)(2*zNear/heightOfViewVolume); 1724 M[6] = 0; 1725 M[7] = 0; 1726 1727 M[8] = 0; 1728 M[9] = 0; 1729 M[10] = (T)(zFar/(zFar-zNear)); 1730 M[11] = 1; 1731 1732 M[12] = 0; 1733 M[13] = 0; 1734 M[14] = (T)(zNear*zFar/(zNear-zFar)); 1735 M[15] = 0; 1736 #if defined ( USE_MATRIX_TEST ) 1737 definitelyIdentityMatrix=false; 1738 #endif 1739 return *this; 1740 } 1741 1742 1743 // Builds a matrix that flattens geometry into a plane. 1744 template <class T> buildShadowMatrix(const core::vector3df & light,core::plane3df plane,f32 point)1745 inline CMatrix4<T>& CMatrix4<T>::buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point) 1746 { 1747 plane.Normal.normalize(); 1748 const f32 d = plane.Normal.dotProduct(light); 1749 1750 M[ 0] = (T)(-plane.Normal.X * light.X + d); 1751 M[ 1] = (T)(-plane.Normal.X * light.Y); 1752 M[ 2] = (T)(-plane.Normal.X * light.Z); 1753 M[ 3] = (T)(-plane.Normal.X * point); 1754 1755 M[ 4] = (T)(-plane.Normal.Y * light.X); 1756 M[ 5] = (T)(-plane.Normal.Y * light.Y + d); 1757 M[ 6] = (T)(-plane.Normal.Y * light.Z); 1758 M[ 7] = (T)(-plane.Normal.Y * point); 1759 1760 M[ 8] = (T)(-plane.Normal.Z * light.X); 1761 M[ 9] = (T)(-plane.Normal.Z * light.Y); 1762 M[10] = (T)(-plane.Normal.Z * light.Z + d); 1763 M[11] = (T)(-plane.Normal.Z * point); 1764 1765 M[12] = (T)(-plane.D * light.X); 1766 M[13] = (T)(-plane.D * light.Y); 1767 M[14] = (T)(-plane.D * light.Z); 1768 M[15] = (T)(-plane.D * point + d); 1769 #if defined ( USE_MATRIX_TEST ) 1770 definitelyIdentityMatrix=false; 1771 #endif 1772 return *this; 1773 } 1774 1775 // Builds a left-handed look-at matrix. 1776 template <class T> buildCameraLookAtMatrixLH(const vector3df & position,const vector3df & target,const vector3df & upVector)1777 inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixLH( 1778 const vector3df& position, 1779 const vector3df& target, 1780 const vector3df& upVector) 1781 { 1782 vector3df zaxis = target - position; 1783 zaxis.normalize(); 1784 1785 vector3df xaxis = upVector.crossProduct(zaxis); 1786 xaxis.normalize(); 1787 1788 vector3df yaxis = zaxis.crossProduct(xaxis); 1789 1790 M[0] = (T)xaxis.X; 1791 M[1] = (T)yaxis.X; 1792 M[2] = (T)zaxis.X; 1793 M[3] = 0; 1794 1795 M[4] = (T)xaxis.Y; 1796 M[5] = (T)yaxis.Y; 1797 M[6] = (T)zaxis.Y; 1798 M[7] = 0; 1799 1800 M[8] = (T)xaxis.Z; 1801 M[9] = (T)yaxis.Z; 1802 M[10] = (T)zaxis.Z; 1803 M[11] = 0; 1804 1805 M[12] = (T)-xaxis.dotProduct(position); 1806 M[13] = (T)-yaxis.dotProduct(position); 1807 M[14] = (T)-zaxis.dotProduct(position); 1808 M[15] = 1; 1809 #if defined ( USE_MATRIX_TEST ) 1810 definitelyIdentityMatrix=false; 1811 #endif 1812 return *this; 1813 } 1814 1815 1816 // Builds a right-handed look-at matrix. 1817 template <class T> buildCameraLookAtMatrixRH(const vector3df & position,const vector3df & target,const vector3df & upVector)1818 inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixRH( 1819 const vector3df& position, 1820 const vector3df& target, 1821 const vector3df& upVector) 1822 { 1823 vector3df zaxis = position - target; 1824 zaxis.normalize(); 1825 1826 vector3df xaxis = upVector.crossProduct(zaxis); 1827 xaxis.normalize(); 1828 1829 vector3df yaxis = zaxis.crossProduct(xaxis); 1830 1831 M[0] = (T)xaxis.X; 1832 M[1] = (T)yaxis.X; 1833 M[2] = (T)zaxis.X; 1834 M[3] = 0; 1835 1836 M[4] = (T)xaxis.Y; 1837 M[5] = (T)yaxis.Y; 1838 M[6] = (T)zaxis.Y; 1839 M[7] = 0; 1840 1841 M[8] = (T)xaxis.Z; 1842 M[9] = (T)yaxis.Z; 1843 M[10] = (T)zaxis.Z; 1844 M[11] = 0; 1845 1846 M[12] = (T)-xaxis.dotProduct(position); 1847 M[13] = (T)-yaxis.dotProduct(position); 1848 M[14] = (T)-zaxis.dotProduct(position); 1849 M[15] = 1; 1850 #if defined ( USE_MATRIX_TEST ) 1851 definitelyIdentityMatrix=false; 1852 #endif 1853 return *this; 1854 } 1855 1856 1857 // creates a new matrix as interpolated matrix from this and the passed one. 1858 template <class T> interpolate(const core::CMatrix4<T> & b,f32 time)1859 inline CMatrix4<T> CMatrix4<T>::interpolate(const core::CMatrix4<T>& b, f32 time) const 1860 { 1861 CMatrix4<T> mat ( EM4CONST_NOTHING ); 1862 1863 for (u32 i=0; i < 16; i += 4) 1864 { 1865 mat.M[i+0] = (T)(M[i+0] + ( b.M[i+0] - M[i+0] ) * time); 1866 mat.M[i+1] = (T)(M[i+1] + ( b.M[i+1] - M[i+1] ) * time); 1867 mat.M[i+2] = (T)(M[i+2] + ( b.M[i+2] - M[i+2] ) * time); 1868 mat.M[i+3] = (T)(M[i+3] + ( b.M[i+3] - M[i+3] ) * time); 1869 } 1870 return mat; 1871 } 1872 1873 1874 // returns transposed matrix 1875 template <class T> getTransposed()1876 inline CMatrix4<T> CMatrix4<T>::getTransposed() const 1877 { 1878 CMatrix4<T> t ( EM4CONST_NOTHING ); 1879 getTransposed ( t ); 1880 return t; 1881 } 1882 1883 1884 // returns transposed matrix 1885 template <class T> getTransposed(CMatrix4<T> & o)1886 inline void CMatrix4<T>::getTransposed( CMatrix4<T>& o ) const 1887 { 1888 o[ 0] = M[ 0]; 1889 o[ 1] = M[ 4]; 1890 o[ 2] = M[ 8]; 1891 o[ 3] = M[12]; 1892 1893 o[ 4] = M[ 1]; 1894 o[ 5] = M[ 5]; 1895 o[ 6] = M[ 9]; 1896 o[ 7] = M[13]; 1897 1898 o[ 8] = M[ 2]; 1899 o[ 9] = M[ 6]; 1900 o[10] = M[10]; 1901 o[11] = M[14]; 1902 1903 o[12] = M[ 3]; 1904 o[13] = M[ 7]; 1905 o[14] = M[11]; 1906 o[15] = M[15]; 1907 #if defined ( USE_MATRIX_TEST ) 1908 o.definitelyIdentityMatrix=definitelyIdentityMatrix; 1909 #endif 1910 } 1911 1912 1913 // used to scale <-1,-1><1,1> to viewport 1914 template <class T> buildNDCToDCMatrix(const core::rect<s32> & viewport,f32 zScale)1915 inline CMatrix4<T>& CMatrix4<T>::buildNDCToDCMatrix( const core::rect<s32>& viewport, f32 zScale) 1916 { 1917 const f32 scaleX = (viewport.getWidth() - 0.75f ) * 0.5f; 1918 const f32 scaleY = -(viewport.getHeight() - 0.75f ) * 0.5f; 1919 1920 const f32 dx = -0.5f + ( (viewport.UpperLeftCorner.X + viewport.LowerRightCorner.X ) * 0.5f ); 1921 const f32 dy = -0.5f + ( (viewport.UpperLeftCorner.Y + viewport.LowerRightCorner.Y ) * 0.5f ); 1922 1923 makeIdentity(); 1924 M[12] = (T)dx; 1925 M[13] = (T)dy; 1926 return setScale(core::vector3d<T>((T)scaleX, (T)scaleY, (T)zScale)); 1927 } 1928 1929 //! Builds a matrix that rotates from one vector to another 1930 /** \param from: vector to rotate from 1931 \param to: vector to rotate to 1932 1933 http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/index.htm 1934 */ 1935 template <class T> buildRotateFromTo(const core::vector3df & from,const core::vector3df & to)1936 inline CMatrix4<T>& CMatrix4<T>::buildRotateFromTo(const core::vector3df& from, const core::vector3df& to) 1937 { 1938 // unit vectors 1939 core::vector3df f(from); 1940 core::vector3df t(to); 1941 f.normalize(); 1942 t.normalize(); 1943 1944 // axis multiplication by sin 1945 core::vector3df vs(t.crossProduct(f)); 1946 1947 // axis of rotation 1948 core::vector3df v(vs); 1949 v.normalize(); 1950 1951 // cosinus angle 1952 T ca = f.dotProduct(t); 1953 1954 core::vector3df vt(v * (1 - ca)); 1955 1956 M[0] = vt.X * v.X + ca; 1957 M[5] = vt.Y * v.Y + ca; 1958 M[10] = vt.Z * v.Z + ca; 1959 1960 vt.X *= v.Y; 1961 vt.Z *= v.X; 1962 vt.Y *= v.Z; 1963 1964 M[1] = vt.X - vs.Z; 1965 M[2] = vt.Z + vs.Y; 1966 M[3] = 0; 1967 1968 M[4] = vt.X + vs.Z; 1969 M[6] = vt.Y - vs.X; 1970 M[7] = 0; 1971 1972 M[8] = vt.Z - vs.Y; 1973 M[9] = vt.Y + vs.X; 1974 M[11] = 0; 1975 1976 M[12] = 0; 1977 M[13] = 0; 1978 M[14] = 0; 1979 M[15] = 1; 1980 1981 return *this; 1982 } 1983 1984 //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis 1985 /** \param camPos: viewer position in world coord 1986 \param center: object position in world-coord, rotation pivot 1987 \param translation: object final translation from center 1988 \param axis: axis to rotate about 1989 \param from: source vector to rotate from 1990 */ 1991 template <class T> buildAxisAlignedBillboard(const core::vector3df & camPos,const core::vector3df & center,const core::vector3df & translation,const core::vector3df & axis,const core::vector3df & from)1992 inline void CMatrix4<T>::buildAxisAlignedBillboard( 1993 const core::vector3df& camPos, 1994 const core::vector3df& center, 1995 const core::vector3df& translation, 1996 const core::vector3df& axis, 1997 const core::vector3df& from) 1998 { 1999 // axis of rotation 2000 core::vector3df up = axis; 2001 up.normalize(); 2002 const core::vector3df forward = (camPos - center).normalize(); 2003 const core::vector3df right = up.crossProduct(forward).normalize(); 2004 2005 // correct look vector 2006 const core::vector3df look = right.crossProduct(up); 2007 2008 // rotate from to 2009 // axis multiplication by sin 2010 const core::vector3df vs = look.crossProduct(from); 2011 2012 // cosinus angle 2013 const f32 ca = from.dotProduct(look); 2014 2015 core::vector3df vt(up * (1.f - ca)); 2016 2017 M[0] = static_cast<T>(vt.X * up.X + ca); 2018 M[5] = static_cast<T>(vt.Y * up.Y + ca); 2019 M[10] = static_cast<T>(vt.Z * up.Z + ca); 2020 2021 vt.X *= up.Y; 2022 vt.Z *= up.X; 2023 vt.Y *= up.Z; 2024 2025 M[1] = static_cast<T>(vt.X - vs.Z); 2026 M[2] = static_cast<T>(vt.Z + vs.Y); 2027 M[3] = 0; 2028 2029 M[4] = static_cast<T>(vt.X + vs.Z); 2030 M[6] = static_cast<T>(vt.Y - vs.X); 2031 M[7] = 0; 2032 2033 M[8] = static_cast<T>(vt.Z - vs.Y); 2034 M[9] = static_cast<T>(vt.Y + vs.X); 2035 M[11] = 0; 2036 2037 setRotationCenter(center, translation); 2038 } 2039 2040 2041 //! Builds a combined matrix which translate to a center before rotation and translate afterwards 2042 template <class T> setRotationCenter(const core::vector3df & center,const core::vector3df & translation)2043 inline void CMatrix4<T>::setRotationCenter(const core::vector3df& center, const core::vector3df& translation) 2044 { 2045 M[12] = -M[0]*center.X - M[4]*center.Y - M[8]*center.Z + (center.X - translation.X ); 2046 M[13] = -M[1]*center.X - M[5]*center.Y - M[9]*center.Z + (center.Y - translation.Y ); 2047 M[14] = -M[2]*center.X - M[6]*center.Y - M[10]*center.Z + (center.Z - translation.Z ); 2048 M[15] = (T) 1.0; 2049 #if defined ( USE_MATRIX_TEST ) 2050 definitelyIdentityMatrix=false; 2051 #endif 2052 } 2053 2054 /*! 2055 Generate texture coordinates as linear functions so that: 2056 u = Ux*x + Uy*y + Uz*z + Uw 2057 v = Vx*x + Vy*y + Vz*z + Vw 2058 The matrix M for this case is: 2059 Ux Vx 0 0 2060 Uy Vy 0 0 2061 Uz Vz 0 0 2062 Uw Vw 0 0 2063 */ 2064 2065 2066 template <class T> buildTextureTransform(f32 rotateRad,const core::vector2df & rotatecenter,const core::vector2df & translate,const core::vector2df & scale)2067 inline CMatrix4<T>& CMatrix4<T>::buildTextureTransform( f32 rotateRad, 2068 const core::vector2df &rotatecenter, 2069 const core::vector2df &translate, 2070 const core::vector2df &scale) 2071 { 2072 const f32 c = cosf(rotateRad); 2073 const f32 s = sinf(rotateRad); 2074 2075 M[0] = (T)(c * scale.X); 2076 M[1] = (T)(s * scale.Y); 2077 M[2] = 0; 2078 M[3] = 0; 2079 2080 M[4] = (T)(-s * scale.X); 2081 M[5] = (T)(c * scale.Y); 2082 M[6] = 0; 2083 M[7] = 0; 2084 2085 M[8] = (T)(c * scale.X * rotatecenter.X + -s * rotatecenter.Y + translate.X); 2086 M[9] = (T)(s * scale.Y * rotatecenter.X + c * rotatecenter.Y + translate.Y); 2087 M[10] = 1; 2088 M[11] = 0; 2089 2090 M[12] = 0; 2091 M[13] = 0; 2092 M[14] = 0; 2093 M[15] = 1; 2094 #if defined ( USE_MATRIX_TEST ) 2095 definitelyIdentityMatrix=false; 2096 #endif 2097 return *this; 2098 } 2099 2100 2101 // rotate about z axis, center ( 0.5, 0.5 ) 2102 template <class T> setTextureRotationCenter(f32 rotateRad)2103 inline CMatrix4<T>& CMatrix4<T>::setTextureRotationCenter( f32 rotateRad ) 2104 { 2105 const f32 c = cosf(rotateRad); 2106 const f32 s = sinf(rotateRad); 2107 M[0] = (T)c; 2108 M[1] = (T)s; 2109 2110 M[4] = (T)-s; 2111 M[5] = (T)c; 2112 2113 M[8] = (T)(0.5f * ( s - c) + 0.5f); 2114 M[9] = (T)(-0.5f * ( s + c) + 0.5f); 2115 2116 #if defined ( USE_MATRIX_TEST ) 2117 definitelyIdentityMatrix = definitelyIdentityMatrix && (rotateRad==0.0f); 2118 #endif 2119 return *this; 2120 } 2121 2122 2123 template <class T> setTextureTranslate(f32 x,f32 y)2124 inline CMatrix4<T>& CMatrix4<T>::setTextureTranslate ( f32 x, f32 y ) 2125 { 2126 M[8] = (T)x; 2127 M[9] = (T)y; 2128 2129 #if defined ( USE_MATRIX_TEST ) 2130 definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f); 2131 #endif 2132 return *this; 2133 } 2134 2135 2136 template <class T> setTextureTranslateTransposed(f32 x,f32 y)2137 inline CMatrix4<T>& CMatrix4<T>::setTextureTranslateTransposed ( f32 x, f32 y ) 2138 { 2139 M[2] = (T)x; 2140 M[6] = (T)y; 2141 2142 #if defined ( USE_MATRIX_TEST ) 2143 definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f) ; 2144 #endif 2145 return *this; 2146 } 2147 2148 template <class T> setTextureScale(f32 sx,f32 sy)2149 inline CMatrix4<T>& CMatrix4<T>::setTextureScale ( f32 sx, f32 sy ) 2150 { 2151 M[0] = (T)sx; 2152 M[5] = (T)sy; 2153 #if defined ( USE_MATRIX_TEST ) 2154 definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f); 2155 #endif 2156 return *this; 2157 } 2158 2159 2160 template <class T> setTextureScaleCenter(f32 sx,f32 sy)2161 inline CMatrix4<T>& CMatrix4<T>::setTextureScaleCenter( f32 sx, f32 sy ) 2162 { 2163 M[0] = (T)sx; 2164 M[5] = (T)sy; 2165 M[8] = (T)(0.5f - 0.5f * sx); 2166 M[9] = (T)(0.5f - 0.5f * sy); 2167 2168 #if defined ( USE_MATRIX_TEST ) 2169 definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f); 2170 #endif 2171 return *this; 2172 } 2173 2174 2175 // sets all matrix data members at once 2176 template <class T> setM(const T * data)2177 inline CMatrix4<T>& CMatrix4<T>::setM(const T* data) 2178 { 2179 memcpy(M,data, 16*sizeof(T)); 2180 2181 #if defined ( USE_MATRIX_TEST ) 2182 definitelyIdentityMatrix=false; 2183 #endif 2184 return *this; 2185 } 2186 2187 2188 // sets if the matrix is definitely identity matrix 2189 template <class T> setDefinitelyIdentityMatrix(bool isDefinitelyIdentityMatrix)2190 inline void CMatrix4<T>::setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix) 2191 { 2192 #if defined ( USE_MATRIX_TEST ) 2193 definitelyIdentityMatrix = isDefinitelyIdentityMatrix; 2194 #endif 2195 } 2196 2197 2198 // gets if the matrix is definitely identity matrix 2199 template <class T> getDefinitelyIdentityMatrix()2200 inline bool CMatrix4<T>::getDefinitelyIdentityMatrix() const 2201 { 2202 #if defined ( USE_MATRIX_TEST ) 2203 return definitelyIdentityMatrix; 2204 #else 2205 return false; 2206 #endif 2207 } 2208 2209 2210 //! Compare two matrices using the equal method 2211 template <class T> equals(const core::CMatrix4<T> & other,const T tolerance)2212 inline bool CMatrix4<T>::equals(const core::CMatrix4<T>& other, const T tolerance) const 2213 { 2214 #if defined ( USE_MATRIX_TEST ) 2215 if (definitelyIdentityMatrix && other.definitelyIdentityMatrix) 2216 return true; 2217 #endif 2218 for (s32 i = 0; i < 16; ++i) 2219 if (!core::equals(M[i],other.M[i], tolerance)) 2220 return false; 2221 2222 return true; 2223 } 2224 2225 2226 // Multiply by scalar. 2227 template <class T> 2228 inline CMatrix4<T> operator*(const T scalar, const CMatrix4<T>& mat) 2229 { 2230 return mat*scalar; 2231 } 2232 2233 2234 //! Typedef for f32 matrix 2235 typedef CMatrix4<f32> matrix4; 2236 2237 //! global const identity matrix 2238 IRRLICHT_API extern const matrix4 IdentityMatrix; 2239 2240 } // end namespace core 2241 } // end namespace irr 2242 2243 #endif 2244 2245