matrix.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2000 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
00022  */
00023 
00024 #include "stdmisc.h"
00025 
00026 #include "nel/misc/matrix.h"
00027 #include "nel/misc/plane.h"
00028 #include "nel/misc/debug.h"
00029 
00030 using namespace std;
00031 
00032 
00033 
00034 namespace   NLMISC
00035 {
00036 
00037 
00038 // ======================================================================================================
00039 const CMatrix   CMatrix::Identity;
00040 
00041 
00042 // ======================================================================================================
00043 // ======================================================================================================
00044 // ======================================================================================================
00045 
00046 
00047 // State Bits.
00048 #define MAT_TRANS       1
00049 #define MAT_ROT         2
00050 #define MAT_SCALEUNI    4
00051 #define MAT_SCALEANY    8
00052 #define MAT_PROJ        16
00053 // Validity bits. These means that the part may be yet identity, but is valid in the floats.
00054 // NB: MAT_VALIDTRANS no more used for faster Pos access
00055 #define MAT_VALIDROT    64
00056 #define MAT_VALIDPROJ   128
00057 #define MAT_VALIDALL    (MAT_VALIDROT | MAT_VALIDPROJ)
00058 // The identity is nothing.
00059 #define MAT_IDENTITY    0
00060 
00061 
00062 
00063 // Matrix elements.
00064 #define a11     M[0]
00065 #define a21     M[1]
00066 #define a31     M[2]
00067 #define a41     M[3]
00068 #define a12     M[4]
00069 #define a22     M[5]
00070 #define a32     M[6]
00071 #define a42     M[7]
00072 #define a13     M[8]
00073 #define a23     M[9]
00074 #define a33     M[10]
00075 #define a43     M[11]
00076 #define a14     M[12]
00077 #define a24     M[13]
00078 #define a34     M[14]
00079 #define a44     M[15]
00080 
00081 
00082 
00083 // ======================================================================================================
00084 // ======================================================================================================
00085 // ======================================================================================================
00086 
00087 
00088 
00089 // ======================================================================================================
00090 bool        CMatrix::hasScalePart() const
00091 {
00092     return (StateBit&(MAT_SCALEUNI|MAT_SCALEANY))!=0;
00093 }
00094 bool        CMatrix::hasProjectionPart() const
00095 {
00096     return (StateBit&MAT_PROJ)!=0;
00097 }
00098 
00099 
00100 bool        CMatrix::hasScaleUniform() const
00101 {
00102     return (StateBit & (MAT_SCALEUNI|MAT_SCALEANY))== MAT_SCALEUNI;
00103 }
00104 float       CMatrix::getScaleUniform() const
00105 {
00106     if(hasScaleUniform())
00107         return Scale33;
00108     else
00109         return 1;
00110 }
00111 
00112 
00113 
00114 // ======================================================================================================
00115 inline bool CMatrix::hasRot() const
00116 {
00117     return (StateBit&(MAT_ROT|MAT_SCALEUNI|MAT_SCALEANY))!=0;
00118 }
00119 inline bool CMatrix::hasTrans() const
00120 {
00121     return (StateBit&MAT_TRANS)!=0;
00122 }
00123 inline bool CMatrix::hasProj() const
00124 {
00125     return (StateBit&MAT_PROJ)!=0;
00126 }
00127 inline bool CMatrix::hasAll() const
00128 {
00129     return (hasRot() && hasTrans() && hasProj());
00130 }
00131 
00132 
00133 inline void CMatrix::testExpandRot() const
00134 {
00135     if(hasRot())
00136         return;
00137     if(!(StateBit&MAT_VALIDROT))
00138     {
00139         CMatrix *self= const_cast<CMatrix*>(this);
00140         self->StateBit|=MAT_VALIDROT;
00141         self->a11= 1; self->a12=0; self->a13=0;
00142         self->a21= 0; self->a22=1; self->a23=0;
00143         self->a31= 0; self->a32=0; self->a33=1;
00144         self->Scale33= 1;
00145     }
00146 }
00147 inline void CMatrix::testExpandProj() const
00148 {
00149     if(hasProj())
00150         return;
00151     if(!(StateBit&MAT_VALIDPROJ))
00152     {
00153         CMatrix *self= const_cast<CMatrix*>(this);
00154         self->StateBit|=MAT_VALIDPROJ;
00155         self->a41=0; self->a42=0; self->a43=0; self->a44=1;
00156     }
00157 }
00158 
00159 
00160 // ======================================================================================================
00161 CMatrix::CMatrix(const CMatrix &m)
00162 {
00163     (*this)= m;
00164 }
00165 // ======================================================================================================
00166 CMatrix     &CMatrix::operator=(const CMatrix &m)
00167 {
00168     StateBit= m.StateBit & ~MAT_VALIDALL;
00169     if(hasAll())
00170     {
00171         memcpy(M, m.M, 16*sizeof(float));
00172         Scale33= m.Scale33;
00173     }
00174     else
00175     {
00176         if(hasRot())
00177         {
00178             memcpy(&a11, &m.a11, 3*sizeof(float));
00179             memcpy(&a12, &m.a12, 3*sizeof(float));
00180             memcpy(&a13, &m.a13, 3*sizeof(float));
00181             Scale33= m.Scale33;
00182         }
00183         if(hasProj())
00184         {
00185             a41= m.a41;
00186             a42= m.a42;
00187             a43= m.a43;
00188             a44= m.a44;
00189         }
00190         // Must always copy Trans part.
00191         memcpy(&a14, &m.a14, 3*sizeof(float));
00192     }
00193     return *this;
00194 }
00195 
00196 
00197 // ======================================================================================================
00198 void        CMatrix::identity()
00199 {
00200     StateBit= MAT_IDENTITY;
00201     // Reset just Pos because must always be valid for faster getPos()
00202     a14= a24= a34= 0;
00203     // For optimisation it would be useful to keep MAT_VALID states.
00204     // But this slows identity(), and this may not be interesting...
00205 }
00206 // ======================================================================================================
00207 void        CMatrix::setRot(const CVector &i, const CVector &j, const CVector &k, bool hintNoScale)
00208 {
00209     StateBit|= MAT_ROT | MAT_SCALEANY;
00210     if(hintNoScale)
00211         StateBit&= ~(MAT_SCALEANY|MAT_SCALEUNI);
00212     a11= i.x; a12= j.x; a13= k.x;
00213     a21= i.y; a22= j.y; a23= k.y;
00214     a31= i.z; a32= j.z; a33= k.z;
00215     Scale33= 1.0f;
00216 }
00217 // ======================================================================================================
00218 void        CMatrix::setRot(const float m33[9], bool hintNoScale)
00219 {
00220     StateBit|= MAT_ROT | MAT_SCALEANY;
00221     if(hintNoScale)
00222         StateBit&= ~(MAT_SCALEANY|MAT_SCALEUNI);
00223     a11= m33[0]; a12= m33[3]; a13= m33[6];
00224     a21= m33[1]; a22= m33[4]; a23= m33[7];
00225     a31= m33[2]; a32= m33[5]; a33= m33[8];
00226     Scale33= 1.0f;
00227 }
00228 // ======================================================================================================
00229 void        CMatrix::setRot(const CVector &v, TRotOrder ro)
00230 {
00231     CMatrix     rot;
00232     rot.identity();
00233     rot.rotate(v, ro);
00234     float   m33[9];
00235     rot.getRot(m33);
00236     setRot(m33, true);
00237 }
00238 
00239 
00240 // ======================================================================================================
00241 void        CMatrix::setRot(const CMatrix &matrix)
00242 {
00243     // copy rotpart statebit from other.
00244     StateBit&= ~(MAT_ROT | MAT_SCALEUNI | MAT_SCALEANY);
00245     StateBit|= matrix.StateBit & (MAT_ROT | MAT_SCALEUNI | MAT_SCALEANY);
00246     // copy values.
00247     if(hasRot())
00248     {
00249         a11= matrix.a11; a12= matrix.a12; a13= matrix.a13;
00250         a21= matrix.a21; a22= matrix.a22; a23= matrix.a23;
00251         a31= matrix.a31; a32= matrix.a32; a33= matrix.a33;
00252         // if has scale uniform, copy from matrix.
00253         if(hasScaleUniform())
00254             Scale33= matrix.Scale33;
00255     }
00256     else
00257     {
00258         // we are rot identity, with undefined values.
00259         StateBit&= ~MAT_VALIDROT;
00260     }
00261 }
00262 
00263 
00264 // ======================================================================================================
00265 void        CMatrix::setPos(const CVector &v)
00266 {
00267     a14= v.x;
00268     a24= v.y;
00269     a34= v.z;
00270     if(a14!=0 || a24!=0 || a34!=0)
00271         StateBit|= MAT_TRANS;
00272     else
00273         // The trans is identity
00274         StateBit&= ~MAT_TRANS;
00275 }
00276 // ======================================================================================================
00277 void        CMatrix::movePos(const CVector &v)
00278 {
00279     a14+= v.x;
00280     a24+= v.y;
00281     a34+= v.z;
00282     if(a14!=0 || a24!=0 || a34!=0)
00283         StateBit|= MAT_TRANS;
00284     else
00285         // The trans is identity
00286         StateBit&= ~MAT_TRANS;
00287 }
00288 // ======================================================================================================
00289 void        CMatrix::setProj(const float proj[4])
00290 {
00291     a41= proj[0];
00292     a42= proj[1];
00293     a43= proj[2];
00294     a44= proj[3];
00295 
00296     // Check Proj state.
00297     if(a41!=0 || a42!=0 || a43!=0 || a44!=1)
00298         StateBit|= MAT_PROJ;
00299     else
00300     {
00301         // The proj is identity, and is correcly setup!
00302         StateBit&= ~MAT_PROJ;
00303         StateBit|= MAT_VALIDPROJ;
00304     }
00305 }
00306 // ======================================================================================================
00307 void        CMatrix::resetProj()
00308 {
00309     a41= 0;
00310     a42= 0;
00311     a43= 0;
00312     a44= 1;
00313     // The proj is identity, and is correcly setup!
00314     StateBit&= ~MAT_PROJ;
00315     StateBit|= MAT_VALIDPROJ;
00316 }
00317 // ======================================================================================================
00318 void        CMatrix::set(const float m44[16])
00319 {
00320     StateBit= MAT_IDENTITY;
00321 
00322     StateBit|= MAT_ROT | MAT_SCALEANY;
00323     memcpy(M, m44, 16*sizeof(float));
00324     Scale33= 1.0f;
00325 
00326     // Check Trans state.
00327     if(a14!=0 || a24!=0 || a34!=0)
00328         StateBit|= MAT_TRANS;
00329     else
00330         // The trans is identity
00331         StateBit&= ~MAT_TRANS;
00332 
00333     // Check Proj state.
00334     if(a41!=0 || a42!=0 || a43!=0 || a44!=1)
00335         StateBit|= MAT_PROJ;
00336     else
00337     {
00338         // The proj is identity, and is correcly setup!
00339         StateBit&= ~MAT_PROJ;
00340         StateBit|= MAT_VALIDPROJ;
00341     }
00342 }
00343 
00344 
00345 // ======================================================================================================
00346 // ======================================================================================================
00347 // ======================================================================================================
00348 
00349 
00350 // ======================================================================================================
00351 void        CMatrix::getRot(CVector &i, CVector &j, CVector &k) const
00352 {
00353     if(hasRot())
00354     {
00355         i.set(a11, a21, a31);
00356         j.set(a12, a22, a32);
00357         k.set(a13, a23, a33);
00358     }
00359     else
00360     {
00361         i.set(1, 0, 0);
00362         j.set(0, 1, 0);
00363         k.set(0, 0, 1);
00364     }
00365 }
00366 // ======================================================================================================
00367 void        CMatrix::getRot(float m33[9]) const
00368 {
00369     if(hasRot())
00370     {
00371         m33[0]= a11;
00372         m33[1]= a21;
00373         m33[2]= a31;
00374 
00375         m33[3]= a12;
00376         m33[4]= a22;
00377         m33[5]= a32;
00378 
00379         m33[6]= a13;
00380         m33[7]= a23;
00381         m33[8]= a33;
00382     }
00383     else
00384     {
00385         m33[0]= 1;
00386         m33[1]= 0;
00387         m33[2]= 0;
00388 
00389         m33[3]= 0;
00390         m33[4]= 1;
00391         m33[5]= 0;
00392 
00393         m33[6]= 0;
00394         m33[7]= 0;
00395         m33[8]= 1;
00396     }
00397 }
00398 // ======================================================================================================
00399 void        CMatrix::getProj(float proj[4]) const
00400 {
00401     if(hasProj())
00402     {
00403         proj[0]= a41;
00404         proj[1]= a42;
00405         proj[2]= a43;
00406         proj[3]= a44;
00407     }
00408     else
00409     {
00410         proj[0]= 0;
00411         proj[1]= 0;
00412         proj[2]= 0;
00413         proj[3]= 1;
00414     }
00415 }
00416 // ======================================================================================================
00417 CVector     CMatrix::getI() const
00418 {
00419     if(hasRot())
00420         return CVector(a11, a21, a31);
00421     else
00422         return CVector(1, 0, 0);
00423 }
00424 // ======================================================================================================
00425 CVector     CMatrix::getJ() const
00426 {
00427     if(hasRot())
00428         return CVector(a12, a22, a32);
00429     else
00430         return CVector(0, 1, 0);
00431 }
00432 // ======================================================================================================
00433 CVector     CMatrix::getK() const
00434 {
00435     if(hasRot())
00436         return CVector(a13, a23, a33);
00437     else
00438         return CVector(0, 0, 1);
00439 }
00440 // ======================================================================================================
00441 void        CMatrix::get(float m44[16]) const
00442 {
00443     testExpandRot();
00444     testExpandProj();
00445     memcpy(m44, M, 16*sizeof(float));
00446 }
00447 // ======================================================================================================
00448 const float *CMatrix::get() const
00449 {
00450     testExpandRot();
00451     testExpandProj();
00452     return M;
00453 }
00454 /*// ======================================================================================================
00455 CVector     CMatrix::toEuler(TRotOrder ro) const
00456 {
00457 
00458 }*/
00459 
00460 
00461 // ======================================================================================================
00462 // ======================================================================================================
00463 // ======================================================================================================
00464 
00465 
00466 // ======================================================================================================
00467 void        CMatrix::translate(const CVector &v)
00468 {
00469     // SetTrans.
00470     if( hasRot() )
00471     {
00472         a14+= a11*v.x + a12*v.y + a13*v.z;
00473         a24+= a21*v.x + a22*v.y + a23*v.z;
00474         a34+= a31*v.x + a32*v.y + a33*v.z;
00475     }
00476     else
00477     {
00478         a14+= v.x;
00479         a24+= v.y;
00480         a34+= v.z;
00481     }
00482 
00483     // SetProj.
00484     if( hasProj() )
00485         a44+= a41*v.x + a42*v.y + a43*v.z;
00486 
00487     // Check Trans.
00488     if(a14!=0 || a24!=0 || a34!=0)
00489         StateBit|= MAT_TRANS;
00490     else
00491         // The trans is identity, and is correcly setup!
00492         StateBit&= ~MAT_TRANS;
00493 }
00494 // ======================================================================================================
00495 void        CMatrix::rotateX(float a)
00496 {
00497 
00498     if(a==0)
00499         return;
00500     double  ca,sa;
00501     ca=cos(a);
00502     sa=sin(a);
00503 
00504     // SetRot.
00505     if( hasRot() )
00506     {
00507         float   b12=a12, b22=a22, b32=a32;
00508         float   b13=a13, b23=a23, b33=a33;
00509         a12= (float)(b12*ca + b13*sa);
00510         a22= (float)(b22*ca + b23*sa);
00511         a32= (float)(b32*ca + b33*sa);
00512         a13= (float)(b13*ca - b12*sa);
00513         a23= (float)(b23*ca - b22*sa);
00514         a33= (float)(b33*ca - b32*sa);
00515     }
00516     else
00517     {
00518         testExpandRot();
00519         a12= 0.0f; a22= (float)ca; a32= (float)sa;
00520         a13= 0.0f; a23= (float)-sa; a33= (float)ca;
00521     }
00522 
00523     // SetProj.
00524     if( hasProj() )
00525     {
00526         float   b42=a42, b43=a43;
00527         a42= (float)(b42*ca + b43*sa);
00528         a43= (float)(b43*ca - b42*sa);
00529     }
00530 
00531     // set Rot.
00532     StateBit|= MAT_ROT;
00533 }
00534 // ======================================================================================================
00535 void        CMatrix::rotateY(float a)
00536 {
00537 
00538     if(a==0)
00539         return;
00540     double  ca,sa;
00541     ca=cos(a);
00542     sa=sin(a);
00543 
00544     // SetRot.
00545     if( hasRot() )
00546     {
00547         float   b11=a11, b21=a21, b31=a31;
00548         float   b13=a13, b23=a23, b33=a33;
00549         a11= (float)(b11*ca - b13*sa);
00550         a21= (float)(b21*ca - b23*sa);
00551         a31= (float)(b31*ca - b33*sa);
00552         a13= (float)(b13*ca + b11*sa);
00553         a23= (float)(b23*ca + b21*sa);
00554         a33= (float)(b33*ca + b31*sa);
00555     }
00556     else
00557     {
00558         testExpandRot();
00559         a11= (float)ca; a21=0.0f; a31= (float)-sa;
00560         a13= (float)sa; a23=0.0f; a33= (float)ca;
00561     }
00562 
00563     // SetProj.
00564     if( hasProj() )
00565     {
00566         float   b41=a41, b43=a43;
00567         a41= (float)(b41*ca - b43*sa);
00568         a43= (float)(b43*ca + b41*sa);
00569     }
00570 
00571     // set Rot.
00572     StateBit|= MAT_ROT;
00573 }
00574 // ======================================================================================================
00575 void        CMatrix::rotateZ(float a)
00576 {
00577 
00578     if(a==0)
00579         return;
00580     double  ca,sa;
00581     ca=cos(a);
00582     sa=sin(a);
00583 
00584     // SetRot.
00585     if( StateBit & (MAT_ROT|MAT_SCALEUNI|MAT_SCALEANY) )
00586     {
00587         float   b11=a11, b21=a21, b31=a31;
00588         float   b12=a12, b22=a22, b32=a32;
00589         a11= (float)(b11*ca + b12*sa);
00590         a21= (float)(b21*ca + b22*sa);
00591         a31= (float)(b31*ca + b32*sa);
00592         a12= (float)(b12*ca - b11*sa);
00593         a22= (float)(b22*ca - b21*sa);
00594         a32= (float)(b32*ca - b31*sa);
00595     }
00596     else
00597     {
00598         testExpandRot();
00599         a11= (float)ca; a21= (float)sa; a31=0.0f;
00600         a12= (float)-sa; a22= (float)ca; a32=0.0f;
00601     }
00602 
00603     // SetProj.
00604     if( hasProj() )
00605     {
00606         float   b41=a41, b42=a42;
00607         a41= (float)(b41*ca + b42*sa);
00608         a42= (float)(b42*ca - b41*sa);
00609     }
00610 
00611     // set Rot.
00612     StateBit|= MAT_ROT;
00613 }
00614 // ======================================================================================================
00615 void        CMatrix::rotate(const CVector &v, TRotOrder ro)
00616 {
00617     CMatrix     rot;
00618     rot.identity();
00619     switch(ro)
00620     {
00621         case XYZ: rot.rotateX(v.x); rot.rotateY(v.y); rot.rotateZ(v.z); break;
00622         case XZY: rot.rotateX(v.x); rot.rotateZ(v.z); rot.rotateY(v.y); break;
00623         case YXZ: rot.rotateY(v.y); rot.rotateX(v.x); rot.rotateZ(v.z); break;
00624         case YZX: rot.rotateY(v.y); rot.rotateZ(v.z); rot.rotateX(v.x); break;
00625         case ZXY: rot.rotateZ(v.z); rot.rotateX(v.x); rot.rotateY(v.y); break;
00626         case ZYX: rot.rotateZ(v.z); rot.rotateY(v.y); rot.rotateX(v.x); break;
00627     }
00628 
00629     (*this)*= rot;
00630 }
00631 
00632 // ======================================================================================================
00633 void        CMatrix::rotate(const CQuat &quat)
00634 {
00635     CMatrix     rot;
00636     rot.setRot(quat);
00637     (*this)*= rot;
00638 }
00639 
00640 // ======================================================================================================
00641 void        CMatrix::scale(float f)
00642 {
00643 
00644     if(f==1.0f) return;
00645     if(StateBit & MAT_SCALEANY)
00646     {
00647         scale(CVector(f,f,f));
00648     }
00649     else
00650     {
00651         testExpandRot();
00652         StateBit|= MAT_SCALEUNI;
00653         Scale33*=f;
00654         a11*= f; a12*=f; a13*=f;
00655         a21*= f; a22*=f; a23*=f;
00656         a31*= f; a32*=f; a33*=f;
00657 
00658         // SetProj.
00659         if( hasProj() )
00660         {
00661             a41*=f; a42*=f; a43*=f;
00662         }
00663     }
00664 }
00665 // ======================================================================================================
00666 void        CMatrix::scale(const CVector &v)
00667 {
00668 
00669     if( v==CVector(1,1,1) ) return;
00670     if( !(StateBit & MAT_SCALEANY) && v.x==v.y && v.x==v.z)
00671     {
00672         scale(v.x);
00673     }
00674     else
00675     {
00676         testExpandRot();
00677         StateBit|=MAT_SCALEANY;
00678         a11*= v.x; a12*=v.y; a13*=v.z;
00679         a21*= v.x; a22*=v.y; a23*=v.z;
00680         a31*= v.x; a32*=v.y; a33*=v.z;
00681 
00682         // SetProj.
00683         if( hasProj() )
00684         {
00685             a41*=v.x;
00686             a42*=v.y;
00687             a43*=v.z;
00688         }
00689     }
00690 }
00691 
00692 
00693 // ======================================================================================================
00694 // ======================================================================================================
00695 // ======================================================================================================
00696 
00697 
00698 // ***************************************************************************
00699 void        CMatrix::setMulMatrixNoProj(const CMatrix &m1, const CMatrix &m2)
00700 {
00701     /*
00702     For a fast MulMatrix, it appears to be better to not take State bits into account (no test/if() overhead)
00703     Just do heavy mul all the time (common case, and not so slow)
00704     */
00705 
00706     // Ensure the src matrix have correct values in rot part
00707     m1.testExpandRot();
00708     m2.testExpandRot();
00709 
00710     // Rot Mul
00711     a11= m1.a11*m2.a11 + m1.a12*m2.a21 + m1.a13*m2.a31;
00712     a12= m1.a11*m2.a12 + m1.a12*m2.a22 + m1.a13*m2.a32;
00713     a13= m1.a11*m2.a13 + m1.a12*m2.a23 + m1.a13*m2.a33;
00714 
00715     a21= m1.a21*m2.a11 + m1.a22*m2.a21 + m1.a23*m2.a31;
00716     a22= m1.a21*m2.a12 + m1.a22*m2.a22 + m1.a23*m2.a32;
00717     a23= m1.a21*m2.a13 + m1.a22*m2.a23 + m1.a23*m2.a33;
00718 
00719     a31= m1.a31*m2.a11 + m1.a32*m2.a21 + m1.a33*m2.a31;
00720     a32= m1.a31*m2.a12 + m1.a32*m2.a22 + m1.a33*m2.a32;
00721     a33= m1.a31*m2.a13 + m1.a32*m2.a23 + m1.a33*m2.a33;
00722 
00723     // Trans mul
00724     a14= m1.a11*m2.a14 + m1.a12*m2.a24 + m1.a13*m2.a34 + m1.a14;
00725     a24= m1.a21*m2.a14 + m1.a22*m2.a24 + m1.a23*m2.a34 + m1.a24;
00726     a34= m1.a31*m2.a14 + m1.a32*m2.a24 + m1.a33*m2.a34 + m1.a34;
00727 
00728     // Setup no proj at all, and force valid rot (still may be identity, but 0/1 are filled)
00729     StateBit= (m1.StateBit | m2.StateBit | MAT_VALIDROT) & ~(MAT_PROJ|MAT_VALIDPROJ);
00730 
00731     // Modify Scale. This test is important because Scale33 may be a #NAN if SCALEANY => avoid very slow mul.
00732     if( hasScaleUniform() )
00733         Scale33= m1.Scale33*m2.Scale33;
00734     else
00735         Scale33=1;
00736 
00737 }
00738 
00739 
00740 // ***************************************************************************
00741 void        CMatrix::setMulMatrix(const CMatrix &m1, const CMatrix &m2)
00742 {
00743     // Do *this= m1*m2
00744     identity();
00745     StateBit= m1.StateBit | m2.StateBit;
00746     StateBit&= ~MAT_VALIDALL;
00747 
00748     // Build Rot part.
00749     //===============
00750     bool    M1Identity= ! m1.hasRot();
00751     bool    M2Identity= ! m2.hasRot();
00752     bool    M1ScaleOnly= ! (m1.StateBit & MAT_ROT);
00753     bool    M2ScaleOnly= ! (m2.StateBit & MAT_ROT);
00754     bool    MGeneralCase= !M1Identity && !M2Identity && !M1ScaleOnly && !M2ScaleOnly;
00755 
00756 
00757     // Manage the most common general case first (optim the if ): blending of two rotations.
00758     if( MGeneralCase )
00759     {
00760         a11= m1.a11*m2.a11 + m1.a12*m2.a21 + m1.a13*m2.a31;
00761         a12= m1.a11*m2.a12 + m1.a12*m2.a22 + m1.a13*m2.a32;
00762         a13= m1.a11*m2.a13 + m1.a12*m2.a23 + m1.a13*m2.a33;
00763 
00764         a21= m1.a21*m2.a11 + m1.a22*m2.a21 + m1.a23*m2.a31;
00765         a22= m1.a21*m2.a12 + m1.a22*m2.a22 + m1.a23*m2.a32;
00766         a23= m1.a21*m2.a13 + m1.a22*m2.a23 + m1.a23*m2.a33;
00767 
00768         a31= m1.a31*m2.a11 + m1.a32*m2.a21 + m1.a33*m2.a31;
00769         a32= m1.a31*m2.a12 + m1.a32*m2.a22 + m1.a33*m2.a32;
00770         a33= m1.a31*m2.a13 + m1.a32*m2.a23 + m1.a33*m2.a33;
00771     }
00772     // If one of the 3x3 matrix is an identity, just do a copy
00773     else if( M1Identity || M2Identity )
00774     {
00775         // If both identity, then me too.
00776         if( M1Identity && M2Identity )
00777         {
00778             // just expand me (important because validated below)
00779             testExpandRot();
00780         }
00781         else
00782         {
00783             // Copy the non identity matrix.
00784             const CMatrix   *c= M2Identity? &m1 : &m2;
00785             a11= c->a11; a12= c->a12; a13= c->a13;
00786             a21= c->a21; a22= c->a22; a23= c->a23;
00787             a31= c->a31; a32= c->a32; a33= c->a33;
00788         }
00789     }
00790     // If two 3x3 matrix are just scaleOnly matrix, do a scaleFact.
00791     else if( M1ScaleOnly && M2ScaleOnly )
00792     {
00793         // same process for scaleUni or scaleAny.
00794         a11= m1.a11*m2.a11; a12= 0; a13= 0;
00795         a21= 0; a22= m1.a22*m2.a22; a23= 0;
00796         a31= 0; a32= 0; a33= m1.a33*m2.a33;
00797     }
00798     // If one of the matrix is a scaleOnly matrix, do a scale*Rot.
00799     else if( M1ScaleOnly && !M2ScaleOnly )
00800     {
00801         a11= m1.a11*m2.a11; a12= m1.a11*m2.a12; a13= m1.a11*m2.a13;
00802         a21= m1.a22*m2.a21; a22= m1.a22*m2.a22; a23= m1.a22*m2.a23;
00803         a31= m1.a33*m2.a31; a32= m1.a33*m2.a32; a33= m1.a33*m2.a33;
00804     }
00805     else
00806     {
00807         // This must be this case
00808         nlassert(!M1ScaleOnly && M2ScaleOnly);
00809         a11= m1.a11*m2.a11; a12= m1.a12*m2.a22; a13= m1.a13*m2.a33;
00810         a21= m1.a21*m2.a11; a22= m1.a22*m2.a22; a23= m1.a23*m2.a33;
00811         a31= m1.a31*m2.a11; a32= m1.a32*m2.a22; a33= m1.a33*m2.a33;
00812     }
00813 
00814     // If M1 has translate and M2 has projective, rotation is modified.
00815     if( m1.hasTrans() && m2.hasProj())
00816     {
00817         StateBit|= MAT_ROT|MAT_SCALEANY;
00818 
00819         a11+= m1.a14*m2.a41;
00820         a12+= m1.a14*m2.a42;
00821         a13+= m1.a14*m2.a43;
00822 
00823         a21+= m1.a24*m2.a41;
00824         a22+= m1.a24*m2.a42;
00825         a23+= m1.a24*m2.a43;
00826 
00827         a31+= m1.a34*m2.a41;
00828         a32+= m1.a34*m2.a42;
00829         a33+= m1.a34*m2.a43;
00830     }
00831 
00832     // Modify Scale.
00833     if( (StateBit & MAT_SCALEUNI) && !(StateBit & MAT_SCALEANY) )
00834     {
00835         // Must have correct Scale33
00836         m1.testExpandRot();
00837         m2.testExpandRot();
00838         Scale33= m1.Scale33*m2.Scale33;
00839     }
00840     else
00841         Scale33=1;
00842 
00843     // In every case, I am valid now!
00844     StateBit|=MAT_VALIDROT;
00845 
00846 
00847     // Build Trans part.
00848     //=================
00849     if( StateBit & MAT_TRANS )
00850     {
00851         // Compose M2 part.
00852         if( M1Identity )
00853         {
00854             a14= m2.a14;
00855             a24= m2.a24;
00856             a34= m2.a34;
00857         }
00858         else if (M1ScaleOnly )
00859         {
00860             a14= m1.a11*m2.a14;
00861             a24= m1.a22*m2.a24;
00862             a34= m1.a33*m2.a34;
00863         }
00864         else
00865         {
00866             a14= m1.a11*m2.a14 + m1.a12*m2.a24 + m1.a13*m2.a34;
00867             a24= m1.a21*m2.a14 + m1.a22*m2.a24 + m1.a23*m2.a34;
00868             a34= m1.a31*m2.a14 + m1.a32*m2.a24 + m1.a33*m2.a34;
00869         }
00870         // Compose M1 part.
00871         if(m1.StateBit & MAT_TRANS)
00872         {
00873             if(m2.StateBit & MAT_PROJ)
00874             {
00875                 a14+= m1.a14*m2.a44;
00876                 a24+= m1.a24*m2.a44;
00877                 a34+= m1.a34*m2.a44;
00878             }
00879             else
00880             {
00881                 a14+= m1.a14;
00882                 a24+= m1.a24;
00883                 a34+= m1.a34;
00884             }
00885         }
00886     }
00887 
00888 
00889     // Build Proj part.
00890     //=================
00891     if( StateBit & MAT_PROJ )
00892     {
00893         // optimize nothing... (projection matrix are rare).
00894         m1.testExpandRot();
00895         m1.testExpandProj();
00896         m2.testExpandRot();
00897         m2.testExpandProj();
00898         a41= m1.a41*m2.a11 + m1.a42*m2.a21 + m1.a43*m2.a31 + m1.a44*m2.a41;
00899         a42= m1.a41*m2.a12 + m1.a42*m2.a22 + m1.a43*m2.a32 + m1.a44*m2.a42;
00900         a43= m1.a41*m2.a13 + m1.a42*m2.a23 + m1.a43*m2.a33 + m1.a44*m2.a43;
00901         a44= m1.a41*m2.a14 + m1.a42*m2.a24 + m1.a43*m2.a34 + m1.a44*m2.a44;
00902         // The proj is valid now
00903         StateBit|= MAT_VALIDPROJ;
00904     }
00905     else
00906     {
00907         // Don't copy proj part, and leave MAT_VALIDPROJ not set
00908     }
00909 }
00910 // ======================================================================================================
00911 void        CMatrix::invert()
00912 {
00913 
00914     *this= inverted();
00915 }
00916 
00917 
00918 // ======================================================================================================
00919 void        CMatrix::transpose3x3()
00920 {
00921     if(hasRot())
00922     {
00923         // swap values.
00924         swap(a12, a21);
00925         swap(a13, a31);
00926         swap(a32, a23);
00927         // Scale mode (none, uni, or any) is conserved. Scale33 too...
00928     }
00929 }
00930 
00931 // ======================================================================================================
00932 void        CMatrix::transpose()
00933 {
00934     transpose3x3();
00935     if(hasTrans() || hasProj())
00936     {
00937         // if necessary, Get valid 0 on proj part.
00938         testExpandProj();
00939         // swap values
00940         swap(a41, a14);
00941         swap(a42, a24);
00942         swap(a43, a34);
00943         // swap StateBit flags, if not both were sets...
00944         if(!hasTrans() || !hasProj())
00945         {
00946             // swap StateBit flags (swap trans with proj).
00947             if(hasTrans())
00948             {
00949                 StateBit&= ~MAT_TRANS;
00950                 StateBit|= MAT_PROJ;
00951             }
00952             else
00953             {
00954                 StateBit&= ~MAT_PROJ;
00955                 StateBit|= MAT_TRANS;
00956             }
00957         }
00958         // reset validity. NB, maybe not useful, but simpler, and bugfree.
00959         StateBit&= ~(MAT_VALIDPROJ);
00960     }
00961     // NB: if no Trans or no Proj, do nothing, so don't need to modify VALIDTRANS and VALIDPROJ too.
00962 }
00963 
00964 
00965 // ======================================================================================================
00966 bool    CMatrix::fastInvert33(CMatrix &ret) const
00967 {
00968     // Fast invert of 3x3 rot matrix.
00969     // Work if no scale and if MAT_SCALEUNI. doesn't work if MAT_SCALEANY.
00970 
00971     if(StateBit & MAT_SCALEUNI)
00972     {
00973         if (Scale33 == 0.f) return false;
00974         double  s,S;    // important for precision.
00975         // Must divide the matrix by 1/Scale 2 times, to set unit, and to have a Scale=1/Scale.
00976         S=1.0/Scale33;
00977         ret.Scale33= (float)S;
00978         s=S*S;
00979         // The matrix is a base, so just transpose it.
00980         ret.a11= (float)(a11*s); ret.a12= (float)(a21*s); ret.a13= (float)(a31*s);
00981         ret.a21= (float)(a12*s); ret.a22= (float)(a22*s); ret.a23= (float)(a32*s);
00982         ret.a31= (float)(a13*s); ret.a32= (float)(a23*s); ret.a33= (float)(a33*s);
00983     }
00984     else
00985     {
00986         ret.Scale33=1;
00987         // The matrix is a base, so just transpose it.
00988         ret.a11= a11; ret.a12= a21; ret.a13=a31;
00989         ret.a21= a12; ret.a22= a22; ret.a23=a32;
00990         ret.a31= a13; ret.a32= a23; ret.a33=a33;
00991     }
00992     return true;
00993     // 15 cycles if no scale.
00994     // 35 cycles if scale.
00995 }
00996 // ======================================================================================================
00997 bool    CMatrix::slowInvert33(CMatrix &ret) const
00998 {
00999     CVector invi,invj,invk;
01000     CVector i,j,k;
01001     double  s;
01002 
01003     i= getI();
01004     j= getJ();
01005     k= getK();
01006     // Compute cofactors (minors *(-1)^(i+j)).
01007     invi.x= j.y*k.z - k.y*j.z;
01008     invi.y= j.z*k.x - k.z*j.x;
01009     invi.z= j.x*k.y - k.x*j.y;
01010     invj.x= k.y*i.z - i.y*k.z;
01011     invj.y= k.z*i.x - i.z*k.x;
01012     invj.z= k.x*i.y - i.x*k.y;
01013     invk.x= i.y*j.z - j.y*i.z;
01014     invk.y= i.z*j.x - j.z*i.x;
01015     invk.z= i.x*j.y - j.x*i.y;
01016     // compute determinant.
01017     s= invi.x*i.x + invj.x*j.x + invk.x*k.x;
01018     if(s==0)
01019         return false;
01020     // Transpose the Comatrice, and divide by determinant.
01021     s=1.0/s;
01022     ret.a11= (float)(invi.x*s); ret.a12= (float)(invi.y*s); ret.a13= (float)(invi.z*s);
01023     ret.a21= (float)(invj.x*s); ret.a22= (float)(invj.y*s); ret.a23= (float)(invj.z*s);
01024     ret.a31= (float)(invk.x*s); ret.a32= (float)(invk.y*s); ret.a33= (float)(invk.z*s);
01025 
01026     return true;
01027     // Roundly 82 cycles. (1Div=10 cycles).
01028 }
01029 // ======================================================================================================
01030 bool    CMatrix::slowInvert44(CMatrix &ret) const
01031 {
01032     sint    i,j;
01033     double  s;
01034 
01035     // Compute Cofactors
01036     //==================
01037     for(i=0;i<=3;i++)
01038     {
01039         for(j=0;j<=3;j++)
01040         {
01041             sint    l1=0,l2=0,l3=0;
01042             sint    c1,c2,c3;
01043             getCofactIndex(i,l1,l2,l3);
01044             getCofactIndex(j,c1,c2,c3);
01045 
01046             ret.mat(i,j)= 0;
01047             ret.mat(i,j)+= mat(l1,c1) * mat(l2,c2) * mat(l3,c3);
01048             ret.mat(i,j)+= mat(l1,c2) * mat(l2,c3) * mat(l3,c1);
01049             ret.mat(i,j)+= mat(l1,c3) * mat(l2,c1) * mat(l3,c2);
01050 
01051             ret.mat(i,j)-= mat(l1,c1) * mat(l2,c3) * mat(l3,c2);
01052             ret.mat(i,j)-= mat(l1,c2) * mat(l2,c1) * mat(l3,c3);
01053             ret.mat(i,j)-= mat(l1,c3) * mat(l2,c2) * mat(l3,c1);
01054 
01055             if( (i+j)&1 )
01056                 ret.mat(i,j)=-ret.mat(i,j);
01057         }
01058     }
01059 
01060     // Compute determinant.
01061     //=====================
01062     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);
01063     if(s==0)
01064         return false;
01065 
01066     // Divide by determinant.
01067     //=======================
01068     s=1.0/s;
01069     for(i=0;i<=3;i++)
01070     {
01071         for(j=0;j<=3;j++)
01072             ret.mat(i,j)= (float)(ret.mat(i,j)*s);
01073     }
01074 
01075     // Transpose the comatrice.
01076     //=========================
01077     for(i=0;i<=3;i++)
01078     {
01079         for(j=i+1;j<=3;j++)
01080         {
01081             swap(ret.mat(i,j), ret.mat(j,i));
01082         }
01083     }
01084 
01085     return true;
01086 }
01087 // ======================================================================================================
01088 CMatrix     CMatrix::inverted() const
01089 {
01090 
01091     CMatrix ret;
01092 
01093     testExpandRot();
01094     testExpandProj();
01095 
01096     // Do a conventionnal 44 inversion.
01097     //=================================
01098     if(StateBit & MAT_PROJ)
01099     {
01100         if(!slowInvert44(ret))
01101         {
01102             ret.identity();
01103             return ret;
01104         }
01105 
01106         // Well, don't know what happens to matrix, so set all StateBit :).
01107         ret.StateBit= MAT_TRANS|MAT_ROT|MAT_SCALEANY|MAT_PROJ;
01108 
01109         // Check Trans state.
01110         if(ret.a14!=0 || ret.a24!=0 || ret.a34!=0)
01111             ret.StateBit|= MAT_TRANS;
01112         else
01113             ret.StateBit&= ~MAT_TRANS;
01114 
01115         // Check Proj state.
01116         if(ret.a41!=0 || ret.a42!=0 || ret.a43!=0 || ret.a44!=1)
01117             ret.StateBit|= MAT_PROJ;
01118         else
01119             ret.StateBit&= ~MAT_PROJ;
01120     }
01121 
01122     // Do a speed 34 inversion.
01123     //=========================
01124     else
01125     {
01126         // Invert the rotation part.
01127         if(StateBit & MAT_SCALEANY)
01128         {
01129             if(!slowInvert33(ret))
01130             {
01131                 ret.identity();
01132                 return ret;
01133             }
01134         }
01135         else
01136         {
01137             if (!fastInvert33(ret))
01138             {
01139                 ret.identity();
01140                 return ret;
01141             }
01142         }
01143         // Scale33 is updated in fastInvert33().
01144 
01145         // Invert the translation part.
01146         if(StateBit & MAT_TRANS)
01147         {
01148             // Invert the translation part.
01149             // This can only work if 4th line is 0 0 0 1.
01150             // formula: InvVp= InvVi*(-Vp.x) + InvVj*(-Vp.y) + InvVk*(-Vp.z)
01151             ret.a14= ret.a11*(-a14) + ret.a12*(-a24) + ret.a13*(-a34);
01152             ret.a24= ret.a21*(-a14) + ret.a22*(-a24) + ret.a23*(-a34);
01153             ret.a34= ret.a31*(-a14) + ret.a32*(-a24) + ret.a33*(-a34);
01154         }
01155         else
01156         {
01157             ret.a14= 0;
01158             ret.a24= 0;
01159             ret.a34= 0;
01160         }
01161 
01162         // The projection part is unmodified.
01163         ret.a41= 0; ret.a42= 0; ret.a43= 0; ret.a44= 1;
01164 
01165         // The matrix inverted keep the same state bits.
01166         ret.StateBit= StateBit;
01167     }
01168 
01169 
01170     return ret;
01171 }
01172 // ======================================================================================================
01173 bool        CMatrix::normalize(TRotOrder ro)
01174 {
01175 
01176     CVector ti,tj,tk;
01177     ti= getI();
01178     tj= getJ();
01179     tk= getK();
01180 
01181     testExpandRot();
01182 
01183     // Normalize with help of ro
01184     switch(ro)
01185     {
01186         case XYZ:
01187             ti.normalize();
01188             tk= ti^tj;
01189             tk.normalize();
01190             tj= tk^ti;
01191             break;
01192         case XZY:
01193             ti.normalize();
01194             tj= tk^ti;
01195             tj.normalize();
01196             tk= ti^tj;
01197             break;
01198         case YXZ:
01199             tj.normalize();
01200             tk= ti^tj;
01201             tk.normalize();
01202             ti= tj^tk;
01203             break;
01204         case YZX:
01205             tj.normalize();
01206             ti= tj^tk;
01207             ti.normalize();
01208             tk= ti^tj;
01209             break;
01210         case ZXY:
01211             tk.normalize();
01212             tj= tk^ti;
01213             tj.normalize();
01214             ti= tj^tk;
01215             break;
01216         case ZYX:
01217             tk.normalize();
01218             ti= tj^tk;
01219             ti.normalize();
01220             tj= tk^ti;
01221             break;
01222     }
01223 
01224     // Check, and set result.
01225     if( ti.isNull() || tj.isNull() || tk.isNull() )
01226         return false;
01227     a11= ti.x; a12= tj.x; a13= tk.x;
01228     a21= ti.y; a22= tj.y; a23= tk.y;
01229     a31= ti.z; a32= tj.z; a33= tk.z;
01230     // Scale is reseted.
01231     StateBit&= ~(MAT_SCALEUNI|MAT_SCALEANY);
01232     // Rot is setup...
01233     StateBit|= MAT_ROT;
01234     Scale33=1;
01235 
01236     return true;
01237 }
01238 
01239 
01240 // ======================================================================================================
01241 // ======================================================================================================
01242 // ======================================================================================================
01243 
01244 
01245 // ======================================================================================================
01246 CVector     CMatrix::mulVector(const CVector &v) const
01247 {
01248 
01249     CVector ret;
01250 
01251     if( hasRot() )
01252     {
01253         ret.x= a11*v.x + a12*v.y + a13*v.z;
01254         ret.y= a21*v.x + a22*v.y + a23*v.z;
01255         ret.z= a31*v.x + a32*v.y + a33*v.z;
01256         return ret;
01257     }
01258     else
01259         return v;
01260 }
01261 
01262 // ======================================================================================================
01263 CVector     CMatrix::mulPoint(const CVector &v) const
01264 {
01265 
01266     CVector ret;
01267 
01268     if( hasRot() )
01269     {
01270         ret.x= a11*v.x + a12*v.y + a13*v.z;
01271         ret.y= a21*v.x + a22*v.y + a23*v.z;
01272         ret.z= a31*v.x + a32*v.y + a33*v.z;
01273     }
01274     else
01275     {
01276         ret= v;
01277     }
01278     if( hasTrans() )
01279     {
01280         ret.x+= a14;
01281         ret.y+= a24;
01282         ret.z+= a34;
01283     }
01284 
01285     return ret;
01286 }
01287 
01288 
01289 /*
01290  * Multiply
01291  */
01292 CVectorH    CMatrix::operator*(const CVectorH& v) const
01293 {
01294 
01295     CVectorH ret;
01296 
01297     testExpandRot();
01298     testExpandProj();
01299 
01300     ret.x= a11*v.x + a12*v.y + a13*v.z + a14*v.w;
01301     ret.y= a21*v.x + a22*v.y + a23*v.z + a24*v.w;
01302     ret.z= a31*v.x + a32*v.y + a33*v.z + a34*v.w;
01303     ret.w= a41*v.x + a42*v.y + a43*v.z + a44*v.w;
01304     return ret;
01305 }
01306 
01307 
01308 // ======================================================================================================
01309 CPlane      operator*(const CPlane &p, const CMatrix &m)
01310 {
01311     m.testExpandRot();
01312     m.testExpandProj();
01313 
01314     CPlane  ret;
01315 
01316     if( m.StateBit & (MAT_ROT|MAT_SCALEUNI|MAT_SCALEANY|MAT_PROJ) )
01317     {
01318         // Compose with translation too.
01319         ret.a= p.a*m.a11 + p.b*m.a21 + p.c*m.a31 + p.d*m.a41;
01320         ret.b= p.a*m.a12 + p.b*m.a22 + p.c*m.a32 + p.d*m.a42;
01321         ret.c= p.a*m.a13 + p.b*m.a23 + p.c*m.a33 + p.d*m.a43;
01322         ret.d= p.a*m.a14 + p.b*m.a24 + p.c*m.a34 + p.d*m.a44;
01323         return ret;
01324     }
01325     else if( m.StateBit & MAT_TRANS )
01326     {
01327 
01328         // Compose just with a translation.
01329         ret.a= p.a;
01330         ret.b= p.b;
01331         ret.c= p.c;
01332         ret.d= p.a*m.a14 + p.b*m.a24 + p.c*m.a34 + p.d*m.a44;
01333         return ret;
01334     }
01335     else    // Identity!!
01336         return p;
01337 }
01338 
01339 
01340 // ======================================================================================================
01341 // ======================================================================================================
01342 // ======================================================================================================
01343 
01344 
01345 // ======================================================================================================
01346 void        CMatrix::setRot(const CQuat &quat)
01347 {
01348     // A quaternion do not have scale.
01349     StateBit&= ~(MAT_ROT | MAT_SCALEANY|MAT_SCALEUNI);
01350     Scale33= 1.0f;
01351     if(quat.isIdentity())
01352     {
01353         a11= 1; a12= 0; a13= 0;
01354         a21= 0; a22= 1; a23= 0;
01355         a31= 0; a32= 0; a33= 1;
01356     }
01357     else
01358     {
01359         StateBit|= MAT_ROT;
01360         float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2;
01361 
01362         // calculate coefficients
01363         x2 = quat.x + quat.x; y2 = quat.y + quat.y;
01364         z2 = quat.z + quat.z;
01365         xx = quat.x * x2;   xy = quat.x * y2;   xz = quat.x * z2;
01366         yy = quat.y * y2;   yz = quat.y * z2;   zz = quat.z * z2;
01367         wx = quat.w * x2;   wy = quat.w * y2;   wz = quat.w * z2;
01368 
01369         a11 = 1.0f - (yy + zz);
01370         a12 = xy - wz;
01371         a13 = xz + wy;
01372 
01373         a21 = xy + wz;
01374         a22 = 1.0f - (xx + zz);
01375         a23 = yz - wx;
01376 
01377         a31 = xz - wy;
01378         a32 = yz + wx;
01379         a33 = 1.0f - (xx + yy);
01380     }
01381 }
01382 
01383 
01384 // ======================================================================================================
01385 void        CMatrix::getRot(CQuat &quat) const
01386 {
01387     const CMatrix   *pmat= this;
01388     CMatrix         MatNormed;
01389 
01390 
01391     // Rot Indentity?
01392     if(! (StateBit & MAT_ROT))
01393     {
01394         quat= CQuat::Identity;
01395         return;
01396     }
01397 
01398     // Must normalize the matrix??
01399     if(StateBit & (MAT_SCALEUNI | MAT_SCALEANY) )
01400     {
01401         MatNormed= *this;
01402         MatNormed.normalize(ZYX);
01403         pmat= &MatNormed;
01404     }
01405 
01406     // Compute quaternion.
01407     float  tr, s, q[4];
01408 
01409     tr = pmat->a11 + pmat->a22 + pmat->a33;
01410 
01411     // check the diagonal
01412     if (tr > 0.0)
01413     {
01414         s = (float)sqrt (tr + 1.0f);
01415         quat.w = s / 2.0f;
01416         s = 0.5f / s;
01417         quat.x = (pmat->a32 - pmat->a23) * s;
01418         quat.y = (pmat->a13 - pmat->a31) * s;
01419         quat.z = (pmat->a21 - pmat->a12) * s;
01420     }
01421     else
01422     {
01423         sint    i, j, k;
01424         sint    nxt[3] = {1, 2, 0};
01425 
01426         // diagonal is negative
01427         i = 0;
01428         if (pmat->a22 > pmat->a11) i = 1;
01429         if (pmat->a33 > pmat->mat(i,i) ) i = 2;
01430         j = nxt[i];
01431         k = nxt[j];
01432 
01433         s = (float) sqrt (  (pmat->mat(i,i) - (pmat->mat(j,j) + pmat->mat(k,k)) )   + 1.0);
01434 
01435         q[i] = s * 0.5f;
01436 
01437         if (s != 0.0f) s = 0.5f / s;
01438 
01439         q[j] = (pmat->mat(j,i) + pmat->mat(i,j)) * s;
01440         q[k] = (pmat->mat(k,i) + pmat->mat(i,k)) * s;
01441         q[3] =   (pmat->mat(k,j) - pmat->mat(j,k)) * s;
01442 
01443         quat.x = q[0];
01444         quat.y = q[1];
01445         quat.z = q[2];
01446         quat.w = q[3];
01447     }
01448 
01449 }
01450 
01451 
01452 // ======================================================================================================
01453 // ======================================================================================================
01454 // ======================================================================================================
01455 
01456 
01457 // ======================================================================================================
01458 inline  void    CMatrix::setScaleUni(float scale)
01459 {
01460     // A Scale matrix do not have rotation.
01461     StateBit&= ~(MAT_ROT | MAT_SCALEANY | MAT_SCALEUNI);
01462     StateBit|= MAT_SCALEUNI | MAT_VALIDROT;
01463     Scale33= scale;
01464     a11= scale; a12= 0; a13= 0;
01465     a21= 0; a22= scale; a23= 0;
01466     a31= 0; a32= 0; a33= scale;
01467 }
01468 
01469 // ======================================================================================================
01470 void        CMatrix::setScale(float scale)
01471 {
01472     setScaleUni(scale);
01473 }
01474 
01475 
01476 // ======================================================================================================
01477 void        CMatrix::setScale(const CVector &v)
01478 {
01479     // actually a scale uniform?
01480     if(v.x==v.y && v.x==v.z)
01481         setScaleUni(v.x);
01482 
01483     // A Scale matrix do not have rotation.
01484     StateBit&= ~(MAT_ROT | MAT_SCALEANY | MAT_SCALEUNI);
01485     StateBit|= MAT_SCALEANY | MAT_VALIDROT;
01486     a11= v.x; a12= 0; a13= 0;
01487     a21= 0; a22= v.y; a23= 0;
01488     a31= 0; a32= 0; a33= v.z;
01489 
01490 }
01491 
01492 
01493 // ======================================================================================================
01494 // ======================================================================================================
01495 // ======================================================================================================
01496 
01497 
01498 // ======================================================================================================
01499 void        CMatrix::serial(IStream &f)
01500 {
01501     // Use versionning, maybe for futur improvement.
01502     (void)f.serialVersion(0);
01503 
01504     if(f.isReading())
01505         identity();
01506     f.serial(StateBit);
01507     // avoid serial of random data
01508     if(!f.isReading() && !hasScaleUniform())
01509     {
01510         float   fs= 1.f;
01511         f.serial(fs);
01512     }
01513     else
01514         f.serial(Scale33);
01515     if( hasRot() )
01516     {
01517         f.serial(a11, a12, a13);
01518         f.serial(a21, a22, a23);
01519         f.serial(a31, a32, a33);
01520     }
01521     if( hasTrans() )
01522     {
01523         f.serial(a14, a24, a34);
01524     }
01525     else if(f.isReading())
01526     {
01527         // must reset because Pos must always be valid
01528         a14= a24= a34= 0;
01529     }
01530     if( hasProj() )
01531     {
01532         f.serial(a41, a42, a43, a44);
01533     }
01534 }
01535 
01536 
01537 // ======================================================================================================
01538 void        CMatrix::setArbitraryRotI(const CVector &idir)
01539 {
01540     // avoid gimbal lock. if idir == nearly K, use an other second lead vector
01541     if( fabs(idir.z)<0.9f )
01542         setRot(idir, CVector::J, CVector::K);
01543     else
01544         setRot(idir, CVector::J, CVector::I);
01545     normalize(CMatrix::XZY);
01546 }
01547 
01548 void        CMatrix::setArbitraryRotJ(const CVector &jdir)
01549 {
01550     // avoid gimbal lock. if jdir == nearly K, use an other second lead vector
01551     if(fabs(jdir.z)<0.9f)
01552         setRot(CVector::I, jdir, CVector::K);
01553     else
01554         setRot(CVector::I, jdir, CVector::J);
01555     normalize(CMatrix::YZX);
01556 }
01557 
01558 void        CMatrix::setArbitraryRotK(const CVector &kdir)
01559 {
01560     // avoid gimbal lock. if kdir == nearly I, use an other second lead vector
01561     if( fabs(kdir.y)<0.9f )
01562         setRot(CVector::I, CVector::J, kdir);
01563     else
01564         setRot(CVector::I, CVector::K, kdir);
01565     normalize(CMatrix::ZYX);
01566 }
01567 
01568 
01569 
01570 
01571 }
01572 

Generated on Thu Jan 7 08:26:34 2010 for NeL by  doxygen 1.6.1