# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

track_tcb.h

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 
00027 #ifndef NL_TRACK_H
00028 #error "internal file included from track.h"
00029 #endif
00030 
00031 // ***************************************************************************
00032 // ***************************************************************************
00033 // TCB Keyframes.
00034 // ***************************************************************************
00035 // ***************************************************************************
00036 
00037 
00038 // ***************************************************************************
00046 template<class CKeyT, class T, class TMapTimeCKey>
00047 class CTCBTools
00048 {
00049 protected:
00050         typedef typename TMapTimeCKey::iterator         TMapTimeCKeyIterator;
00051 
00052 
00053 
00055         void compileTCBEase(TMapTimeCKey &mapKey, bool loopMode)
00056         {
00057                 TMapTimeCKeyIterator    it= mapKey.begin();
00058                 for(;it!=mapKey.end();it++)
00059                 {
00060                         TMapTimeCKeyIterator    next= it;
00061                         next++;
00062 
00063                         // loop mgt. must compute ease from last to first (usefull if _RangeLock is false).
00064                         if(next==mapKey.end() && loopMode && mapKey.size()>1)
00065                                 next= mapKey.begin();
00066 
00067                         // Ease Precompute.
00068                         //=================
00069                         CKeyT   &key= it->second;
00070                         if(next!=mapKey.end())
00071                         {
00072                                 float   e0= it->second.EaseFrom;
00073                                 float   e1= next->second.EaseTo;
00074                                 float   s =  e0 + e1;
00075                                 
00076                                 // "normalize".
00077                                 if (s > 1.0f)
00078                                 {
00079                                         e0 = e0/s;
00080                                         e1 = e1/s;
00081                                 }
00082 
00083                                 // precalc ease factors.
00084                                 key.Ease0= e0;
00085                                 key.Ease1= e1;
00086                                 key.EaseK= 1/(2.0f - e0 - e1);
00087                                 if(e0)
00088                                         key.EaseKOverEase0= key.EaseK / e0;
00089                                 if(e1)
00090                                         key.EaseKOverEase1= key.EaseK / e1;
00091                         }
00092                         else
00093                         {
00094                                 // force ease() to just return d (see ease()).
00095                                 key.EaseK = 0.5f;
00096                         }
00097 
00098                 }
00099         }
00100 
00101         // ease time.
00102         float ease(const CKeyT *key, float d)
00103         {
00104                 if (d==0.0f || d==1.0f) return d;
00105                 // k==0.5f <=> e0+e1 == 0.
00106                 if (key->EaseK == 0.5f) return d;
00107 
00108                 if (d < key->Ease0)
00109                         return key->EaseKOverEase0 * d*d;
00110                 else if (d < 1.0f - key->Ease1)
00111                         return key->EaseK * (2.0f*d - key->Ease0);
00112                 else
00113                 {
00114                         d = 1.0f - d;
00115                         return 1.0f - key->EaseKOverEase1 * d*d;
00116                 }
00117         }
00118 
00119         // compute hermite factors.
00120         void computeHermiteBasis(float d, float hb[4]) 
00121         {
00122                 float d2,d3,a;
00123                 
00124                 d2 = d*d;
00125                 d3 = d2*d;
00126                 a  = 3.0f*d2 - 2.0f*d3;
00127                 hb[0] = 1.0f - a;
00128                 hb[1] = a;
00129                 hb[2] = d3 - 2.0f*d2 + d;
00130                 hb[3] = d3 - d2;
00131         }
00132 
00133 
00134         // compute TCB tangents factors.
00135         void computeTCBFactors(const CKeyT &key, float timeBefore, float time, float timeAfter, 
00136                 float rangeDelta, bool firstKey, bool endKey, bool isLoop, float &ksm, float &ksp, float &kdm, float &kdp)
00137         {
00138                 float fp,fn;
00139 
00140                 if(isLoop || (!firstKey && !endKey))
00141                 {
00142                         float   dtm;
00143                         // Compute Time deltas.
00144                         if (firstKey)
00145                         {
00146                                 dtm = 0.5f * (rangeDelta + timeAfter - time);
00147                                 fp = rangeDelta / dtm;
00148                                 fn = (timeAfter - time) / dtm;
00149                         }
00150                         else if (endKey)
00151                         {
00152                                 dtm = 0.5f * (rangeDelta + time - timeBefore);
00153                                 fp = rangeDelta / dtm;
00154                                 fn = (time - timeBefore) / dtm;
00155                         }
00156                         else
00157                         {
00158                                 dtm = 0.5f * (timeAfter - timeBefore);
00159                                 fp = (time - timeBefore) / dtm;
00160                                 fn = (timeAfter - time) / dtm;
00161                         }
00162                         float   c= (float)fabs( key.Continuity );
00163                         fp = fp + c - c * fp;
00164                         fn = fn + c - c * fn;
00165                 }
00166                 else
00167                 {
00168                         // firstkey and lastkey of not loop track.
00169                         fp = 1.0f;
00170                         fn = 1.0f;
00171                 }
00172 
00173                 // Compute tangents factors.
00174                 float   tm,cm,cp,bm,bp,tmcm,tmcp;
00175 
00176                 cm = 1.0f - key.Continuity;
00177                 tm = 0.5f * ( 1.0f - key.Tension );
00178                 cp = 2.0f - cm;
00179                 bm = 1.0f - key.Bias;
00180                 bp = 2.0f - bm;
00181                 tmcm = tm*cm;   tmcp = tm*cp;
00182 
00183                 // tgts factors.
00184                 ksm = tmcm*bp*fp;       ksp = tmcp*bm*fp;
00185                 kdm = tmcp*bp*fn;       kdp = tmcm*bm*fn;
00186 
00187         }
00188 
00189 };
00190 
00191 
00192 // ***************************************************************************
00200 template<class CKeyT, class T>
00201 class CTrackKeyFramerTCB : public ITrackKeyFramer<CKeyT>, private CTCBTools<CKeyT, T, std::map<CAnimationTime, CKeyT> >
00202 {
00203 public:
00204 
00206         virtual const IAnimatedValue& getValue () const
00207         {
00208                 return _Value;
00209         }
00210         
00211 protected:
00212 
00213 
00214         typedef typename CKeyT::TValueType              TKeyValueType;
00215 
00216 
00217 
00219         // @{
00220 
00222         virtual void evalKey (  const CKeyT* previous, const CKeyT* next,
00223                                                         CAnimationTime datePrevious, CAnimationTime dateNext,
00224                                                         CAnimationTime date )
00225         {
00226                 if(previous && next)
00227                 {
00228                         // lerp from previous to cur.
00229                         date-= datePrevious;
00230                         date*= previous->OODeltaTime;
00231                         NLMISC::clamp(date, 0,1);
00232                         
00233                         date = ease(previous, date);
00234 
00235                         float hb[4];
00236                         computeHermiteBasis(date, hb);
00237                         copyToValue(_Value.Value, 
00238                                 previous->Value*hb[0] + next->Value*hb[1] + 
00239                                 previous->TanFrom*hb[2] + next->TanTo*hb[3]);
00240                 }
00241                 else
00242                 {
00243                         if (previous)
00244                                 copyToValue(_Value.Value, previous->Value);
00245                         else
00246                                 if (next)
00247                                         copyToValue(_Value.Value, next->Value);
00248                 }
00249         }
00250 
00252         virtual void compile()
00253         {
00254                 ITrackKeyFramer<CKeyT>::compile();
00255 
00256                 // Ease Precompute.
00257                 compileTCBEase(_MapKey, getLoopMode());
00258 
00259 
00260                 // Tangents Precompute.
00261                 sint    nKeys= _MapKey.size();
00262                 if(nKeys<=1)
00263                         return;
00264 
00265                 TMapTimeCKey::iterator  it= _MapKey.begin();                            // first key.
00266                 TMapTimeCKey::iterator  itNext= it; itNext++;                           // second key.
00267                 TMapTimeCKey::iterator  itPrev= _MapKey.end(); itPrev--;        // last key.
00268 
00269                 if(nKeys==2 && !getLoopMode())
00270                 {
00271                         computeTCBKeyLinear( it->second, itNext->second );
00272                 }
00273                 else
00274                 {
00275                         // rangeDelta is the length of effective Range - length of LastKey-FirstKey.
00276                         // NB: if RangeLock, rangeDelta==0.
00277                         float   rangeDelta;
00278                         // NB: _RangeDelta has just been compiled in ITrackKeyFramer<CKeyT>::compile().
00279                         rangeDelta= getCompiledRangeDelta();
00280 
00281                         // Compute all middle keys.
00282                         for(;it!=_MapKey.end();)
00283                         {
00284                                 // Do the first key and the last key only in LoopMode.
00285                                 // NB: we are the last if itNext==_MapKey.begin().
00286                                 if(getLoopMode() || (it!=_MapKey.begin() && itNext!=_MapKey.begin()) )
00287                                 {
00288                                         computeTCBKey(itPrev->second, it->second, itNext->second, 
00289                                                 itPrev->first, it->first, itNext->first, rangeDelta, 
00290                                                 it==_MapKey.begin(), itNext==_MapKey.begin(), getLoopMode());
00291                                 }
00292 
00293                                 // Next key!!
00294                                 itPrev= it;
00295                                 it++;
00296                                 itNext++;
00297                                 // loop.
00298                                 if(itNext==_MapKey.end())
00299                                         itNext= _MapKey.begin();
00300                         }
00301 
00302                         // In not loop mode, compute first and last key, AFTER middle keys computed.
00303                         if(!getLoopMode())
00304                         {
00305                                 TMapTimeCKey::iterator  it0= _MapKey.begin();                           // first key.
00306                                 TMapTimeCKey::iterator  it1= it0; it1++;                                        // second key.
00307                                 TMapTimeCKey::iterator  itLast= _MapKey.end();itLast--;         // last key.
00308                                 TMapTimeCKey::iterator  itLastPrev= itLast;itLastPrev--;        // prev of last key.
00309 
00310                                 computeFirstKey(it0->second, it1->second);
00311                                 computeLastKey(itLast->second, itLastPrev->second);
00312                         }
00313                 }
00314         }
00315 
00316         // @}
00317 
00318 
00319 // *****************
00320 private:
00321         CAnimatedValueBlendable<T>      _Value;
00322 
00323 
00324 
00325         void computeTCBKey(CKeyT &keyBefore, CKeyT &key, CKeyT &keyAfter, float timeBefore, float time, float timeAfter, 
00326                 float rangeDelta, bool firstKey, bool endKey, bool isLoop)
00327         {
00328                 float   ksm,ksp,kdm,kdp;
00329 
00330                 // compute tangents factors.
00331                 computeTCBFactors(key, timeBefore, time, timeAfter, rangeDelta, firstKey, endKey, isLoop, ksm,ksp,kdm,kdp);
00332 
00333                 // Delta.
00334                 TKeyValueType   delm, delp;
00335                 delm = key.Value - keyBefore.Value;
00336                 delp = keyAfter.Value - key.Value;
00337 
00338                 // Tangents.
00339                 key.TanTo       = delm*ksm + delp*ksp;
00340                 key.TanFrom= delm*kdm + delp*kdp;
00341 
00342         }
00343 
00344         // compute 2 TCB keys for a not-loop track => "linear".
00345         void computeTCBKeyLinear(CKeyT &key0, CKeyT &key1)
00346         {
00347                 float f0, f1;
00348                 TKeyValueType   dv;
00349                 
00350                 f0 = 1.0f - key0.Tension;
00351                 f1 = 1.0f - key1.Tension;
00352                 dv = key1.Value - key0.Value;
00353                 key0.TanFrom= dv * f0;
00354                 key1.TanTo= dv * f1;
00355         }
00356 
00357         // compute this AFTER computing key1.
00358         void computeFirstKey(CKeyT &keyFirst, CKeyT &keyAfter)
00359         {
00360                 float tm;
00361                 tm = 0.5f * (1.0f - keyFirst.Tension);
00362                 keyFirst.TanFrom= tm * ((keyAfter.Value - keyFirst.Value) * 3.0f - keyAfter.TanTo);
00363         }
00364 
00365         // compute this AFTER computing key(n-2).
00366         void computeLastKey(CKeyT &keyLast, CKeyT &keyBefore)
00367         {
00368                 float tm;
00369                 tm = 0.5f * (1.0f - keyLast.Tension);
00370                 keyLast.TanTo= tm * ((keyLast.Value - keyBefore.Value) * 3.0f - keyBefore.TanFrom);
00371         }
00372 
00373 
00374 };
00375 
00376 
00377 // ***************************************************************************
00385 class CTrackKeyFramerTCB<CKeyTCBQuat, NLMISC::CAngleAxis> : public ITrackKeyFramer<CKeyTCBQuat>, 
00386         private CTCBTools<CKeyTCBQuat, NLMISC::CAngleAxis, std::map<CAnimationTime, CKeyTCBQuat> >
00387 {
00388 public:
00389 
00391         virtual const IAnimatedValue& getValue () const
00392         {
00393                 return _Value;
00394         }
00395         
00397         // @{
00398 
00400         virtual void evalKey (  const CKeyTCBQuat* previous, const CKeyTCBQuat* next, 
00401                                                         CAnimationTime datePrevious, CAnimationTime dateNext,
00402                                                         CAnimationTime date )
00403         {
00404                 if(previous && next)
00405                 {
00406                         // lerp from previous to cur.
00407                         date-= datePrevious;
00408                         date*= previous->OODeltaTime;
00409                         NLMISC::clamp(date, 0,1);
00410 
00411                         // ease.
00412                         date = ease(previous, date);
00413 
00414                         // quad slerp.
00415                         _Value.Value= CQuat::squadrev(next->LocalAngleAxis, previous->Quat, previous->A, next->B, next->Quat, date);
00416                 }
00417                 else
00418                 {
00419                         if (previous)
00420                                 _Value.Value= previous->Quat;
00421                         else
00422                                 if (next)
00423                                         _Value.Value= next->Quat;
00424                 }
00425 
00426         }
00427 
00429         virtual void compile()
00430         {
00431                 ITrackKeyFramer<CKeyTCBQuat>::compile();
00432 
00433                 // Ease Precompute.
00434                 compileTCBEase(_MapKey, getLoopMode());
00435 
00436                 TMapTimeCKey::iterator  it;
00437                 TMapTimeCKey::iterator  itNext;
00438                 TMapTimeCKey::iterator  itPrev;
00439 
00440                 // Compute absolute quaternions.
00441                 for (it= _MapKey.begin();it!=_MapKey.end();)
00442                 {
00443                         CKeyTCBQuat             &key= it->second;
00444 
00445                         // Compute Local AngleAxis.
00446                         if(it!= _MapKey.begin())
00447                         {
00448                                 NLMISC::CMatrix         mat;
00449                                 mat.setRot(itPrev->second.Quat);
00450                                 mat.invert();
00451                                 key.LocalAngleAxis.Axis= mat*key.Value.Axis;
00452                                 key.LocalAngleAxis.Angle= key.Value.Angle;
00453                         }
00454                         else
00455                                 key.LocalAngleAxis= key.Value;
00456 
00457 
00458                         key.LocalAngleAxis.Axis.normalize();
00459                         // make angle positive.
00460                         if(key.LocalAngleAxis.Angle<0.f)
00461                         {
00462                                 key.LocalAngleAxis.Axis= -key.LocalAngleAxis.Axis;
00463                                 key.LocalAngleAxis.Angle= -key.LocalAngleAxis.Angle;
00464                         }
00465 
00466                         // relative quat
00467                         key.Quat.setAngleAxis(key.LocalAngleAxis);
00468 
00469                         // absolute quat
00470                         if (it!= _MapKey.begin())
00471                                 key.Quat = itPrev->second.Quat * key.Quat;
00472 
00473                         // next key.
00474                         itPrev= it;
00475                         it++;
00476                 }
00477 
00478                 // Tangents Precompute.
00479                 sint    nKeys= _MapKey.size();
00480                 if(nKeys<=1)
00481                         return;
00482 
00483                 // rangeDelta is the length of effective Range - length of LastKey-FirstKey.
00484                 // NB: if RangeLock, rangeDelta==0.
00485                 float   rangeDelta;
00486                 // NB: _RangeDelta has just been compiled in ITrackKeyFramer<CKeyTCBQuat>::compile().
00487                 rangeDelta= getCompiledRangeDelta();
00488 
00489                 it= _MapKey.begin();                            // first key.
00490                 itNext= it; itNext++;                           // second key.
00491                 itPrev= _MapKey.end(); itPrev--;        // last key.
00492 
00493                 // Compute all keys.
00494                 for(;it!=_MapKey.end();)
00495                 {
00496                         // NB: we are the last key if itNext==_MapKey.begin().
00497                         computeTCBKey(itPrev->second, it->second, itNext->second, 
00498                                 itPrev->first, it->first, itNext->first, rangeDelta, it==_MapKey.begin(), itNext==_MapKey.begin(), getLoopMode());
00499 
00500                         // Next key!!
00501                         itPrev= it;
00502                         it++;
00503                         itNext++;
00504                         // loop.
00505                         if(itNext==_MapKey.end())
00506                                 itNext= _MapKey.begin();
00507                 }
00508 
00509         }
00510 
00511         // @}
00512 
00513 
00514 // *****************
00515 private:
00516         CAnimatedValueBlendable<CQuat>  _Value;
00517 
00518 
00519         void computeTCBKey(CKeyTCBQuat &keyBefore, CKeyTCBQuat &key, CKeyTCBQuat &keyAfter, float timeBefore, float time, float timeAfter, 
00520                 float rangeDelta, bool firstKey, bool endKey, bool isLoop) 
00521         {
00522                 CQuat  qp, qm;
00523                 
00524                 // compute qm.
00525                 if (!firstKey || isLoop)
00526                 {
00527                         float   angle= key.LocalAngleAxis.Angle;
00528                         CVector &axis= key.LocalAngleAxis.Axis;
00529 
00530                         if (angle > 2*NLMISC::Pi- NLMISC::QuatEpsilon)
00531                         {
00532                                 qm.set(axis.x, axis.y, axis.z, 0.0f);
00533                                 qm = qm.log();
00534                         }
00535                         else
00536                         {
00537                                 CQuat   qprev= keyBefore.Quat;
00538                                 qprev.makeClosest(key.Quat);
00539                                 qm = CQuat::lnDif(qprev, key.Quat);
00540                         }
00541                 }
00542                 
00543                 // compute qp.
00544                 if (!endKey || isLoop)
00545                 {
00546                         float   angle= keyAfter.LocalAngleAxis.Angle;
00547                         CVector &axis= keyAfter.LocalAngleAxis.Axis;
00548 
00549                         if (angle > 2*NLMISC::Pi- NLMISC::QuatEpsilon)
00550                         {
00551                                 qp.set(axis.x, axis.y, axis.z, 0.0f);
00552                                 qp = qp.log();
00553                         }
00554                         else
00555                         {
00556                                 CQuat   qnext= keyAfter.Quat;
00557                                 qnext.makeClosest(key.Quat);
00558                                 qp = CQuat::lnDif(key.Quat, qnext);
00559                         }
00560                 }
00561                 
00562                 // not loop mgt.
00563                 if (firstKey && !isLoop)
00564                         qm = qp;
00565                 if (endKey && !isLoop)
00566                         qp = qm;
00567 
00568 
00569                 // compute tangents factors.
00570                 float   ksm, ksp, kdm, kdp;
00571                 computeTCBFactors(key, timeBefore, time, timeAfter, rangeDelta, firstKey, endKey, isLoop, ksm,ksp,kdm,kdp);
00572 
00573 
00574                 // A/B.
00575                 CQuat   qa, qb;
00576                 qb= (qm * (1.0f-ksm) + qp * (-ksp)        ) * 0.5f;
00577                 qa= (qm * kdm            + qp * (kdp-1.0f) ) * 0.5f;
00578                 qa = qa.exp();
00579                 qb = qb.exp();
00580 
00581                 key.A = key.Quat * qa;
00582                 key.B = key.Quat * qb;
00583         }
00584 
00585 
00586 
00587 };
00588 
00589