00001
00007 00008 00009 00010 00011 00012 00013 00014 00015 00016 00017 00018 00019 00020 00021 00022 00023 00024
00025
00026
00027 #ifndef NL_TRACK_H
00028 #error "internal file included from track.h"
00029 #endif
00030
00031
00032
00033
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
00064 if(next==mapKey.end() && loopMode && mapKey.size()>1)
00065 next= mapKey.begin();
00066
00067
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
00077 if (s > 1.0f)
00078 {
00079 e0 = e0/s;
00080 e1 = e1/s;
00081 }
00082
00083
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
00095 key.EaseK = 0.5f;
00096 }
00097
00098 }
00099 }
00100
00101
00102 float ease(const CKeyT *key, float d)
00103 {
00104 if (d==0.0f || d==1.0f) return d;
00105
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
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
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
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
00169 fp = 1.0f;
00170 fn = 1.0f;
00171 }
00172
00173
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
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
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
00257 compileTCBEase(_MapKey, getLoopMode());
00258
00259
00260
00261 sint nKeys= _MapKey.size();
00262 if(nKeys<=1)
00263 return;
00264
00265 TMapTimeCKey::iterator it= _MapKey.begin();
00266 TMapTimeCKey::iterator itNext= it; itNext++;
00267 TMapTimeCKey::iterator itPrev= _MapKey.end(); itPrev--;
00268
00269 if(nKeys==2 && !getLoopMode())
00270 {
00271 computeTCBKeyLinear( it->second, itNext->second );
00272 }
00273 else
00274 {
00275
00276
00277 float rangeDelta;
00278
00279 rangeDelta= getCompiledRangeDelta();
00280
00281
00282 for(;it!=_MapKey.end();)
00283 {
00284
00285
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
00294 itPrev= it;
00295 it++;
00296 itNext++;
00297
00298 if(itNext==_MapKey.end())
00299 itNext= _MapKey.begin();
00300 }
00301
00302
00303 if(!getLoopMode())
00304 {
00305 TMapTimeCKey::iterator it0= _MapKey.begin();
00306 TMapTimeCKey::iterator it1= it0; it1++;
00307 TMapTimeCKey::iterator itLast= _MapKey.end();itLast--;
00308 TMapTimeCKey::iterator itLastPrev= itLast;itLastPrev--;
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
00331 computeTCBFactors(key, timeBefore, time, timeAfter, rangeDelta, firstKey, endKey, isLoop, ksm,ksp,kdm,kdp);
00332
00333
00334 TKeyValueType delm, delp;
00335 delm = key.Value - keyBefore.Value;
00336 delp = keyAfter.Value - key.Value;
00337
00338
00339 key.TanTo = delm*ksm + delp*ksp;
00340 key.TanFrom= delm*kdm + delp*kdp;
00341
00342 }
00343
00344
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
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
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
00407 date-= datePrevious;
00408 date*= previous->OODeltaTime;
00409 NLMISC::clamp(date, 0,1);
00410
00411
00412 date = ease(previous, date);
00413
00414
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
00434 compileTCBEase(_MapKey, getLoopMode());
00435
00436 TMapTimeCKey::iterator it;
00437 TMapTimeCKey::iterator itNext;
00438 TMapTimeCKey::iterator itPrev;
00439
00440
00441 for (it= _MapKey.begin();it!=_MapKey.end();)
00442 {
00443 CKeyTCBQuat &key= it->second;
00444
00445
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
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
00467 key.Quat.setAngleAxis(key.LocalAngleAxis);
00468
00469
00470 if (it!= _MapKey.begin())
00471 key.Quat = itPrev->second.Quat * key.Quat;
00472
00473
00474 itPrev= it;
00475 it++;
00476 }
00477
00478
00479 sint nKeys= _MapKey.size();
00480 if(nKeys<=1)
00481 return;
00482
00483
00484
00485 float rangeDelta;
00486
00487 rangeDelta= getCompiledRangeDelta();
00488
00489 it= _MapKey.begin();
00490 itNext= it; itNext++;
00491 itPrev= _MapKey.end(); itPrev--;
00492
00493
00494 for(;it!=_MapKey.end();)
00495 {
00496
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
00501 itPrev= it;
00502 it++;
00503 itNext++;
00504
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
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
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
00563 if (firstKey && !isLoop)
00564 qm = qp;
00565 if (endKey && !isLoop)
00566 qp = qm;
00567
00568
00569
00570 float ksm, ksp, kdm, kdp;
00571 computeTCBFactors(key, timeBefore, time, timeAfter, rangeDelta, firstKey, endKey, isLoop, ksm,ksp,kdm,kdp);
00572
00573
00574
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