| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487 |
- //
- // Copyright (c) 2008-2015 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 "../IO/Log.h"
- #include "../Resource/ResourceCache.h"
- #include "../Scene/Scene.h"
- #include "../Scene/SceneEvents.h"
- #include "../Atomic2D/AnimatedSprite2D.h"
- #include "../Atomic2D/AnimationSet2D.h"
- #include "../Atomic2D/Sprite2D.h"
- #include "../DebugNew.h"
- namespace Atomic
- {
- extern const char* ATOMIC2D_CATEGORY;
- extern const char* blendModeNames[];
- const char* loopModeNames[] =
- {
- "Default",
- "ForceLooped",
- "ForceClamped",
- 0
- };
- AnimatedSprite2D::AnimatedSprite2D(Context* context) :
- StaticSprite2D(context),
- speed_(1.0f),
- loopMode_(LM_DEFAULT),
- looped_(false),
- currentTime_(0.0f),
- numTracks_(0)
- {
- }
- AnimatedSprite2D::~AnimatedSprite2D()
- {
- }
- void AnimatedSprite2D::RegisterObject(Context* context)
- {
- context->RegisterFactory<AnimatedSprite2D>(ATOMIC2D_CATEGORY);
- COPY_BASE_ATTRIBUTES(StaticSprite2D);
- REMOVE_ATTRIBUTE("Sprite");
- ACCESSOR_ATTRIBUTE("Speed", GetSpeed, SetSpeed, float, 1.0f, AM_DEFAULT);
- MIXED_ACCESSOR_ATTRIBUTE("Animation Set", GetAnimationSetAttr, SetAnimationSetAttr, ResourceRef,
- ResourceRef(AnimatedSprite2D::GetTypeStatic()), AM_DEFAULT);
- ACCESSOR_ATTRIBUTE("Animation", GetAnimation, SetAnimationAttr, String, String::EMPTY, AM_DEFAULT);
- ENUM_ACCESSOR_ATTRIBUTE("Loop Mode", GetLoopMode, SetLoopMode, LoopMode2D, loopModeNames, LM_DEFAULT, AM_DEFAULT);
- }
- void AnimatedSprite2D::OnSetEnabled()
- {
- StaticSprite2D::OnSetEnabled();
- bool enabled = IsEnabledEffective();
- Scene* scene = GetScene();
- if (scene)
- {
- if (enabled)
- SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(AnimatedSprite2D, HandleScenePostUpdate));
- else
- UnsubscribeFromEvent(scene, E_SCENEPOSTUPDATE);
- }
- for (unsigned i = 0; i < trackNodes_.Size(); ++i)
- {
- if (!trackNodes_[i])
- continue;
- StaticSprite2D* staticSprite = trackNodes_[i]->GetComponent<StaticSprite2D>();
- if (staticSprite)
- staticSprite->SetEnabled(enabled);
- }
- }
- void AnimatedSprite2D::SetSpeed(float speed)
- {
- speed_ = speed;
- MarkNetworkUpdate();
- }
- void AnimatedSprite2D::SetAnimation(AnimationSet2D* animationSet, const String& name, LoopMode2D loopMode)
- {
- animationSet_ = animationSet;
- SetAnimation(name, loopMode);
- }
- void AnimatedSprite2D::SetAnimation(const String& name, LoopMode2D loopMode)
- {
- animationName_ = name;
- if (animationSet_)
- SetAnimation(animationSet_->GetAnimation(animationName_), loopMode);
- }
- void AnimatedSprite2D::SetAnimationSet(AnimationSet2D* animationSet)
- {
- if (animationSet == animationSet_)
- return;
- animationSet_ = animationSet;
- SetAnimation(animationName_, loopMode_);
- }
- void AnimatedSprite2D::SetLoopMode(LoopMode2D loopMode)
- {
- if (!animation_)
- return;
- loopMode_ = loopMode;
- switch (loopMode_)
- {
- case LM_FORCE_LOOPED:
- looped_ = true;
- break;
- case LM_FORCE_CLAMPED:
- looped_ = false;
- break;
- default:
- looped_ = animation_->IsLooped();
- break;
- }
- }
- AnimationSet2D* AnimatedSprite2D::GetAnimationSet() const
- {
- return animationSet_;
- }
- Node* AnimatedSprite2D::GetRootNode() const
- {
- return rootNode_;
- }
- void AnimatedSprite2D::SetAnimationSetAttr(const ResourceRef& value)
- {
- ResourceCache* cache = GetSubsystem<ResourceCache>();
- SetAnimationSet(cache->GetResource<AnimationSet2D>(value.name_));
- }
- ResourceRef AnimatedSprite2D::GetAnimationSetAttr() const
- {
- return GetResourceRef(animationSet_, AnimationSet2D::GetTypeStatic());
- }
- void AnimatedSprite2D::OnSceneSet(Scene* scene)
- {
- StaticSprite2D::OnSceneSet(scene);
- if (scene)
- {
- if (scene == node_)
- LOGWARNING(GetTypeName() + " should not be created to the root scene node");
- if (IsEnabledEffective())
- SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(AnimatedSprite2D, HandleScenePostUpdate));
- }
- else
- UnsubscribeFromEvent(E_SCENEPOSTUPDATE);
- }
- void AnimatedSprite2D::SetAnimationAttr(const String& name)
- {
- animationName_ = name;
- if (animationSet_)
- SetAnimation(animationSet_->GetAnimation(animationName_), loopMode_);
- }
- void AnimatedSprite2D::OnWorldBoundingBoxUpdate()
- {
- boundingBox_.Clear();
- worldBoundingBox_.Clear();
- for (unsigned i = 0; i < numTracks_; ++i)
- {
- if (!trackNodes_[i])
- continue;
- StaticSprite2D* staticSprite = trackNodes_[i]->GetComponent<StaticSprite2D>();
- if (staticSprite)
- worldBoundingBox_.Merge(staticSprite->GetWorldBoundingBox());
- }
- boundingBox_ = worldBoundingBox_.Transformed(node_->GetWorldTransform().Inverse());
- }
- void AnimatedSprite2D::OnDrawOrderChanged()
- {
- for (unsigned i = 0; i < numTracks_; ++i)
- {
- if (!trackNodes_[i])
- continue;
- StaticSprite2D* staticSprite = trackNodes_[i]->GetComponent<StaticSprite2D>();
- if (staticSprite)
- staticSprite->SetLayer(layer_);
- }
- }
- void AnimatedSprite2D::OnFlipChanged()
- {
- for (unsigned i = 0; i < numTracks_; ++i)
- {
- if (!trackNodes_[i])
- continue;
- StaticSprite2D* staticSprite = trackNodes_[i]->GetComponent<StaticSprite2D>();
- if (staticSprite)
- staticSprite->SetFlip(flipX_, flipY_);
- }
- // For editor paused mode
- UpdateAnimation(0.0f);
- }
- void AnimatedSprite2D::UpdateSourceBatches()
- {
- sourceBatchesDirty_ = false;
- }
- void AnimatedSprite2D::SetAnimation(Animation2D* animation, LoopMode2D loopMode)
- {
- if (animation == animation_)
- {
- SetLoopMode(loopMode_);
- currentTime_ = 0.0f;
- UpdateAnimation(0.0f);
- return;
- }
- for (unsigned i = 0; i < numTracks_; ++i)
- {
- if (trackNodes_[i])
- trackNodes_[i]->SetEnabled(false);
- }
- numTracks_ = 0;
- trackNodes_.Clear();
- trackNodeInfos_.Clear();
- animation_ = animation;
- if (!animation_)
- return;
- currentTime_ = 0.0f;
- if (!rootNode_)
- {
- rootNode_ = GetNode()->CreateChild("_root_", LOCAL);
- rootNode_->SetTemporary(true);
- }
- numTracks_ = animation_->GetNumTracks();
- trackNodes_.Resize(numTracks_);
- trackNodeInfos_.Resize(numTracks_);
- for (unsigned i = 0; i < numTracks_; ++i)
- {
- const AnimationTrack2D& track = animation->GetTrack(i);
- SharedPtr<Node> trackNode(rootNode_->GetChild(track.name_));
- StaticSprite2D* staticSprite = 0;
- if (trackNode)
- {
- // Enable track node
- trackNode->SetEnabled(true);
- // Get StaticSprite2D component
- if (track.hasSprite_)
- staticSprite = trackNode->GetComponent<StaticSprite2D>();
- }
- else
- {
- // Create new track node
- trackNode = rootNode_->CreateChild(track.name_, LOCAL);
- trackNode->SetTemporary(true);
- // Create StaticSprite2D component
- if (track.hasSprite_)
- {
- staticSprite = trackNode->CreateComponent<StaticSprite2D>();
- staticSprite->SetEnabled(IsEnabledEffective());
- }
- }
- if (staticSprite)
- {
- staticSprite->SetLayer(layer_);
- staticSprite->SetBlendMode(blendMode_);
- staticSprite->SetFlip(flipX_, flipY_);
- //use color of that object, animations doesn't have color
- staticSprite->SetColor(color_);
- staticSprite->SetUseHotSpot(true);
- }
- trackNodes_[i] = trackNode;
- trackNodeInfos_[i].hasSprite = track.hasSprite_;
- }
- SetLoopMode(loopMode);
- UpdateAnimation(0.0f);
- MarkNetworkUpdate();
- }
- void AnimatedSprite2D::UpdateAnimation(float timeStep)
- {
- if (!animation_)
- return;
- currentTime_ += timeStep * speed_;
- float time;
- float animationLength = animation_->GetLength();
- if (looped_)
- {
- time = fmodf(currentTime_, animationLength);
- if (time < 0.0f)
- time += animation_->GetLength();
- }
- else
- time = Clamp(currentTime_, 0.0f, animationLength);
- for (unsigned i = 0; i < numTracks_; ++i)
- {
- trackNodeInfos_[i].worldSpace = false;
- const AnimationTrack2D& track = animation_->GetTrack(i);
- const Vector<AnimationKeyFrame2D>& keyFrames = track.keyFrames_;
- // Time out of range
- if (time < keyFrames[0].time_ || time > keyFrames.Back().time_)
- trackNodeInfos_[i].value.enabled_ = false;
- else
- {
- unsigned index = keyFrames.Size() - 1;
- for (unsigned j = 0; j < keyFrames.Size() - 1; ++j)
- {
- if (time <= keyFrames[j + 1].time_)
- {
- index = j;
- break;
- }
- }
- const AnimationKeyFrame2D& currKey = keyFrames[index];
- AnimationKeyFrame2D& value = trackNodeInfos_[i].value;
- value.enabled_ = currKey.enabled_;
- value.parent_ = currKey.parent_;
- if (index < keyFrames.Size() - 1)
- {
- const AnimationKeyFrame2D& nextKey = keyFrames[index + 1];
- float t = (time - currKey.time_) / (nextKey.time_ - currKey.time_);
- value.transform_ = currKey.transform_.Lerp(nextKey.transform_, t, currKey.spin_);
- if (trackNodeInfos_[i].hasSprite)
- value.alpha_ = Atomic::Lerp(currKey.alpha_, nextKey.alpha_, t);
- }
- else
- {
- value.transform_ = currKey.transform_;
- if (trackNodeInfos_[i].hasSprite)
- value.alpha_ = currKey.alpha_;
- }
- if (trackNodeInfos_[i].hasSprite)
- {
- value.zIndex_ = currKey.zIndex_;
- value.sprite_ = currKey.sprite_;
- value.useHotSpot_ = currKey.useHotSpot_;
- value.hotSpot_ = currKey.hotSpot_;
- }
- }
- }
- for (unsigned i = 0; i < numTracks_; ++i)
- {
- Node* node = trackNodes_[i];
- if (!node)
- continue;
- TrackNodeInfo& nodeInfo = trackNodeInfos_[i];
- if (!nodeInfo.value.enabled_)
- node->SetEnabled(false);
- else
- {
- node->SetEnabled(true);
- // Calculate world transform.
- CalculateTimelineWorldTransform(i);
- // Update node's transform
- Vector2 position = nodeInfo.value.transform_.position_ * PIXEL_SIZE;
- if (flipX_)
- position.x_ = -position.x_;
- if (flipY_)
- position.y_ = -position.y_;
- node->SetPosition(position);
- float angle = nodeInfo.value.transform_.angle_;
- if (flipX_ != flipY_)
- angle = -angle;
- node->SetRotation(angle);
- node->SetScale(nodeInfo.value.transform_.scale_);
- if (nodeInfo.hasSprite)
- {
- StaticSprite2D* staticSprite = node->GetComponent<StaticSprite2D>();
- if (staticSprite)
- {
- staticSprite->SetOrderInLayer(orderInLayer_ + nodeInfo.value.zIndex_);
- staticSprite->SetSprite(nodeInfo.value.sprite_);
- staticSprite->SetAlpha(nodeInfo.value.alpha_);
- staticSprite->SetUseHotSpot(nodeInfo.value.useHotSpot_);
- staticSprite->SetHotSpot(nodeInfo.value.hotSpot_);
- //use color of that object, animations doesn't have color
- staticSprite->SetColor(color_);
- }
- }
- }
- }
- }
- void AnimatedSprite2D::CalculateTimelineWorldTransform(int index)
- {
- TrackNodeInfo& info = trackNodeInfos_[index];
- if (info.worldSpace)
- return;
- info.worldSpace = true;
- int parent = info.value.parent_;
- if (parent != -1)
- {
- CalculateTimelineWorldTransform(parent);
- info.value.transform_ = trackNodeInfos_[parent].value.transform_ * info.value.transform_;
- }
- }
- void AnimatedSprite2D::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
- {
- using namespace ScenePostUpdate;
- float timeStep = eventData[P_TIMESTEP].GetFloat();
- UpdateAnimation(timeStep);
- }
- }
|