1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "nel/misc/matrix.h"
23 #include "nel/misc/plane.h"
24 #include "nel/misc/debug.h"
37 // ======================================================================================================
38 const CMatrix
CMatrix::Identity
;
41 // ======================================================================================================
42 // ======================================================================================================
43 // ======================================================================================================
49 #define MAT_SCALEUNI 4
50 #define MAT_SCALEANY 8
52 // Validity bits. These means that the part may be yet identity, but is valid in the floats.
53 // NB: MAT_VALIDTRANS no more used for faster Pos access
54 #define MAT_VALIDROT 64
55 #define MAT_VALIDPROJ 128
56 #define MAT_VALIDALL (MAT_VALIDROT | MAT_VALIDPROJ)
57 // The identity is nothing.
58 #define MAT_IDENTITY 0
82 // ======================================================================================================
83 // ======================================================================================================
84 // ======================================================================================================
88 // ======================================================================================================
89 bool CMatrix::hasScalePart() const
91 return (StateBit
&(MAT_SCALEUNI
|MAT_SCALEANY
))!=0;
93 bool CMatrix::hasProjectionPart() const
95 return (StateBit
&MAT_PROJ
)!=0;
99 bool CMatrix::hasScaleUniform() const
101 return (StateBit
& (MAT_SCALEUNI
|MAT_SCALEANY
))== MAT_SCALEUNI
;
103 float CMatrix::getScaleUniform() const
105 if(hasScaleUniform())
113 // ======================================================================================================
114 inline bool CMatrix::hasRot() const
116 return (StateBit
&(MAT_ROT
|MAT_SCALEUNI
|MAT_SCALEANY
))!=0;
118 inline bool CMatrix::hasTrans() const
120 return (StateBit
&MAT_TRANS
)!=0;
122 inline bool CMatrix::hasProj() const
124 return (StateBit
&MAT_PROJ
)!=0;
126 inline bool CMatrix::hasAll() const
128 return (hasRot() && hasTrans() && hasProj());
132 inline void CMatrix::testExpandRot() const
136 if(!(StateBit
&MAT_VALIDROT
))
138 CMatrix
*self
= const_cast<CMatrix
*>(this);
139 self
->StateBit
|=MAT_VALIDROT
;
140 self
->a11
= 1; self
->a12
=0; self
->a13
=0;
141 self
->a21
= 0; self
->a22
=1; self
->a23
=0;
142 self
->a31
= 0; self
->a32
=0; self
->a33
=1;
147 inline void CMatrix::testExpandProj() const
151 if(!(StateBit
&MAT_VALIDPROJ
))
153 CMatrix
*self
= const_cast<CMatrix
*>(this);
154 self
->StateBit
|=MAT_VALIDPROJ
;
155 self
->a41
=0; self
->a42
=0; self
->a43
=0; self
->a44
=1;
160 // ======================================================================================================
161 CMatrix::CMatrix(const CMatrix
&m
)
165 // ======================================================================================================
166 CMatrix
&CMatrix::operator=(const CMatrix
&m
)
168 StateBit
= m
.StateBit
& ~MAT_VALIDALL
;
171 memcpy(M
, m
.M
, 16*sizeof(float));
178 memcpy(&a11
, &m
.a11
, 3*sizeof(float));
179 memcpy(&a12
, &m
.a12
, 3*sizeof(float));
180 memcpy(&a13
, &m
.a13
, 3*sizeof(float));
190 // Must always copy Trans part.
191 memcpy(&a14
, &m
.a14
, 3*sizeof(float));
197 // ======================================================================================================
198 void CMatrix::identity()
200 StateBit
= MAT_IDENTITY
;
201 // Reset just Pos because must always be valid for faster getPos()
203 // For optimisation it would be useful to keep MAT_VALID states.
204 // But this slows identity(), and this may not be interesting...
206 // ======================================================================================================
207 void CMatrix::setRot(const CVector
&i
, const CVector
&j
, const CVector
&k
, bool hintNoScale
)
209 StateBit
|= MAT_ROT
| MAT_SCALEANY
;
211 StateBit
&= ~(MAT_SCALEANY
|MAT_SCALEUNI
);
212 a11
= i
.x
; a12
= j
.x
; a13
= k
.x
;
213 a21
= i
.y
; a22
= j
.y
; a23
= k
.y
;
214 a31
= i
.z
; a32
= j
.z
; a33
= k
.z
;
217 // ======================================================================================================
218 void CMatrix::setRot(const float m33
[9], bool hintNoScale
)
220 StateBit
|= MAT_ROT
| MAT_SCALEANY
;
222 StateBit
&= ~(MAT_SCALEANY
|MAT_SCALEUNI
);
223 a11
= m33
[0]; a12
= m33
[3]; a13
= m33
[6];
224 a21
= m33
[1]; a22
= m33
[4]; a23
= m33
[7];
225 a31
= m33
[2]; a32
= m33
[5]; a33
= m33
[8];
228 // ======================================================================================================
229 void CMatrix::setRot(const CVector
&v
, TRotOrder ro
)
240 // ======================================================================================================
241 void CMatrix::setRot(const CMatrix
&matrix
)
243 // copy rotpart statebit from other.
244 StateBit
&= ~(MAT_ROT
| MAT_SCALEUNI
| MAT_SCALEANY
);
245 StateBit
|= matrix
.StateBit
& (MAT_ROT
| MAT_SCALEUNI
| MAT_SCALEANY
);
249 a11
= matrix
.a11
; a12
= matrix
.a12
; a13
= matrix
.a13
;
250 a21
= matrix
.a21
; a22
= matrix
.a22
; a23
= matrix
.a23
;
251 a31
= matrix
.a31
; a32
= matrix
.a32
; a33
= matrix
.a33
;
252 // if has scale uniform, copy from matrix.
253 if(hasScaleUniform())
254 Scale33
= matrix
.Scale33
;
258 // we are rot identity, with undefined values.
259 StateBit
&= ~MAT_VALIDROT
;
264 // ======================================================================================================
265 void CMatrix::setPos(const CVector
&v
)
270 if(a14
!=0 || a24
!=0 || a34
!=0)
271 StateBit
|= MAT_TRANS
;
273 // The trans is identity
274 StateBit
&= ~MAT_TRANS
;
276 // ======================================================================================================
277 void CMatrix::movePos(const CVector
&v
)
282 if(a14
!=0 || a24
!=0 || a34
!=0)
283 StateBit
|= MAT_TRANS
;
285 // The trans is identity
286 StateBit
&= ~MAT_TRANS
;
288 // ======================================================================================================
289 void CMatrix::setProj(const float proj
[4])
297 if(a41
!=0 || a42
!=0 || a43
!=0 || a44
!=1)
301 // The proj is identity, and is correcly setup!
302 StateBit
&= ~MAT_PROJ
;
303 StateBit
|= MAT_VALIDPROJ
;
306 // ======================================================================================================
307 void CMatrix::resetProj()
313 // The proj is identity, and is correcly setup!
314 StateBit
&= ~MAT_PROJ
;
315 StateBit
|= MAT_VALIDPROJ
;
317 // ======================================================================================================
318 void CMatrix::set(const float m44
[16])
320 StateBit
= MAT_IDENTITY
;
322 StateBit
|= MAT_ROT
| MAT_SCALEANY
;
323 memcpy(M
, m44
, 16*sizeof(float));
326 // Check Trans state.
327 if(a14
!=0 || a24
!=0 || a34
!=0)
328 StateBit
|= MAT_TRANS
;
330 // The trans is identity
331 StateBit
&= ~MAT_TRANS
;
334 if(a41
!=0 || a42
!=0 || a43
!=0 || a44
!=1)
338 // The proj is identity, and is correcly setup!
339 StateBit
&= ~MAT_PROJ
;
340 StateBit
|= MAT_VALIDPROJ
;
345 // ======================================================================================================
346 // ======================================================================================================
347 // ======================================================================================================
350 // ======================================================================================================
351 void CMatrix::getRot(CVector
&i
, CVector
&j
, CVector
&k
) const
355 i
.set(a11
, a21
, a31
);
356 j
.set(a12
, a22
, a32
);
357 k
.set(a13
, a23
, a33
);
366 // ======================================================================================================
367 void CMatrix::getRot(float m33
[9]) const
398 // ======================================================================================================
399 void CMatrix::getProj(float proj
[4]) const
416 // ======================================================================================================
417 CVector
CMatrix::getI() const
420 return CVector(a11
, a21
, a31
);
422 return CVector(1, 0, 0);
424 // ======================================================================================================
425 CVector
CMatrix::getJ() const
428 return CVector(a12
, a22
, a32
);
430 return CVector(0, 1, 0);
432 // ======================================================================================================
433 CVector
CMatrix::getK() const
436 return CVector(a13
, a23
, a33
);
438 return CVector(0, 0, 1);
440 // ======================================================================================================
441 void CMatrix::get(float m44
[16]) const
445 memcpy(m44
, M
, 16*sizeof(float));
447 // ======================================================================================================
448 const float *CMatrix::get() const
454 /*// ======================================================================================================
455 CVector CMatrix::toEuler(TRotOrder ro) const
461 // ======================================================================================================
462 // ======================================================================================================
463 // ======================================================================================================
466 // ======================================================================================================
467 void CMatrix::translate(const CVector
&v
)
472 a14
+= a11
*v
.x
+ a12
*v
.y
+ a13
*v
.z
;
473 a24
+= a21
*v
.x
+ a22
*v
.y
+ a23
*v
.z
;
474 a34
+= a31
*v
.x
+ a32
*v
.y
+ a33
*v
.z
;
485 a44
+= a41
*v
.x
+ a42
*v
.y
+ a43
*v
.z
;
488 if(a14
!=0 || a24
!=0 || a34
!=0)
489 StateBit
|= MAT_TRANS
;
491 // The trans is identity, and is correcly setup!
492 StateBit
&= ~MAT_TRANS
;
494 // ======================================================================================================
495 void CMatrix::rotateX(float a
)
507 float b12
=a12
, b22
=a22
, b32
=a32
;
508 float b13
=a13
, b23
=a23
, b33
=a33
;
509 a12
= (float)(b12
*ca
+ b13
*sa
);
510 a22
= (float)(b22
*ca
+ b23
*sa
);
511 a32
= (float)(b32
*ca
+ b33
*sa
);
512 a13
= (float)(b13
*ca
- b12
*sa
);
513 a23
= (float)(b23
*ca
- b22
*sa
);
514 a33
= (float)(b33
*ca
- b32
*sa
);
519 a12
= 0.0f
; a22
= (float)ca
; a32
= (float)sa
;
520 a13
= 0.0f
; a23
= (float)-sa
; a33
= (float)ca
;
526 float b42
=a42
, b43
=a43
;
527 a42
= (float)(b42
*ca
+ b43
*sa
);
528 a43
= (float)(b43
*ca
- b42
*sa
);
534 // ======================================================================================================
535 void CMatrix::rotateY(float a
)
547 float b11
=a11
, b21
=a21
, b31
=a31
;
548 float b13
=a13
, b23
=a23
, b33
=a33
;
549 a11
= (float)(b11
*ca
- b13
*sa
);
550 a21
= (float)(b21
*ca
- b23
*sa
);
551 a31
= (float)(b31
*ca
- b33
*sa
);
552 a13
= (float)(b13
*ca
+ b11
*sa
);
553 a23
= (float)(b23
*ca
+ b21
*sa
);
554 a33
= (float)(b33
*ca
+ b31
*sa
);
559 a11
= (float)ca
; a21
=0.0f
; a31
= (float)-sa
;
560 a13
= (float)sa
; a23
=0.0f
; a33
= (float)ca
;
566 float b41
=a41
, b43
=a43
;
567 a41
= (float)(b41
*ca
- b43
*sa
);
568 a43
= (float)(b43
*ca
+ b41
*sa
);
574 // ======================================================================================================
575 void CMatrix::rotateZ(float a
)
585 if( StateBit
& (MAT_ROT
|MAT_SCALEUNI
|MAT_SCALEANY
) )
587 float b11
=a11
, b21
=a21
, b31
=a31
;
588 float b12
=a12
, b22
=a22
, b32
=a32
;
589 a11
= (float)(b11
*ca
+ b12
*sa
);
590 a21
= (float)(b21
*ca
+ b22
*sa
);
591 a31
= (float)(b31
*ca
+ b32
*sa
);
592 a12
= (float)(b12
*ca
- b11
*sa
);
593 a22
= (float)(b22
*ca
- b21
*sa
);
594 a32
= (float)(b32
*ca
- b31
*sa
);
599 a11
= (float)ca
; a21
= (float)sa
; a31
=0.0f
;
600 a12
= (float)-sa
; a22
= (float)ca
; a32
=0.0f
;
606 float b41
=a41
, b42
=a42
;
607 a41
= (float)(b41
*ca
+ b42
*sa
);
608 a42
= (float)(b42
*ca
- b41
*sa
);
614 // ======================================================================================================
615 void CMatrix::rotate(const CVector
&v
, TRotOrder ro
)
621 case XYZ
: rot
.rotateX(v
.x
); rot
.rotateY(v
.y
); rot
.rotateZ(v
.z
); break;
622 case XZY
: rot
.rotateX(v
.x
); rot
.rotateZ(v
.z
); rot
.rotateY(v
.y
); break;
623 case YXZ
: rot
.rotateY(v
.y
); rot
.rotateX(v
.x
); rot
.rotateZ(v
.z
); break;
624 case YZX
: rot
.rotateY(v
.y
); rot
.rotateZ(v
.z
); rot
.rotateX(v
.x
); break;
625 case ZXY
: rot
.rotateZ(v
.z
); rot
.rotateX(v
.x
); rot
.rotateY(v
.y
); break;
626 case ZYX
: rot
.rotateZ(v
.z
); rot
.rotateY(v
.y
); rot
.rotateX(v
.x
); break;
632 // ======================================================================================================
633 void CMatrix::rotate(const CQuat
&quat
)
640 // ======================================================================================================
641 void CMatrix::scale(float f
)
645 if(StateBit
& MAT_SCALEANY
)
647 scale(CVector(f
,f
,f
));
652 StateBit
|= MAT_SCALEUNI
;
654 a11
*= f
; a12
*=f
; a13
*=f
;
655 a21
*= f
; a22
*=f
; a23
*=f
;
656 a31
*= f
; a32
*=f
; a33
*=f
;
661 a41
*=f
; a42
*=f
; a43
*=f
;
665 // ======================================================================================================
666 void CMatrix::scale(const CVector
&v
)
669 if( v
==CVector(1,1,1) ) return;
670 if( !(StateBit
& MAT_SCALEANY
) && v
.x
==v
.y
&& v
.x
==v
.z
)
677 StateBit
|=MAT_SCALEANY
;
678 a11
*= v
.x
; a12
*=v
.y
; a13
*=v
.z
;
679 a21
*= v
.x
; a22
*=v
.y
; a23
*=v
.z
;
680 a31
*= v
.x
; a32
*=v
.y
; a33
*=v
.z
;
693 // ======================================================================================================
694 // ======================================================================================================
695 // ======================================================================================================
698 // ***************************************************************************
699 void CMatrix::setMulMatrixNoProj(const CMatrix
&m1
, const CMatrix
&m2
)
702 For a fast MulMatrix, it appears to be better to not take State bits into account (no test/if() overhead)
703 Just do heavy mul all the time (common case, and not so slow)
706 // Ensure the src matrix have correct values in rot part
711 a11
= m1
.a11
*m2
.a11
+ m1
.a12
*m2
.a21
+ m1
.a13
*m2
.a31
;
712 a12
= m1
.a11
*m2
.a12
+ m1
.a12
*m2
.a22
+ m1
.a13
*m2
.a32
;
713 a13
= m1
.a11
*m2
.a13
+ m1
.a12
*m2
.a23
+ m1
.a13
*m2
.a33
;
715 a21
= m1
.a21
*m2
.a11
+ m1
.a22
*m2
.a21
+ m1
.a23
*m2
.a31
;
716 a22
= m1
.a21
*m2
.a12
+ m1
.a22
*m2
.a22
+ m1
.a23
*m2
.a32
;
717 a23
= m1
.a21
*m2
.a13
+ m1
.a22
*m2
.a23
+ m1
.a23
*m2
.a33
;
719 a31
= m1
.a31
*m2
.a11
+ m1
.a32
*m2
.a21
+ m1
.a33
*m2
.a31
;
720 a32
= m1
.a31
*m2
.a12
+ m1
.a32
*m2
.a22
+ m1
.a33
*m2
.a32
;
721 a33
= m1
.a31
*m2
.a13
+ m1
.a32
*m2
.a23
+ m1
.a33
*m2
.a33
;
724 a14
= m1
.a11
*m2
.a14
+ m1
.a12
*m2
.a24
+ m1
.a13
*m2
.a34
+ m1
.a14
;
725 a24
= m1
.a21
*m2
.a14
+ m1
.a22
*m2
.a24
+ m1
.a23
*m2
.a34
+ m1
.a24
;
726 a34
= m1
.a31
*m2
.a14
+ m1
.a32
*m2
.a24
+ m1
.a33
*m2
.a34
+ m1
.a34
;
728 // Setup no proj at all, and force valid rot (still may be identity, but 0/1 are filled)
729 StateBit
= (m1
.StateBit
| m2
.StateBit
| MAT_VALIDROT
) & ~(MAT_PROJ
|MAT_VALIDPROJ
);
731 // Modify Scale. This test is important because Scale33 may be a #NAN if SCALEANY => avoid very slow mul.
732 if( hasScaleUniform() )
733 Scale33
= m1
.Scale33
*m2
.Scale33
;
740 // ***************************************************************************
741 void CMatrix::setMulMatrix(const CMatrix
&m1
, const CMatrix
&m2
)
745 StateBit
= m1
.StateBit
| m2
.StateBit
;
746 StateBit
&= ~MAT_VALIDALL
;
750 bool M1Identity
= ! m1
.hasRot();
751 bool M2Identity
= ! m2
.hasRot();
752 bool M1ScaleOnly
= ! (m1
.StateBit
& MAT_ROT
);
753 bool M2ScaleOnly
= ! (m2
.StateBit
& MAT_ROT
);
754 bool MGeneralCase
= !M1Identity
&& !M2Identity
&& !M1ScaleOnly
&& !M2ScaleOnly
;
757 // Manage the most common general case first (optim the if ): blending of two rotations.
760 a11
= m1
.a11
*m2
.a11
+ m1
.a12
*m2
.a21
+ m1
.a13
*m2
.a31
;
761 a12
= m1
.a11
*m2
.a12
+ m1
.a12
*m2
.a22
+ m1
.a13
*m2
.a32
;
762 a13
= m1
.a11
*m2
.a13
+ m1
.a12
*m2
.a23
+ m1
.a13
*m2
.a33
;
764 a21
= m1
.a21
*m2
.a11
+ m1
.a22
*m2
.a21
+ m1
.a23
*m2
.a31
;
765 a22
= m1
.a21
*m2
.a12
+ m1
.a22
*m2
.a22
+ m1
.a23
*m2
.a32
;
766 a23
= m1
.a21
*m2
.a13
+ m1
.a22
*m2
.a23
+ m1
.a23
*m2
.a33
;
768 a31
= m1
.a31
*m2
.a11
+ m1
.a32
*m2
.a21
+ m1
.a33
*m2
.a31
;
769 a32
= m1
.a31
*m2
.a12
+ m1
.a32
*m2
.a22
+ m1
.a33
*m2
.a32
;
770 a33
= m1
.a31
*m2
.a13
+ m1
.a32
*m2
.a23
+ m1
.a33
*m2
.a33
;
772 // If one of the 3x3 matrix is an identity, just do a copy
773 else if( M1Identity
|| M2Identity
)
775 // If both identity, then me too.
776 if( M1Identity
&& M2Identity
)
778 // just expand me (important because validated below)
783 // Copy the non identity matrix.
784 const CMatrix
*c
= M2Identity
? &m1
: &m2
;
785 a11
= c
->a11
; a12
= c
->a12
; a13
= c
->a13
;
786 a21
= c
->a21
; a22
= c
->a22
; a23
= c
->a23
;
787 a31
= c
->a31
; a32
= c
->a32
; a33
= c
->a33
;
790 // If two 3x3 matrix are just scaleOnly matrix, do a scaleFact.
791 else if( M1ScaleOnly
&& M2ScaleOnly
)
793 // same process for scaleUni or scaleAny.
794 a11
= m1
.a11
*m2
.a11
; a12
= 0; a13
= 0;
795 a21
= 0; a22
= m1
.a22
*m2
.a22
; a23
= 0;
796 a31
= 0; a32
= 0; a33
= m1
.a33
*m2
.a33
;
798 // If one of the matrix is a scaleOnly matrix, do a scale*Rot.
799 else if( M1ScaleOnly
&& !M2ScaleOnly
)
801 a11
= m1
.a11
*m2
.a11
; a12
= m1
.a11
*m2
.a12
; a13
= m1
.a11
*m2
.a13
;
802 a21
= m1
.a22
*m2
.a21
; a22
= m1
.a22
*m2
.a22
; a23
= m1
.a22
*m2
.a23
;
803 a31
= m1
.a33
*m2
.a31
; a32
= m1
.a33
*m2
.a32
; a33
= m1
.a33
*m2
.a33
;
807 // This must be this case
808 nlassert(!M1ScaleOnly
&& M2ScaleOnly
);
809 a11
= m1
.a11
*m2
.a11
; a12
= m1
.a12
*m2
.a22
; a13
= m1
.a13
*m2
.a33
;
810 a21
= m1
.a21
*m2
.a11
; a22
= m1
.a22
*m2
.a22
; a23
= m1
.a23
*m2
.a33
;
811 a31
= m1
.a31
*m2
.a11
; a32
= m1
.a32
*m2
.a22
; a33
= m1
.a33
*m2
.a33
;
814 // If M1 has translate and M2 has projective, rotation is modified.
815 if( m1
.hasTrans() && m2
.hasProj())
817 StateBit
|= MAT_ROT
|MAT_SCALEANY
;
833 if( (StateBit
& MAT_SCALEUNI
) && !(StateBit
& MAT_SCALEANY
) )
835 // Must have correct Scale33
838 Scale33
= m1
.Scale33
*m2
.Scale33
;
843 // In every case, I am valid now!
844 StateBit
|=MAT_VALIDROT
;
849 if( StateBit
& MAT_TRANS
)
858 else if (M1ScaleOnly
)
866 a14
= m1
.a11
*m2
.a14
+ m1
.a12
*m2
.a24
+ m1
.a13
*m2
.a34
;
867 a24
= m1
.a21
*m2
.a14
+ m1
.a22
*m2
.a24
+ m1
.a23
*m2
.a34
;
868 a34
= m1
.a31
*m2
.a14
+ m1
.a32
*m2
.a24
+ m1
.a33
*m2
.a34
;
871 if(m1
.StateBit
& MAT_TRANS
)
873 if(m2
.StateBit
& MAT_PROJ
)
891 if( StateBit
& MAT_PROJ
)
893 // optimize nothing... (projection matrix are rare).
898 a41
= m1
.a41
*m2
.a11
+ m1
.a42
*m2
.a21
+ m1
.a43
*m2
.a31
+ m1
.a44
*m2
.a41
;
899 a42
= m1
.a41
*m2
.a12
+ m1
.a42
*m2
.a22
+ m1
.a43
*m2
.a32
+ m1
.a44
*m2
.a42
;
900 a43
= m1
.a41
*m2
.a13
+ m1
.a42
*m2
.a23
+ m1
.a43
*m2
.a33
+ m1
.a44
*m2
.a43
;
901 a44
= m1
.a41
*m2
.a14
+ m1
.a42
*m2
.a24
+ m1
.a43
*m2
.a34
+ m1
.a44
*m2
.a44
;
902 // The proj is valid now
903 StateBit
|= MAT_VALIDPROJ
;
907 // Don't copy proj part, and leave MAT_VALIDPROJ not set
910 // ======================================================================================================
911 void CMatrix::invert()
918 // ======================================================================================================
919 void CMatrix::transpose3x3()
927 // Scale mode (none, uni, or any) is conserved. Scale33 too...
931 // ======================================================================================================
932 void CMatrix::transpose()
935 if(hasTrans() || hasProj())
937 // if necessary, Get valid 0 on proj part.
943 // swap StateBit flags, if not both were sets...
944 if(!hasTrans() || !hasProj())
946 // swap StateBit flags (swap trans with proj).
949 StateBit
&= ~MAT_TRANS
;
954 StateBit
&= ~MAT_PROJ
;
955 StateBit
|= MAT_TRANS
;
958 // reset validity. NB, maybe not useful, but simpler, and bugfree.
959 StateBit
&= ~(MAT_VALIDPROJ
);
961 // NB: if no Trans or no Proj, do nothing, so don't need to modify VALIDTRANS and VALIDPROJ too.
965 // ======================================================================================================
966 bool CMatrix::fastInvert33(CMatrix
&ret
) const
968 // Fast invert of 3x3 rot matrix.
969 // Work if no scale and if MAT_SCALEUNI. doesn't work if MAT_SCALEANY.
971 if(StateBit
& MAT_SCALEUNI
)
973 if (Scale33
== 0.f
) return false;
974 double s
,S
; // important for precision.
975 // Must divide the matrix by 1/Scale 2 times, to set unit, and to have a Scale=1/Scale.
977 ret
.Scale33
= (float)S
;
979 // The matrix is a base, so just transpose it.
980 ret
.a11
= (float)(a11
*s
); ret
.a12
= (float)(a21
*s
); ret
.a13
= (float)(a31
*s
);
981 ret
.a21
= (float)(a12
*s
); ret
.a22
= (float)(a22
*s
); ret
.a23
= (float)(a32
*s
);
982 ret
.a31
= (float)(a13
*s
); ret
.a32
= (float)(a23
*s
); ret
.a33
= (float)(a33
*s
);
987 // The matrix is a base, so just transpose it.
988 ret
.a11
= a11
; ret
.a12
= a21
; ret
.a13
=a31
;
989 ret
.a21
= a12
; ret
.a22
= a22
; ret
.a23
=a32
;
990 ret
.a31
= a13
; ret
.a32
= a23
; ret
.a33
=a33
;
993 // 15 cycles if no scale.
994 // 35 cycles if scale.
996 // ======================================================================================================
997 bool CMatrix::slowInvert33(CMatrix
&ret
) const
999 CVector invi
,invj
,invk
;
1006 // Compute cofactors (minors *(-1)^(i+j)).
1007 invi
.x
= j
.y
*k
.z
- k
.y
*j
.z
;
1008 invi
.y
= j
.z
*k
.x
- k
.z
*j
.x
;
1009 invi
.z
= j
.x
*k
.y
- k
.x
*j
.y
;
1010 invj
.x
= k
.y
*i
.z
- i
.y
*k
.z
;
1011 invj
.y
= k
.z
*i
.x
- i
.z
*k
.x
;
1012 invj
.z
= k
.x
*i
.y
- i
.x
*k
.y
;
1013 invk
.x
= i
.y
*j
.z
- j
.y
*i
.z
;
1014 invk
.y
= i
.z
*j
.x
- j
.z
*i
.x
;
1015 invk
.z
= i
.x
*j
.y
- j
.x
*i
.y
;
1016 // compute determinant.
1017 s
= invi
.x
*i
.x
+ invj
.x
*j
.x
+ invk
.x
*k
.x
;
1020 // Transpose the Comatrice, and divide by determinant.
1022 ret
.a11
= (float)(invi
.x
*s
); ret
.a12
= (float)(invi
.y
*s
); ret
.a13
= (float)(invi
.z
*s
);
1023 ret
.a21
= (float)(invj
.x
*s
); ret
.a22
= (float)(invj
.y
*s
); ret
.a23
= (float)(invj
.z
*s
);
1024 ret
.a31
= (float)(invk
.x
*s
); ret
.a32
= (float)(invk
.y
*s
); ret
.a33
= (float)(invk
.z
*s
);
1027 // Roundly 82 cycles. (1Div=10 cycles).
1029 // ======================================================================================================
1030 bool CMatrix::slowInvert44(CMatrix
&ret
) const
1035 // Compute Cofactors
1036 //==================
1041 sint l1
=0,l2
=0,l3
=0;
1043 getCofactIndex(i
,l1
,l2
,l3
);
1044 getCofactIndex(j
,c1
,c2
,c3
);
1047 ret
.mat(i
,j
)+= mat(l1
,c1
) * mat(l2
,c2
) * mat(l3
,c3
);
1048 ret
.mat(i
,j
)+= mat(l1
,c2
) * mat(l2
,c3
) * mat(l3
,c1
);
1049 ret
.mat(i
,j
)+= mat(l1
,c3
) * mat(l2
,c1
) * mat(l3
,c2
);
1051 ret
.mat(i
,j
)-= mat(l1
,c1
) * mat(l2
,c3
) * mat(l3
,c2
);
1052 ret
.mat(i
,j
)-= mat(l1
,c2
) * mat(l2
,c1
) * mat(l3
,c3
);
1053 ret
.mat(i
,j
)-= mat(l1
,c3
) * mat(l2
,c2
) * mat(l3
,c1
);
1056 ret
.mat(i
,j
)=-ret
.mat(i
,j
);
1060 // Compute determinant.
1061 //=====================
1062 s
= ret
.mat(0,0) * mat(0,0) + ret
.mat(0,1) * mat(0,1) + ret
.mat(0,2) * mat(0,2) + ret
.mat(0,3) * mat(0,3);
1066 // Divide by determinant.
1067 //=======================
1072 ret
.mat(i
,j
)= (float)(ret
.mat(i
,j
)*s
);
1075 // Transpose the comatrice.
1076 //=========================
1081 swap(ret
.mat(i
,j
), ret
.mat(j
,i
));
1087 // ======================================================================================================
1088 CMatrix
CMatrix::inverted() const
1096 // Do a conventionnal 44 inversion.
1097 //=================================
1098 if(StateBit
& MAT_PROJ
)
1100 if(!slowInvert44(ret
))
1106 // Well, don't know what happens to matrix, so set all StateBit :).
1107 ret
.StateBit
= MAT_TRANS
|MAT_ROT
|MAT_SCALEANY
|MAT_PROJ
;
1109 // Check Trans state.
1110 if(ret
.a14
!=0 || ret
.a24
!=0 || ret
.a34
!=0)
1111 ret
.StateBit
|= MAT_TRANS
;
1113 ret
.StateBit
&= ~MAT_TRANS
;
1115 // Check Proj state.
1116 if(ret
.a41
!=0 || ret
.a42
!=0 || ret
.a43
!=0 || ret
.a44
!=1)
1117 ret
.StateBit
|= MAT_PROJ
;
1119 ret
.StateBit
&= ~MAT_PROJ
;
1122 // Do a speed 34 inversion.
1123 //=========================
1126 // Invert the rotation part.
1127 if(StateBit
& MAT_SCALEANY
)
1129 if(!slowInvert33(ret
))
1137 if (!fastInvert33(ret
))
1143 // Scale33 is updated in fastInvert33().
1145 // Invert the translation part.
1146 if(StateBit
& MAT_TRANS
)
1148 // Invert the translation part.
1149 // This can only work if 4th line is 0 0 0 1.
1150 // formula: InvVp= InvVi*(-Vp.x) + InvVj*(-Vp.y) + InvVk*(-Vp.z)
1151 ret
.a14
= ret
.a11
*(-a14
) + ret
.a12
*(-a24
) + ret
.a13
*(-a34
);
1152 ret
.a24
= ret
.a21
*(-a14
) + ret
.a22
*(-a24
) + ret
.a23
*(-a34
);
1153 ret
.a34
= ret
.a31
*(-a14
) + ret
.a32
*(-a24
) + ret
.a33
*(-a34
);
1162 // The projection part is unmodified.
1163 ret
.a41
= 0; ret
.a42
= 0; ret
.a43
= 0; ret
.a44
= 1;
1165 // The matrix inverted keep the same state bits.
1166 ret
.StateBit
= StateBit
;
1172 // ======================================================================================================
1173 bool CMatrix::normalize(TRotOrder ro
)
1183 // Normalize with help of ro
1224 // Check, and set result.
1225 if( ti
.isNull() || tj
.isNull() || tk
.isNull() )
1227 a11
= ti
.x
; a12
= tj
.x
; a13
= tk
.x
;
1228 a21
= ti
.y
; a22
= tj
.y
; a23
= tk
.y
;
1229 a31
= ti
.z
; a32
= tj
.z
; a33
= tk
.z
;
1230 // Scale is reseted.
1231 StateBit
&= ~(MAT_SCALEUNI
|MAT_SCALEANY
);
1240 // ======================================================================================================
1241 // ======================================================================================================
1242 // ======================================================================================================
1245 // ======================================================================================================
1246 CVector
CMatrix::mulVector(const CVector
&v
) const
1253 ret
.x
= a11
*v
.x
+ a12
*v
.y
+ a13
*v
.z
;
1254 ret
.y
= a21
*v
.x
+ a22
*v
.y
+ a23
*v
.z
;
1255 ret
.z
= a31
*v
.x
+ a32
*v
.y
+ a33
*v
.z
;
1262 // ======================================================================================================
1263 CVector
CMatrix::mulPoint(const CVector
&v
) const
1270 ret
.x
= a11
*v
.x
+ a12
*v
.y
+ a13
*v
.z
;
1271 ret
.y
= a21
*v
.x
+ a22
*v
.y
+ a23
*v
.z
;
1272 ret
.z
= a31
*v
.x
+ a32
*v
.y
+ a33
*v
.z
;
1292 CVectorH
CMatrix::operator*(const CVectorH
& v
) const
1300 ret
.x
= a11
*v
.x
+ a12
*v
.y
+ a13
*v
.z
+ a14
*v
.w
;
1301 ret
.y
= a21
*v
.x
+ a22
*v
.y
+ a23
*v
.z
+ a24
*v
.w
;
1302 ret
.z
= a31
*v
.x
+ a32
*v
.y
+ a33
*v
.z
+ a34
*v
.w
;
1303 ret
.w
= a41
*v
.x
+ a42
*v
.y
+ a43
*v
.z
+ a44
*v
.w
;
1308 // ======================================================================================================
1309 CPlane
operator*(const CPlane
&p
, const CMatrix
&m
)
1316 if( m
.StateBit
& (MAT_ROT
|MAT_SCALEUNI
|MAT_SCALEANY
|MAT_PROJ
) )
1318 // Compose with translation too.
1319 ret
.a
= p
.a
*m
.a11
+ p
.b
*m
.a21
+ p
.c
*m
.a31
+ p
.d
*m
.a41
;
1320 ret
.b
= p
.a
*m
.a12
+ p
.b
*m
.a22
+ p
.c
*m
.a32
+ p
.d
*m
.a42
;
1321 ret
.c
= p
.a
*m
.a13
+ p
.b
*m
.a23
+ p
.c
*m
.a33
+ p
.d
*m
.a43
;
1322 ret
.d
= p
.a
*m
.a14
+ p
.b
*m
.a24
+ p
.c
*m
.a34
+ p
.d
*m
.a44
;
1325 else if( m
.StateBit
& MAT_TRANS
)
1328 // Compose just with a translation.
1332 ret
.d
= p
.a
*m
.a14
+ p
.b
*m
.a24
+ p
.c
*m
.a34
+ p
.d
*m
.a44
;
1340 // ======================================================================================================
1341 // ======================================================================================================
1342 // ======================================================================================================
1345 // ======================================================================================================
1346 void CMatrix::setRot(const CQuat
&quat
)
1348 // A quaternion do not have scale.
1349 StateBit
&= ~(MAT_ROT
| MAT_SCALEANY
|MAT_SCALEUNI
);
1351 if(quat
.isIdentity())
1353 a11
= 1; a12
= 0; a13
= 0;
1354 a21
= 0; a22
= 1; a23
= 0;
1355 a31
= 0; a32
= 0; a33
= 1;
1360 float wx
, wy
, wz
, xx
, yy
, yz
, xy
, xz
, zz
, x2
, y2
, z2
;
1362 // calculate coefficients
1363 x2
= quat
.x
+ quat
.x
; y2
= quat
.y
+ quat
.y
;
1364 z2
= quat
.z
+ quat
.z
;
1365 xx
= quat
.x
* x2
; xy
= quat
.x
* y2
; xz
= quat
.x
* z2
;
1366 yy
= quat
.y
* y2
; yz
= quat
.y
* z2
; zz
= quat
.z
* z2
;
1367 wx
= quat
.w
* x2
; wy
= quat
.w
* y2
; wz
= quat
.w
* z2
;
1369 a11
= 1.0f
- (yy
+ zz
);
1374 a22
= 1.0f
- (xx
+ zz
);
1379 a33
= 1.0f
- (xx
+ yy
);
1384 // ======================================================================================================
1385 void CMatrix::getRot(CQuat
&quat
) const
1387 const CMatrix
*pmat
= this;
1392 if(! (StateBit
& MAT_ROT
))
1394 quat
= CQuat::Identity
;
1398 // Must normalize the matrix??
1399 if(StateBit
& (MAT_SCALEUNI
| MAT_SCALEANY
) )
1402 MatNormed
.normalize(ZYX
);
1406 // Compute quaternion.
1409 tr
= pmat
->a11
+ pmat
->a22
+ pmat
->a33
;
1411 // check the diagonal
1414 s
= (float)sqrt (tr
+ 1.0f
);
1417 quat
.x
= (pmat
->a32
- pmat
->a23
) * s
;
1418 quat
.y
= (pmat
->a13
- pmat
->a31
) * s
;
1419 quat
.z
= (pmat
->a21
- pmat
->a12
) * s
;
1424 sint nxt
[3] = {1, 2, 0};
1426 // diagonal is negative
1428 if (pmat
->a22
> pmat
->a11
) i
= 1;
1429 if (pmat
->a33
> pmat
->mat(i
,i
) ) i
= 2;
1433 s
= (float) sqrt ( (pmat
->mat(i
,i
) - (pmat
->mat(j
,j
) + pmat
->mat(k
,k
)) ) + 1.0);
1437 if (s
!= 0.0f
) s
= 0.5f
/ s
;
1439 q
[j
] = (pmat
->mat(j
,i
) + pmat
->mat(i
,j
)) * s
;
1440 q
[k
] = (pmat
->mat(k
,i
) + pmat
->mat(i
,k
)) * s
;
1441 q
[3] = (pmat
->mat(k
,j
) - pmat
->mat(j
,k
)) * s
;
1452 // ======================================================================================================
1453 // ======================================================================================================
1454 // ======================================================================================================
1457 // ======================================================================================================
1458 inline void CMatrix::setScaleUni(float scale
)
1460 // A Scale matrix do not have rotation.
1461 StateBit
&= ~(MAT_ROT
| MAT_SCALEANY
| MAT_SCALEUNI
);
1462 StateBit
|= MAT_SCALEUNI
| MAT_VALIDROT
;
1464 a11
= scale
; a12
= 0; a13
= 0;
1465 a21
= 0; a22
= scale
; a23
= 0;
1466 a31
= 0; a32
= 0; a33
= scale
;
1469 // ======================================================================================================
1470 void CMatrix::setScale(float scale
)
1476 // ======================================================================================================
1477 void CMatrix::setScale(const CVector
&v
)
1479 // actually a scale uniform?
1480 if(v
.x
==v
.y
&& v
.x
==v
.z
)
1483 // A Scale matrix do not have rotation.
1484 StateBit
&= ~(MAT_ROT
| MAT_SCALEANY
| MAT_SCALEUNI
);
1485 StateBit
|= MAT_SCALEANY
| MAT_VALIDROT
;
1486 a11
= v
.x
; a12
= 0; a13
= 0;
1487 a21
= 0; a22
= v
.y
; a23
= 0;
1488 a31
= 0; a32
= 0; a33
= v
.z
;
1493 // ======================================================================================================
1494 // ======================================================================================================
1495 // ======================================================================================================
1498 // ======================================================================================================
1499 void CMatrix::serial(IStream
&f
)
1501 // Use versionning, maybe for futur improvement.
1502 (void)f
.serialVersion(0);
1507 // avoid serial of random data
1508 if(!f
.isReading() && !hasScaleUniform())
1517 f
.serial(a11
, a12
, a13
);
1518 f
.serial(a21
, a22
, a23
);
1519 f
.serial(a31
, a32
, a33
);
1523 f
.serial(a14
, a24
, a34
);
1525 else if(f
.isReading())
1527 // must reset because Pos must always be valid
1532 f
.serial(a41
, a42
, a43
, a44
);
1537 // ======================================================================================================
1538 void CMatrix::setArbitraryRotI(const CVector
&idir
)
1540 // avoid gimbal lock. if idir == nearly K, use another second lead vector
1541 if( fabs(idir
.z
)<0.9f
)
1542 setRot(idir
, CVector::J
, CVector::K
);
1544 setRot(idir
, CVector::J
, CVector::I
);
1545 normalize(CMatrix::XZY
);
1548 void CMatrix::setArbitraryRotJ(const CVector
&jdir
)
1550 // avoid gimbal lock. if jdir == nearly K, use another second lead vector
1551 if(fabs(jdir
.z
)<0.9f
)
1552 setRot(CVector::I
, jdir
, CVector::K
);
1554 setRot(CVector::I
, jdir
, CVector::J
);
1555 normalize(CMatrix::YZX
);
1558 void CMatrix::setArbitraryRotK(const CVector
&kdir
)
1560 // avoid gimbal lock. if kdir == nearly I, use another second lead vector
1561 if( fabs(kdir
.y
)<0.9f
)
1562 setRot(CVector::I
, CVector::J
, kdir
);
1564 setRot(CVector::I
, CVector::K
, kdir
);
1565 normalize(CMatrix::ZYX
);