00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "std3d.h"
00027
00028 #include "3d/channel_mixer.h"
00029 #include "3d/track.h"
00030 #include "3d/animatable.h"
00031 #include "3d/skeleton_weight.h"
00032 #include "nel/misc/debug.h"
00033 #include "nel/misc/common.h"
00034
00035 using namespace NLMISC;
00036 using namespace std;
00037
00038 namespace NL3D
00039 {
00040
00041
00042
00043 CChannelMixer::CChannelMixer()
00044 {
00045
00046 _FirstChannelGlobal=NULL;
00047 _FirstChannelDetail=NULL;
00048
00049
00050 _AnimationSet=NULL;
00051
00052
00053 _Dirt=false;
00054 _ListToEvalDirt= false;
00055
00056
00057 _LastEvalDetailDate= -1;
00058 }
00059
00060
00061
00062 void CChannelMixer::setAnimationSet (const CAnimationSet* animationSet)
00063 {
00064
00065 _AnimationSet=animationSet;
00066
00067
00068 resetChannels();
00069 }
00070
00071
00072
00073 const CAnimationSet* CChannelMixer::getAnimationSet () const
00074 {
00075
00076 return _AnimationSet;
00077 }
00078
00079
00080
00081 void CChannelMixer::eval (bool detail, uint64 evalDetailDate)
00082 {
00083
00084 uint numActive=0;
00085 uint activeSlot[NumAnimationSlot];
00086
00087 if(detail && (sint64)evalDetailDate== _LastEvalDetailDate)
00088 return;
00089
00090
00091 if(_Dirt)
00092 {
00093 refreshList();
00094 cleanAll();
00095 }
00096
00097
00098 if(_ListToEvalDirt)
00099 {
00100 refreshListToEval();
00101 nlassert(!_ListToEvalDirt);
00102 }
00103
00104
00105 for (uint s=0; s<NumAnimationSlot; s++)
00106 {
00107
00108 if (!_SlotArray[s].isEmpty() && _SlotArray[s]._Weight>0)
00109
00110 activeSlot[numActive++]=s;
00111 }
00112
00113
00114 if(numActive==0)
00115 return;
00116
00117
00118 CChannel **channelArrayPtr = 0;
00119 uint numChans;
00120 if(detail)
00121 {
00122 numChans= _DetailListToEval.size();
00123 if(numChans)
00124 channelArrayPtr= &_DetailListToEval[0];
00125
00126 _LastEvalDetailDate= evalDetailDate;
00127 }
00128 else
00129 {
00130 numChans= _GlobalListToEval.size();
00131 if(numChans)
00132 channelArrayPtr= &_GlobalListToEval[0];
00133 }
00134
00135
00136 for(;numChans>0; numChans--, channelArrayPtr++)
00137 {
00138 CChannel *pChannel= *channelArrayPtr;
00139
00140
00141 CQuat firstQuat;
00142
00143
00144 bool bFirst=true;
00145
00146
00147 float lastBlend=0.0;
00148
00149
00150 for (uint a=0; a<numActive; a++)
00151 {
00152
00153 uint slot=activeSlot[a];
00154
00155
00156 float blend=pChannel->_Weights[slot]*_SlotArray[slot]._Weight;
00157
00158 if(blend!=0.0f)
00159 {
00160
00161 ((ITrack*)pChannel->_Tracks[slot])->eval (_SlotArray[slot]._Time);
00162
00163
00164 if (bFirst)
00165 {
00166
00167 if (pChannel->_IsQuat)
00168 {
00169 CAnimatedValueBlendable<NLMISC::CQuat> *pQuatValue=(CAnimatedValueBlendable<NLMISC::CQuat>*)&pChannel->_Tracks[slot]->getValue();
00170 firstQuat=pQuatValue->Value;
00171 }
00172
00173
00174 pChannel->_Value->affect (pChannel->_Tracks[slot]->getValue());
00175
00176
00177 lastBlend=blend;
00178
00179
00180 bFirst=false;
00181 }
00182 else
00183 {
00184
00185 if (pChannel->_IsQuat)
00186 {
00187 CAnimatedValueBlendable<NLMISC::CQuat> *pQuatValue=(CAnimatedValueBlendable<NLMISC::CQuat>*)&pChannel->_Tracks[slot]->getValue();
00188 pQuatValue->Value.makeClosest (firstQuat);
00189 }
00190
00191
00192 pChannel->_Value->blend (pChannel->_Tracks[slot]->getValue(), lastBlend/(lastBlend+blend));
00193
00194
00195 lastBlend+=blend;
00196 }
00197 }
00198
00199
00200 }
00201
00202
00203 pChannel->_Object->touch (pChannel->_ValueId, pChannel->_OwnerValueId);
00204 }
00205 }
00206
00207
00208
00209 sint CChannelMixer::addChannel (const string& channelName, IAnimatable* animatable, IAnimatedValue* value, ITrack* defaultValue, uint32 valueId, uint32 ownerValueId, bool detail)
00210 {
00211
00212 nlassert (_AnimationSet);
00213
00214
00215 nlassert (animatable);
00216 nlassert (value);
00217 nlassert (defaultValue);
00218
00219
00220 uint iDInAnimationSet=_AnimationSet->getChannelIdByName (channelName);
00221
00222
00223 if (iDInAnimationSet!=CAnimationSet::NotFound)
00224 {
00225
00226 CChannel entry;
00227
00228
00229 entry._ChannelName=channelName;
00230
00231
00232 entry._Object=animatable;
00233
00234
00235 entry._Value=value;
00236
00237
00238 entry._IsQuat= (typeid (*(entry._Value))==typeid (CAnimatedValueBlendable<NLMISC::CQuat>))!=0;
00239
00240
00241
00242 entry._DefaultTracks=defaultValue;
00243
00244
00245 entry._ValueId=valueId;
00246
00247
00248 entry._OwnerValueId=ownerValueId;
00249
00250
00251 entry._Detail= detail;
00252
00253
00254 for(sint s=0;s<NumAnimationSlot;s++)
00255 {
00256 entry._Weights[s]= 1.0f;
00257 entry._Tracks[s]= entry._DefaultTracks;
00258 }
00259
00260
00261 _Channels[iDInAnimationSet]= entry;
00262
00263
00264 dirtAll ();
00265
00266
00267 entry._Value->affect (entry._DefaultTracks->getValue());
00268
00269
00270 entry._Object->touch (entry._ValueId, entry._OwnerValueId);
00271
00272
00273 return iDInAnimationSet;
00274 }
00275 else
00276 {
00277
00278 return -1;
00279 }
00280 }
00281
00282
00283
00284 void CChannelMixer::resetChannels ()
00285 {
00286 _Channels.clear();
00287 dirtAll ();
00288 }
00289
00290
00291
00292 void CChannelMixer::enableChannel (uint channelId, bool enable)
00293 {
00294 std::map<uint, CChannel>::iterator it= _Channels.find(channelId);
00295 if(it!=_Channels.end())
00296 {
00297 it->second._EnableFlags &= ~CChannel::EnableUserFlag;
00298 if(enable)
00299 it->second._EnableFlags |= CChannel::EnableUserFlag;
00300
00301
00302 _ListToEvalDirt= true;
00303 }
00304 }
00305
00306
00307
00308 bool CChannelMixer::isChannelEnabled (uint channelId) const
00309 {
00310 std::map<uint, CChannel>::const_iterator it= _Channels.find(channelId);
00311 if(it!=_Channels.end())
00312 {
00313 return (it->second._EnableFlags & CChannel::EnableUserFlag) != 0;
00314 }
00315 else
00316 return false;
00317 }
00318
00319
00320
00321 void CChannelMixer::lodEnableChannel (uint channelId, bool enable)
00322 {
00323 std::map<uint, CChannel>::iterator it= _Channels.find(channelId);
00324 if(it!=_Channels.end())
00325 {
00326 it->second._EnableFlags &= ~CChannel::EnableLodFlag;
00327 if(enable)
00328 it->second._EnableFlags |= CChannel::EnableLodFlag;
00329
00330
00331 _ListToEvalDirt= true;
00332 }
00333 }
00334
00335
00336
00337 bool CChannelMixer::isChannelLodEnabled (uint channelId) const
00338 {
00339 std::map<uint, CChannel>::const_iterator it= _Channels.find(channelId);
00340 if(it!=_Channels.end())
00341 {
00342 return (it->second._EnableFlags & CChannel::EnableLodFlag) != 0;
00343 }
00344 else
00345 return false;
00346 }
00347
00348
00349
00350
00351
00352 void CChannelMixer::setSlotAnimation (uint slot, uint animation)
00353 {
00354
00355 nlassert (slot<NumAnimationSlot);
00356
00357
00358 nlassert (_AnimationSet);
00359
00360
00361 const CAnimation* pAnimation=_AnimationSet->getAnimation (animation);
00362
00363
00364 if (_SlotArray[slot]._Animation!=pAnimation)
00365 {
00366
00367 _SlotArray[slot]._Animation=pAnimation;
00368
00369
00370 _SlotArray[slot]._Dirt=true;
00371
00372
00373 _Dirt=true;
00374 }
00375 }
00376
00377
00378
00379 const CAnimation *CChannelMixer::getSlotAnimation(uint slot) const
00380 {
00381 nlassert(slot < NumAnimationSlot);
00382 return _SlotArray[slot]._Animation;
00383 }
00384
00385
00386
00387
00388 void CChannelMixer::emptySlot (uint slot)
00389 {
00390
00391 nlassert (slot<NumAnimationSlot);
00392
00393
00394 if (!_SlotArray[slot].isEmpty ())
00395 {
00396
00397 _SlotArray[slot].empty ();
00398
00399
00400 _SlotArray[slot]._Dirt=true;
00401
00402
00403 _Dirt=true;
00404 }
00405 }
00406
00407
00408
00409 void CChannelMixer::resetSlots ()
00410 {
00411
00412 for (uint s=0; s<NumAnimationSlot; s++)
00413
00414 emptySlot (s);
00415 }
00416
00417
00418
00419 void CChannelMixer::applySkeletonWeight (uint slot, uint skeleton, bool invert)
00420 {
00421
00422 nlassert (slot<NumAnimationSlot);
00423
00424
00425 nlassert (_AnimationSet);
00426
00427
00428 const CSkeletonWeight *pSkeleton=_AnimationSet->getSkeletonWeight (skeleton);
00429
00430
00431 if ((pSkeleton!=_SlotArray[slot]._SkeletonWeight)||(invert!=_SlotArray[slot]._InvertedSkeletonWeight))
00432 {
00433
00434 _SlotArray[slot]._SkeletonWeight=pSkeleton;
00435 _SlotArray[slot]._InvertedSkeletonWeight=invert;
00436
00437
00438 uint sizeSkel=pSkeleton->getNumNode ();
00439
00440
00441 for (uint n=0; n<sizeSkel; n++)
00442 {
00443
00444 const string& channelName=pSkeleton->getNodeName (n);
00445
00446
00447 uint channelId=_AnimationSet->getChannelIdByName (channelName);
00448
00449
00450 if (channelId!=CAnimationSet::NotFound)
00451 {
00452
00453 float weight=pSkeleton->getNodeWeight (n);
00454
00455
00456 std::map<uint, CChannel>::iterator ite=_Channels.find(channelId);
00457 if (ite!=_Channels.end())
00458 ite->second._Weights[slot]=invert?1.f-weight:weight;
00459 }
00460 }
00461 }
00462 }
00463
00464
00465
00466 void CChannelMixer::resetSkeletonWeight (uint slot)
00467 {
00468
00469 nlassert (slot<NumAnimationSlot);
00470
00471
00472 if (_SlotArray[slot]._SkeletonWeight!=NULL)
00473 {
00474
00475 _SlotArray[slot]._SkeletonWeight=NULL;
00476 _SlotArray[slot]._InvertedSkeletonWeight=false;
00477
00478
00479 map<uint, CChannel>::iterator itChannel;
00480 for(itChannel= _Channels.begin(); itChannel!=_Channels.end();itChannel++)
00481 {
00482
00483 (*itChannel).second._Weights[slot]=1.f;
00484 }
00485 }
00486 }
00487
00488
00489
00490 void CChannelMixer::cleanAll ()
00491 {
00492
00493 for (uint s=0; s<NumAnimationSlot; s++)
00494 {
00495
00496 _SlotArray[s]._Dirt=false;
00497 }
00498
00499
00500 _Dirt=false;
00501 }
00502
00503
00504
00505 void CChannelMixer::dirtAll ()
00506 {
00507
00508 for (uint s=0; s<NumAnimationSlot; s++)
00509 {
00510
00511 if (!_SlotArray[s].isEmpty())
00512 {
00513
00514 _SlotArray[s]._Dirt=true;
00515
00516
00517 _Dirt=true;
00518 }
00519 }
00520 }
00521
00522
00523
00524 void CChannelMixer::refreshList ()
00525 {
00526
00527 uint numAdd=0;
00528 uint addSlot[NumAnimationSlot];
00529
00530
00531 uint numStay=0;
00532 uint staySlot[NumAnimationSlot];
00533
00534
00535 uint s;
00536 for (s=0; s<NumAnimationSlot; s++)
00537 {
00538
00539 if ((_SlotArray[s]._Dirt)&&(!_SlotArray[s].isEmpty()))
00540
00541 addSlot[numAdd++]=s;
00542
00543
00544 if ((!_SlotArray[s]._Dirt)&&(!_SlotArray[s].isEmpty()))
00545
00546 staySlot[numStay++]=s;
00547 }
00548
00549
00550 CChannel **lastPointerGlobal=&_FirstChannelGlobal;
00551 CChannel **lastPointerDetail=&_FirstChannelDetail;
00552
00553
00554
00555 map<uint, CChannel>::iterator itChannel;
00556 for(itChannel= _Channels.begin(); itChannel!=_Channels.end();itChannel++)
00557 {
00558 CChannel &channel= (*itChannel).second;
00559
00560
00561 bool add=false;
00562
00563
00564 for (s=0; s<numAdd; s++)
00565 {
00566
00567 uint iDTrack=_SlotArray[addSlot[s]]._Animation->getIdTrackByName (channel._ChannelName);
00568
00569
00570 if (iDTrack!=CAnimation::NotFound)
00571 {
00572
00573 channel._Tracks[addSlot[s]]=_SlotArray[addSlot[s]]._Animation->getTrack (iDTrack);
00574
00575
00576 add=true;
00577 }
00578 else
00579 {
00580
00581 channel._Tracks[addSlot[s]]=channel._DefaultTracks;
00582 }
00583 }
00584
00585
00586 if (!add)
00587 {
00588
00589 if (channel._InTheList)
00590 {
00591
00592
00593
00594 for (s=0; s<numStay; s++)
00595 {
00596
00597 if (channel._Tracks[staySlot[s]]!=channel._DefaultTracks)
00598 {
00599
00600 add=true;
00601
00602
00603 break;
00604 }
00605 }
00606
00607
00608 if (!add)
00609 {
00610
00611 channel._Value->affect (channel._DefaultTracks->getValue());
00612 channel._Object->touch (channel._ValueId, channel._OwnerValueId);
00613 }
00614 }
00615 }
00616
00617
00618 if (add)
00619 {
00620
00621 channel._InTheList=true;
00622
00623 if(channel._Detail)
00624 {
00625
00626 *lastPointerDetail=&channel;
00627
00628 lastPointerDetail=&channel._Next;
00629 }
00630 else
00631 {
00632
00633 *lastPointerGlobal=&channel;
00634
00635 lastPointerGlobal=&channel._Next;
00636 }
00637
00638 }
00639 else
00640 {
00641
00642 channel._InTheList=false;
00643 }
00644 }
00645
00646
00647 *lastPointerGlobal=NULL;
00648 *lastPointerDetail=NULL;
00649
00650
00651 _ListToEvalDirt= true;
00652 }
00653
00654
00655
00656 void CChannelMixer::refreshListToEval ()
00657 {
00658 CChannel* pChannel;
00659
00660
00661
00662
00663
00664 _GlobalListToEval.clear();
00665 _GlobalListToEval.reserve(_Channels.size());
00666 pChannel=_FirstChannelGlobal;
00667 while(pChannel)
00668 {
00669
00670 if(pChannel->_EnableFlags == CChannel::EnableAllFlag)
00671 _GlobalListToEval.push_back(pChannel);
00672
00673 pChannel= pChannel->_Next;
00674 }
00675
00676
00677 _DetailListToEval.clear();
00678 _DetailListToEval.reserve(_Channels.size());
00679 pChannel=_FirstChannelDetail;
00680 while(pChannel)
00681 {
00682
00683 if(pChannel->_EnableFlags == CChannel::EnableAllFlag)
00684 _DetailListToEval.push_back(pChannel);
00685
00686 pChannel= pChannel->_Next;
00687 }
00688
00689
00690 _ListToEvalDirt= false;
00691 }
00692
00693
00694 void CChannelMixer::resetEvalDetailDate()
00695 {
00696 _LastEvalDetailDate= -1;
00697 }
00698
00699
00700 }