| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042 |
- //
- // Copyright (c) 2008-2016 the Urho3D project.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- //
- #include "../Precompiled.h"
- #include "../Core/Context.h"
- #include "../Core/Profiler.h"
- #include "../Graphics/AnimatedModel.h"
- #include "../Graphics/Animation.h"
- #include "../Graphics/AnimationController.h"
- #include "../Graphics/AnimationState.h"
- #include "../IO/FileSystem.h"
- #include "../IO/Log.h"
- #include "../IO/MemoryBuffer.h"
- #include "../Resource/ResourceCache.h"
- #include "../Scene/Scene.h"
- #include "../Scene/SceneEvents.h"
- #include "../DebugNew.h"
- namespace Atomic
- {
- static const unsigned char CTRL_LOOPED = 0x1;
- static const unsigned char CTRL_STARTBONE = 0x2;
- static const unsigned char CTRL_AUTOFADE = 0x4;
- static const unsigned char CTRL_SETTIME = 0x08;
- static const unsigned char CTRL_SETWEIGHT = 0x10;
- static const unsigned char CTRL_REMOVEONCOMPLETION = 0x20;
- static const unsigned char CTRL_ADDITIVE = 0x40;
- static const float EXTRA_ANIM_FADEOUT_TIME = 0.1f;
- static const float COMMAND_STAY_TIME = 0.25f;
- static const unsigned MAX_NODE_ANIMATION_STATES = 256;
- extern const char* LOGIC_CATEGORY;
- AnimationController::AnimationController(Context* context) :
- Component(context),
- // ATOMIC BEGIN
- animationResourcesAttr_(Animation::GetTypeStatic()),
- autoPlay_(true),
- autoPlayed_(false)
- // ATOMIC END
- {
- }
- AnimationController::~AnimationController()
- {
- }
- void AnimationController::RegisterObject(Context* context)
- {
- context->RegisterFactory<AnimationController>(LOGIC_CATEGORY);
- ATOMIC_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
- ATOMIC_MIXED_ACCESSOR_ATTRIBUTE("Animations", GetAnimationsAttr, SetAnimationsAttr, VariantVector, Variant::emptyVariantVector,
- AM_FILE | AM_NOEDIT);
- ATOMIC_ACCESSOR_ATTRIBUTE("Network Animations", GetNetAnimationsAttr, SetNetAnimationsAttr, PODVector<unsigned char>,
- Variant::emptyBuffer, AM_NET | AM_LATESTDATA | AM_NOEDIT);
- ATOMIC_MIXED_ACCESSOR_ATTRIBUTE("Node Animation States", GetNodeAnimationStatesAttr, SetNodeAnimationStatesAttr, VariantVector,
- Variant::emptyVariantVector, AM_FILE | AM_NOEDIT);
- // ATOMIC BEGIN
- ATOMIC_MIXED_ACCESSOR_ATTRIBUTE("Animation", GetAnimationAttr, SetAnimationAttr, ResourceRef, ResourceRef(Animation::GetTypeStatic()), AM_DEFAULT);
- ATOMIC_ATTRIBUTE("Autoplay", bool, autoPlay_, true, AM_DEFAULT);
- ATOMIC_ACCESSOR_ATTRIBUTE("AnimationResources", GetAnimationResourcesAttr, SetAnimationResourcesAttr, ResourceRefList, ResourceRefList(Animation::GetTypeStatic()), AM_DEFAULT);
- // ATOMIC END
- }
- void AnimationController::OnSetEnabled()
- {
- Scene* scene = GetScene();
- if (scene)
- {
- if (IsEnabledEffective())
- SubscribeToEvent(scene, E_SCENEPOSTUPDATE, ATOMIC_HANDLER(AnimationController, HandleScenePostUpdate));
- else
- UnsubscribeFromEvent(scene, E_SCENEPOSTUPDATE);
- }
- }
- void AnimationController::Update(float timeStep)
- {
- // ATOMIC BEGIN
- if (autoPlay_ && !autoPlayed_ && animation_.NotNull())
- {
- autoPlayed_ = true;
- Play(animation_->GetAnimationName(), 0, true);
- }
- // ATOMIC END
- // Loop through animations
- for (unsigned i = 0; i < animations_.Size();)
- {
- AnimationControl& ctrl = animations_[i];
- AnimationState* state = GetAnimationState(ctrl.hash_);
- bool remove = false;
- if (!state)
- remove = true;
- else
- {
- // Advance the animation
- if (ctrl.speed_ != 0.0f)
- state->AddTime(ctrl.speed_ * timeStep);
- float targetWeight = ctrl.targetWeight_;
- float fadeTime = ctrl.fadeTime_;
- // If non-looped animation at the end, activate autofade as applicable
- if (!state->IsLooped() && state->GetTime() >= state->GetLength() && ctrl.autoFadeTime_ > 0.0f)
- {
- targetWeight = 0.0f;
- fadeTime = ctrl.autoFadeTime_;
- }
- // Process weight fade
- float currentWeight = state->GetWeight();
- if (currentWeight != targetWeight)
- {
- if (fadeTime > 0.0f)
- {
- float weightDelta = 1.0f / fadeTime * timeStep;
- if (currentWeight < targetWeight)
- currentWeight = Min(currentWeight + weightDelta, targetWeight);
- else if (currentWeight > targetWeight)
- currentWeight = Max(currentWeight - weightDelta, targetWeight);
- state->SetWeight(currentWeight);
- }
- else
- state->SetWeight(targetWeight);
- }
- // Remove if weight zero and target weight zero
- if (state->GetWeight() == 0.0f && (targetWeight == 0.0f || fadeTime == 0.0f) && ctrl.removeOnCompletion_)
- remove = true;
- }
- // Decrement the command time-to-live values
- if (ctrl.setTimeTtl_ > 0.0f)
- ctrl.setTimeTtl_ = Max(ctrl.setTimeTtl_ - timeStep, 0.0f);
- if (ctrl.setWeightTtl_ > 0.0f)
- ctrl.setWeightTtl_ = Max(ctrl.setWeightTtl_ - timeStep, 0.0f);
- if (remove)
- {
- if (state)
- RemoveAnimationState(state);
- animations_.Erase(i);
- MarkNetworkUpdate();
- }
- else
- ++i;
- }
- // Node hierarchy animations need to be applied manually
- for (Vector<SharedPtr<AnimationState> >::Iterator i = nodeAnimationStates_.Begin(); i != nodeAnimationStates_.End(); ++i)
- (*i)->Apply();
- }
- bool AnimationController::Play(const String& name, unsigned char layer, bool looped, float fadeInTime)
- {
- // ATOMIC BEGIN
- Animation* newAnimation = 0;
- // Check if we're using attached animation resource
- if (animation_.NotNull() && animation_->GetAnimationName() == name)
- {
- newAnimation = animation_;
- }
- else
- {
- for (unsigned i = 0; i < animationResources_.Size(); i++)
- {
- if (name == animationResources_[i]->GetAnimationName())
- {
- newAnimation = animationResources_[i];
- break;
- }
- }
- }
- // Get the animation resource first to be able to get the canonical resource name
- // (avoids potential adding of duplicate animations)
- if (!newAnimation)
- newAnimation = GetSubsystem<ResourceCache>()->GetResource<Animation>(name);
- if (!newAnimation)
- return false;
- // ATOMIC END
- // Check if already exists
- unsigned index;
- AnimationState* state;
- FindAnimation(newAnimation->GetName(), index, state);
- if (!state)
- {
- state = AddAnimationState(newAnimation);
- if (!state)
- return false;
- }
- if (index == M_MAX_UNSIGNED)
- {
- AnimationControl newControl;
- newControl.name_ = newAnimation->GetName();
- newControl.hash_ = newAnimation->GetNameHash();
- animations_.Push(newControl);
- index = animations_.Size() - 1;
- }
- state->SetLayer(layer);
- state->SetLooped(looped);
- animations_[index].targetWeight_ = 1.0f;
- animations_[index].fadeTime_ = fadeInTime;
- MarkNetworkUpdate();
- return true;
- }
- bool AnimationController::PlayExclusive(const String& name, unsigned char layer, bool looped, float fadeTime)
- {
- FadeOthers(name, 0.0f, fadeTime);
- return Play(name, layer, looped, fadeTime);
- }
- bool AnimationController::Stop(const String& name, float fadeOutTime)
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- if (index != M_MAX_UNSIGNED)
- {
- animations_[index].targetWeight_ = 0.0f;
- animations_[index].fadeTime_ = fadeOutTime;
- MarkNetworkUpdate();
- }
- return index != M_MAX_UNSIGNED || state != 0;
- }
- void AnimationController::StopLayer(unsigned char layer, float fadeOutTime)
- {
- bool needUpdate = false;
- for (Vector<AnimationControl>::Iterator i = animations_.Begin(); i != animations_.End(); ++i)
- {
- AnimationState* state = GetAnimationState(i->hash_);
- if (state && state->GetLayer() == layer)
- {
- i->targetWeight_ = 0.0f;
- i->fadeTime_ = fadeOutTime;
- needUpdate = true;
- }
- }
- if (needUpdate)
- MarkNetworkUpdate();
- }
- void AnimationController::StopAll(float fadeOutTime)
- {
- if (animations_.Size())
- {
- for (Vector<AnimationControl>::Iterator i = animations_.Begin(); i != animations_.End(); ++i)
- {
- i->targetWeight_ = 0.0f;
- i->fadeTime_ = fadeOutTime;
- }
- MarkNetworkUpdate();
- }
- }
- bool AnimationController::Fade(const String& name, float targetWeight, float fadeTime)
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- if (index == M_MAX_UNSIGNED)
- return false;
- animations_[index].targetWeight_ = Clamp(targetWeight, 0.0f, 1.0f);
- animations_[index].fadeTime_ = fadeTime;
- MarkNetworkUpdate();
- return true;
- }
- bool AnimationController::FadeOthers(const String& name, float targetWeight, float fadeTime)
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- if (index == M_MAX_UNSIGNED || !state)
- return false;
- unsigned char layer = state->GetLayer();
- bool needUpdate = false;
- for (unsigned i = 0; i < animations_.Size(); ++i)
- {
- if (i != index)
- {
- AnimationControl& control = animations_[i];
- AnimationState* otherState = GetAnimationState(control.hash_);
- if (otherState && otherState->GetLayer() == layer)
- {
- control.targetWeight_ = Clamp(targetWeight, 0.0f, 1.0f);
- control.fadeTime_ = fadeTime;
- needUpdate = true;
- }
- }
- }
- if (needUpdate)
- MarkNetworkUpdate();
- return true;
- }
- bool AnimationController::SetLayer(const String& name, unsigned char layer)
- {
- AnimationState* state = GetAnimationState(name);
- if (!state)
- return false;
- state->SetLayer(layer);
- MarkNetworkUpdate();
- return true;
- }
- bool AnimationController::SetStartBone(const String& name, const String& startBoneName)
- {
- // Start bone can only be set in model mode
- AnimatedModel* model = GetComponent<AnimatedModel>();
- if (!model)
- return false;
- AnimationState* state = model->GetAnimationState(name);
- if (!state)
- return false;
- Bone* bone = model->GetSkeleton().GetBone(startBoneName);
- state->SetStartBone(bone);
- MarkNetworkUpdate();
- return true;
- }
- bool AnimationController::SetTime(const String& name, float time)
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- if (index == M_MAX_UNSIGNED || !state)
- return false;
- time = Clamp(time, 0.0f, state->GetLength());
- state->SetTime(time);
- // Prepare "set time" command for network replication
- animations_[index].setTime_ = (unsigned short)(time / state->GetLength() * 65535.0f);
- animations_[index].setTimeTtl_ = COMMAND_STAY_TIME;
- ++animations_[index].setTimeRev_;
- MarkNetworkUpdate();
- return true;
- }
- bool AnimationController::SetSpeed(const String& name, float speed)
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- if (index == M_MAX_UNSIGNED)
- return false;
- animations_[index].speed_ = speed;
- MarkNetworkUpdate();
- return true;
- }
- bool AnimationController::SetWeight(const String& name, float weight)
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- if (index == M_MAX_UNSIGNED || !state)
- return false;
- weight = Clamp(weight, 0.0f, 1.0f);
- state->SetWeight(weight);
- // Prepare "set weight" command for network replication
- animations_[index].setWeight_ = (unsigned char)(weight * 255.0f);
- animations_[index].setWeightTtl_ = COMMAND_STAY_TIME;
- ++animations_[index].setWeightRev_;
- // Cancel any ongoing weight fade
- animations_[index].targetWeight_ = weight;
- animations_[index].fadeTime_ = 0.0f;
- MarkNetworkUpdate();
- return true;
- }
- bool AnimationController::SetRemoveOnCompletion(const String& name, bool removeOnCompletion)
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- if (index == M_MAX_UNSIGNED || !state)
- return false;
- animations_[index].removeOnCompletion_ = removeOnCompletion;
- MarkNetworkUpdate();
- return true;
- }
- bool AnimationController::SetLooped(const String& name, bool enable)
- {
- AnimationState* state = GetAnimationState(name);
- if (!state)
- return false;
- state->SetLooped(enable);
- MarkNetworkUpdate();
- return true;
- }
- bool AnimationController::SetBlendMode(const String& name, AnimationBlendMode mode)
- {
- AnimationState* state = GetAnimationState(name);
- if (!state)
- return false;
- state->SetBlendMode(mode);
- MarkNetworkUpdate();
- return true;
- }
- bool AnimationController::SetAutoFade(const String& name, float fadeOutTime)
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- if (index == M_MAX_UNSIGNED)
- return false;
- animations_[index].autoFadeTime_ = Max(fadeOutTime, 0.0f);
- MarkNetworkUpdate();
- return true;
- }
- bool AnimationController::IsPlaying(const String& name) const
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- return index != M_MAX_UNSIGNED;
- }
- bool AnimationController::IsFadingIn(const String& name) const
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- if (index == M_MAX_UNSIGNED || !state)
- return false;
- return animations_[index].fadeTime_ && animations_[index].targetWeight_ > state->GetWeight();
- }
- bool AnimationController::IsFadingOut(const String& name) const
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- if (index == M_MAX_UNSIGNED || !state)
- return false;
- return (animations_[index].fadeTime_ && animations_[index].targetWeight_ < state->GetWeight())
- || (!state->IsLooped() && state->GetTime() >= state->GetLength() && animations_[index].autoFadeTime_);
- }
- bool AnimationController::IsAtEnd(const String& name) const
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- if (index == M_MAX_UNSIGNED || !state)
- return false;
- else
- return state->GetTime() >= state->GetLength();
- }
- unsigned char AnimationController::GetLayer(const String& name) const
- {
- AnimationState* state = GetAnimationState(name);
- return (unsigned char)(state ? state->GetLayer() : 0);
- }
- Bone* AnimationController::GetStartBone(const String& name) const
- {
- AnimationState* state = GetAnimationState(name);
- return state ? state->GetStartBone() : 0;
- }
- const String& AnimationController::GetStartBoneName(const String& name) const
- {
- Bone* bone = GetStartBone(name);
- return bone ? bone->name_ : String::EMPTY;
- }
- float AnimationController::GetTime(const String& name) const
- {
- AnimationState* state = GetAnimationState(name);
- return state ? state->GetTime() : 0.0f;
- }
- float AnimationController::GetWeight(const String& name) const
- {
- AnimationState* state = GetAnimationState(name);
- return state ? state->GetWeight() : 0.0f;
- }
- bool AnimationController::IsLooped(const String& name) const
- {
- AnimationState* state = GetAnimationState(name);
- return state ? state->IsLooped() : false;
- }
- AnimationBlendMode AnimationController::GetBlendMode(const String& name) const
- {
- AnimationState* state = GetAnimationState(name);
- return state ? state->GetBlendMode() : ABM_LERP;
- }
- float AnimationController::GetLength(const String& name) const
- {
- AnimationState* state = GetAnimationState(name);
- return state ? state->GetLength() : 0.0f;
- }
- float AnimationController::GetSpeed(const String& name) const
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- return index != M_MAX_UNSIGNED ? animations_[index].speed_ : 0.0f;
- }
- float AnimationController::GetFadeTarget(const String& name) const
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- return index != M_MAX_UNSIGNED ? animations_[index].targetWeight_ : 0.0f;
- }
- float AnimationController::GetFadeTime(const String& name) const
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- return index != M_MAX_UNSIGNED ? animations_[index].targetWeight_ : 0.0f;
- }
- float AnimationController::GetAutoFade(const String& name) const
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- return index != M_MAX_UNSIGNED ? animations_[index].autoFadeTime_ : 0.0f;
- }
- bool AnimationController::GetRemoveOnCompletion(const String& name) const
- {
- unsigned index;
- AnimationState* state;
- FindAnimation(name, index, state);
- return index != M_MAX_UNSIGNED ? animations_[index].removeOnCompletion_ : false;
- }
- AnimationState* AnimationController::GetAnimationState(const String& name) const
- {
- return GetAnimationState(StringHash(name));
- }
- AnimationState* AnimationController::GetAnimationState(StringHash nameHash) const
- {
- // Model mode
- AnimatedModel* model = GetComponent<AnimatedModel>();
- if (model)
- return model->GetAnimationState(nameHash);
- // Node hierarchy mode
- for (Vector<SharedPtr<AnimationState> >::ConstIterator i = nodeAnimationStates_.Begin(); i != nodeAnimationStates_.End(); ++i)
- {
- Animation* animation = (*i)->GetAnimation();
- if (animation->GetNameHash() == nameHash || animation->GetAnimationNameHash() == nameHash)
- return *i;
- }
- return 0;
- }
- void AnimationController::SetAnimationsAttr(const VariantVector& value)
- {
- animations_.Clear();
- animations_.Reserve(value.Size() / 5); // Incomplete data is discarded
- unsigned index = 0;
- while (index + 4 < value.Size()) // Prevent out-of-bound index access
- {
- AnimationControl newControl;
- newControl.name_ = value[index++].GetString();
- newControl.hash_ = StringHash(newControl.name_);
- newControl.speed_ = value[index++].GetFloat();
- newControl.targetWeight_ = value[index++].GetFloat();
- newControl.fadeTime_ = value[index++].GetFloat();
- newControl.autoFadeTime_ = value[index++].GetFloat();
- animations_.Push(newControl);
- }
- }
- void AnimationController::SetNetAnimationsAttr(const PODVector<unsigned char>& value)
- {
- MemoryBuffer buf(value);
- AnimatedModel* model = GetComponent<AnimatedModel>();
- // Check which animations we need to remove
- HashSet<StringHash> processedAnimations;
- unsigned numAnimations = buf.ReadVLE();
- while (numAnimations--)
- {
- String animName = buf.ReadString();
- StringHash animHash(animName);
- processedAnimations.Insert(animHash);
- // Check if the animation state exists. If not, add new
- AnimationState* state = GetAnimationState(animHash);
- if (!state)
- {
- Animation* newAnimation = GetSubsystem<ResourceCache>()->GetResource<Animation>(animName);
- state = AddAnimationState(newAnimation);
- if (!state)
- {
- ATOMIC_LOGERROR("Animation update applying aborted due to unknown animation");
- return;
- }
- }
- // Check if the internal control structure exists. If not, add new
- unsigned index;
- for (index = 0; index < animations_.Size(); ++index)
- {
- if (animations_[index].hash_ == animHash)
- break;
- }
- if (index == animations_.Size())
- {
- AnimationControl newControl;
- newControl.name_ = animName;
- newControl.hash_ = animHash;
- animations_.Push(newControl);
- }
- unsigned char ctrl = buf.ReadUByte();
- state->SetLayer(buf.ReadUByte());
- state->SetLooped((ctrl & CTRL_LOOPED) != 0);
- state->SetBlendMode((ctrl & CTRL_ADDITIVE) != 0 ? ABM_ADDITIVE : ABM_LERP);
- animations_[index].speed_ = (float)buf.ReadShort() / 2048.0f; // 11 bits of decimal precision, max. 16x playback speed
- animations_[index].targetWeight_ = (float)buf.ReadUByte() / 255.0f; // 8 bits of decimal precision
- animations_[index].fadeTime_ = (float)buf.ReadUByte() / 64.0f; // 6 bits of decimal precision, max. 4 seconds fade
- if (ctrl & CTRL_STARTBONE)
- {
- StringHash boneHash = buf.ReadStringHash();
- if (model)
- state->SetStartBone(model->GetSkeleton().GetBone(boneHash));
- }
- else
- state->SetStartBone(0);
- if (ctrl & CTRL_AUTOFADE)
- animations_[index].autoFadeTime_ = (float)buf.ReadUByte() / 64.0f; // 6 bits of decimal precision, max. 4 seconds fade
- else
- animations_[index].autoFadeTime_ = 0.0f;
-
- animations_[index].removeOnCompletion_ = (ctrl & CTRL_REMOVEONCOMPLETION) != 0;
-
- if (ctrl & CTRL_SETTIME)
- {
- unsigned char setTimeRev = buf.ReadUByte();
- unsigned short setTime = buf.ReadUShort();
- // Apply set time command only if revision differs
- if (setTimeRev != animations_[index].setTimeRev_)
- {
- state->SetTime(((float)setTime / 65535.0f) * state->GetLength());
- animations_[index].setTimeRev_ = setTimeRev;
- }
- }
- if (ctrl & CTRL_SETWEIGHT)
- {
- unsigned char setWeightRev = buf.ReadUByte();
- unsigned char setWeight = buf.ReadUByte();
- // Apply set weight command only if revision differs
- if (setWeightRev != animations_[index].setWeightRev_)
- {
- state->SetWeight((float)setWeight / 255.0f);
- animations_[index].setWeightRev_ = setWeightRev;
- }
- }
- }
- // Set any extra animations to fade out
- for (Vector<AnimationControl>::Iterator i = animations_.Begin(); i != animations_.End(); ++i)
- {
- if (!processedAnimations.Contains(i->hash_))
- {
- i->targetWeight_ = 0.0f;
- i->fadeTime_ = EXTRA_ANIM_FADEOUT_TIME;
- }
- }
- }
- void AnimationController::SetNodeAnimationStatesAttr(const VariantVector& value)
- {
- ResourceCache* cache = GetSubsystem<ResourceCache>();
- nodeAnimationStates_.Clear();
- unsigned index = 0;
- unsigned numStates = index < value.Size() ? value[index++].GetUInt() : 0;
- // Prevent negative or overly large value being assigned from the editor
- if (numStates > M_MAX_INT)
- numStates = 0;
- if (numStates > MAX_NODE_ANIMATION_STATES)
- numStates = MAX_NODE_ANIMATION_STATES;
- nodeAnimationStates_.Reserve(numStates);
- while (numStates--)
- {
- if (index + 2 < value.Size())
- {
- // Note: null animation is allowed here for editing
- const ResourceRef& animRef = value[index++].GetResourceRef();
- SharedPtr<AnimationState> newState(new AnimationState(GetNode(), cache->GetResource<Animation>(animRef.name_)));
- nodeAnimationStates_.Push(newState);
- newState->SetLooped(value[index++].GetBool());
- newState->SetTime(value[index++].GetFloat());
- }
- else
- {
- // If not enough data, just add an empty animation state
- SharedPtr<AnimationState> newState(new AnimationState(GetNode(), 0));
- nodeAnimationStates_.Push(newState);
- }
- }
- }
- VariantVector AnimationController::GetAnimationsAttr() const
- {
- VariantVector ret;
- ret.Reserve(animations_.Size() * 5);
- for (Vector<AnimationControl>::ConstIterator i = animations_.Begin(); i != animations_.End(); ++i)
- {
- ret.Push(i->name_);
- ret.Push(i->speed_);
- ret.Push(i->targetWeight_);
- ret.Push(i->fadeTime_);
- ret.Push(i->autoFadeTime_);
- }
- return ret;
- }
- const PODVector<unsigned char>& AnimationController::GetNetAnimationsAttr() const
- {
- attrBuffer_.Clear();
- AnimatedModel* model = GetComponent<AnimatedModel>();
- unsigned validAnimations = 0;
- for (Vector<AnimationControl>::ConstIterator i = animations_.Begin(); i != animations_.End(); ++i)
- {
- if (GetAnimationState(i->hash_))
- ++validAnimations;
- }
- attrBuffer_.WriteVLE(validAnimations);
- for (Vector<AnimationControl>::ConstIterator i = animations_.Begin(); i != animations_.End(); ++i)
- {
- AnimationState* state = GetAnimationState(i->hash_);
- if (!state)
- continue;
- unsigned char ctrl = 0;
- Bone* startBone = state->GetStartBone();
- if (state->IsLooped())
- ctrl |= CTRL_LOOPED;
- if (state->GetBlendMode() == ABM_ADDITIVE)
- ctrl |= CTRL_ADDITIVE;
- if (startBone && model && startBone != model->GetSkeleton().GetRootBone())
- ctrl |= CTRL_STARTBONE;
- if (i->autoFadeTime_ > 0.0f)
- ctrl |= CTRL_AUTOFADE;
- if (i->removeOnCompletion_)
- ctrl |= CTRL_REMOVEONCOMPLETION;
- if (i->setTimeTtl_ > 0.0f)
- ctrl |= CTRL_SETTIME;
- if (i->setWeightTtl_ > 0.0f)
- ctrl |= CTRL_SETWEIGHT;
- attrBuffer_.WriteString(i->name_);
- attrBuffer_.WriteUByte(ctrl);
- attrBuffer_.WriteUByte(state->GetLayer());
- attrBuffer_.WriteShort((short)Clamp(i->speed_ * 2048.0f, -32767.0f, 32767.0f));
- attrBuffer_.WriteUByte((unsigned char)(i->targetWeight_ * 255.0f));
- attrBuffer_.WriteUByte((unsigned char)Clamp(i->fadeTime_ * 64.0f, 0.0f, 255.0f));
- if (ctrl & CTRL_STARTBONE)
- attrBuffer_.WriteStringHash(startBone->nameHash_);
- if (ctrl & CTRL_AUTOFADE)
- attrBuffer_.WriteUByte((unsigned char)Clamp(i->autoFadeTime_ * 64.0f, 0.0f, 255.0f));
- if (ctrl & CTRL_SETTIME)
- {
- attrBuffer_.WriteUByte(i->setTimeRev_);
- attrBuffer_.WriteUShort(i->setTime_);
- }
- if (ctrl & CTRL_SETWEIGHT)
- {
- attrBuffer_.WriteUByte(i->setWeightRev_);
- attrBuffer_.WriteUByte(i->setWeight_);
- }
- }
- return attrBuffer_.GetBuffer();
- }
- VariantVector AnimationController::GetNodeAnimationStatesAttr() const
- {
- VariantVector ret;
- ret.Reserve(nodeAnimationStates_.Size() * 3 + 1);
- ret.Push(nodeAnimationStates_.Size());
- for (Vector<SharedPtr<AnimationState> >::ConstIterator i = nodeAnimationStates_.Begin(); i != nodeAnimationStates_.End(); ++i)
- {
- AnimationState* state = *i;
- Animation* animation = state->GetAnimation();
- ret.Push(GetResourceRef(animation, Animation::GetTypeStatic()));
- ret.Push(state->IsLooped());
- ret.Push(state->GetTime());
- }
- return ret;
- }
- void AnimationController::OnSceneSet(Scene* scene)
- {
- if (scene && IsEnabledEffective())
- SubscribeToEvent(scene, E_SCENEPOSTUPDATE, ATOMIC_HANDLER(AnimationController, HandleScenePostUpdate));
- else if (!scene)
- UnsubscribeFromEvent(E_SCENEPOSTUPDATE);
- }
- AnimationState* AnimationController::AddAnimationState(Animation* animation)
- {
- if (!animation)
- return 0;
- // Model mode
- AnimatedModel* model = GetComponent<AnimatedModel>();
- if (model)
- return model->AddAnimationState(animation);
- // Node hierarchy mode
- SharedPtr<AnimationState> newState(new AnimationState(node_, animation));
- nodeAnimationStates_.Push(newState);
- return newState;
- }
- void AnimationController::RemoveAnimationState(AnimationState* state)
- {
- if (!state)
- return;
- // Model mode
- AnimatedModel* model = GetComponent<AnimatedModel>();
- if (model)
- {
- model->RemoveAnimationState(state);
- return;
- }
- // Node hierarchy mode
- for (Vector<SharedPtr<AnimationState> >::Iterator i = nodeAnimationStates_.Begin(); i != nodeAnimationStates_.End(); ++i)
- {
- if ((*i) == state)
- {
- nodeAnimationStates_.Erase(i);
- return;
- }
- }
- }
- void AnimationController::FindAnimation(const String& name, unsigned& index, AnimationState*& state) const
- {
- StringHash nameHash(GetInternalPath(name));
- // ATOMIC BEGIN
- // Check if we're using attached animation resource
- if (animation_.NotNull() && animation_->GetAnimationName() == name)
- {
- nameHash = animation_->GetName();
- }
- else
- {
- for (unsigned i = 0; i < animationResources_.Size(); i++)
- {
- if (name == animationResources_[i]->GetAnimationName())
- {
- nameHash = animationResources_[i]->GetName();
- break;
- }
- }
- }
- // ATOMIC END
- // Find the AnimationState
- state = GetAnimationState(nameHash);
- if (state)
- {
- // Either a resource name or animation name may be specified. We store resource names, so correct the hash if necessary
- nameHash = state->GetAnimation()->GetNameHash();
- }
- // Find the internal control structure
- index = M_MAX_UNSIGNED;
- for (unsigned i = 0; i < animations_.Size(); ++i)
- {
- if (animations_[i].hash_ == nameHash)
- {
- index = i;
- break;
- }
- }
- }
- void AnimationController::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
- {
- using namespace ScenePostUpdate;
- Update(eventData[P_TIMESTEP].GetFloat());
- }
- // ATOMIC BEGIN
- void AnimationController::SetAnimationAttr(const ResourceRef& value)
- {
- ResourceCache* cache = GetSubsystem<ResourceCache>();
- animation_ = cache->GetResource<Animation>(value.name_);
- }
- ResourceRef AnimationController::GetAnimationAttr() const
- {
- return GetResourceRef(animation_, Animation::GetTypeStatic());
- }
- void AnimationController::AddAnimationResource(Animation* animation)
- {
- if (!animation)
- return;
- SharedPtr<Animation> anim(animation);
- if (!animationResources_.Contains(anim))
- animationResources_.Push(anim);
- }
- void AnimationController::RemoveAnimationResource(Animation* animation)
- {
- if (!animation)
- return;
- animationResources_.Remove(SharedPtr<Animation>(animation));
- }
- void AnimationController::ClearAnimationResources()
- {
- animationResources_.Clear();
- }
- void AnimationController::SetAnimationResourcesAttr(const ResourceRefList& value)
- {
- animationResources_.Clear();
- ResourceCache* cache = GetSubsystem<ResourceCache>();
- for (unsigned i = 0; i < value.names_.Size(); ++i)
- {
- Animation* animation = cache->GetResource<Animation>(value.names_[i]);
- if (!animation)
- {
- //LOGERRORF("AnimationController::SetAnimationResourcesAttr - Unable to load animation: %s", value.names_[i].CString());
- animationResources_.Push(SharedPtr<Animation>(nullptr));
- }
- else
- {
- animationResources_.Push(SharedPtr<Animation>(animation));
- }
- }
- }
- const ResourceRefList& AnimationController::GetAnimationResourcesAttr() const
- {
- animationResourcesAttr_.names_.Resize(animationResources_.Size());
- for (unsigned i = 0; i < animationResources_.Size(); ++i)
- animationResourcesAttr_.names_[i] = GetResourceName(animationResources_[i]);
- return animationResourcesAttr_;
- }
- // ATOMIC END
- }
|