| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539 |
- //
- // Copyright (c) 2008-2014 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 "AnimatedSprite2D.h"
- #include "Animation2D.h"
- #include "AnimationSet2D.h"
- #include "Context.h"
- #include "Drawable2D.h"
- #include "ResourceCache.h"
- #include "Scene.h"
- #include "SceneEvents.h"
- #include "Sprite2D.h"
- #include "StaticSprite2D.h"
- #include "DebugNew.h"
- namespace Urho3D
- {
- extern const char* URHO2D_CATEGORY;
- extern const char* blendModeNames[];
- const char* loopModeNames[] =
- {
- "Default",
- "ForceLooped",
- "ForceClamped",
- 0
- };
- AnimatedSprite2D::AnimatedSprite2D(Context* context) :
- Drawable(context, DRAWABLE_GEOMETRY),
- layer_(0),
- orderInLayer_(0),
- blendMode_(BLEND_ALPHA),
- flipX_(false),
- flipY_(false),
- color_(Color::WHITE),
- speed_(1.0f),
- loopMode_(LM_DEFAULT),
- looped_(false),
- currentTime_(0.0f)
- {
- }
- AnimatedSprite2D::~AnimatedSprite2D()
- {
- }
- void AnimatedSprite2D::RegisterObject(Context* context)
- {
- context->RegisterFactory<AnimatedSprite2D>(URHO2D_CATEGORY);
- ACCESSOR_ATTRIBUTE("Layer", GetLayer, SetLayer, int, 0, AM_DEFAULT);
- ACCESSOR_ATTRIBUTE("Order in Layer", GetOrderInLayer, SetOrderInLayer, int, 0, AM_DEFAULT);
- ENUM_ACCESSOR_ATTRIBUTE("Blend Mode", GetBlendMode, SetBlendMode, BlendMode, blendModeNames, BLEND_ALPHA, AM_DEFAULT);
- ACCESSOR_ATTRIBUTE("Flip X", GetFlipX, SetFlipX, bool, false, AM_DEFAULT);
- ACCESSOR_ATTRIBUTE("Flip Y", GetFlipY, SetFlipY, bool, false, AM_DEFAULT);
- ACCESSOR_ATTRIBUTE("Color", GetColor, SetColor, Color, Color::WHITE, AM_DEFAULT);
- 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);
- COPY_BASE_ATTRIBUTES(Drawable);
- }
- void AnimatedSprite2D::OnSetEnabled()
- {
- Drawable::OnSetEnabled();
- Scene* scene = GetScene();
- if (scene)
- {
- if (IsEnabledEffective())
- SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(AnimatedSprite2D, HandleScenePostUpdate));
- else
- UnsubscribeFromEvent(scene, E_SCENEPOSTUPDATE);
- }
- }
- void AnimatedSprite2D::SetLayer(int layer)
- {
- if (layer == layer_)
- return;
- layer_ = layer;
- for (unsigned i = 0; i < timelineNodes_.Size(); ++i)
- {
- if (!timelineNodes_[i])
- continue;
- StaticSprite2D* staticSprite = timelineNodes_[i]->GetComponent<StaticSprite2D>();
- staticSprite->SetLayer(layer_);
- }
- }
- void AnimatedSprite2D::SetOrderInLayer(int orderInLayer)
- {
- orderInLayer_ = orderInLayer;
- }
- void AnimatedSprite2D::SetBlendMode(BlendMode blendMode)
- {
- if (blendMode == blendMode_)
- return;
- blendMode_ = blendMode;
- for (unsigned i = 0; i < timelineNodes_.Size(); ++i)
- {
- if (!timelineNodes_[i])
- continue;
- StaticSprite2D* staticSprite = timelineNodes_[i]->GetComponent<StaticSprite2D>();
- staticSprite->SetBlendMode(blendMode_);
- }
- }
- void AnimatedSprite2D::SetFlip(bool flipX, bool flipY)
- {
- if (flipX == flipX_ && flipY == flipY_)
- return;
- flipX_ = flipX;
- flipY_ = flipY;
- for (unsigned i = 0; i < timelineNodes_.Size(); ++i)
- {
- if (!timelineNodes_[i])
- continue;
- StaticSprite2D* staticSprite = timelineNodes_[i]->GetComponent<StaticSprite2D>();
- staticSprite->SetFlip(flipX_, flipY_);
- }
- // For editor paused mode
- UpdateAnimation(0.0f);
- MarkNetworkUpdate();
- }
- void AnimatedSprite2D::SetFlipX(bool flipX)
- {
- SetFlip(flipX, flipY_);
- }
- void AnimatedSprite2D::SetFlipY(bool flipY)
- {
- SetFlip(flipX_, flipY);
- }
- void AnimatedSprite2D::SetColor(const Color& color)
- {
- color_ = color;
- MarkNetworkUpdate();
- }
- 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::OnNodeSet(Node* node)
- {
- Drawable::OnNodeSet(node);
- if (node)
- {
- Scene* scene = GetScene();
- if (scene && IsEnabledEffective())
- SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(AnimatedSprite2D, HandleScenePostUpdate));
- }
- else
- {
- if (rootNode_)
- rootNode_->Remove();
- rootNode_ = 0;
- timelineNodes_.Clear();
- }
- }
- 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 < timelineNodes_.Size(); ++i)
- {
- if (!timelineNodes_[i])
- continue;
- StaticSprite2D* staticSprite = timelineNodes_[i]->GetComponent<StaticSprite2D>();
- if (staticSprite)
- worldBoundingBox_.Merge(staticSprite->GetWorldBoundingBox());
- }
- boundingBox_ = worldBoundingBox_.Transformed(node_->GetWorldTransform().Inverse());
- }
- void AnimatedSprite2D::SetAnimation(Animation2D* animation, LoopMode2D loopMode)
- {
- if (animation == animation_)
- {
- SetLoopMode(loopMode_);
- currentTime_ = 0.0f;
- UpdateAnimation(0.0f);
- return;
- }
- for (unsigned i = 0; i < timelineNodes_.Size(); ++i)
- {
- if (timelineNodes_[i])
- timelineNodes_[i]->SetEnabled(false);
- }
- timelineNodes_.Clear();
- animation_ = animation;
- if (!animation_)
- return;
- currentTime_ = 0.0f;
- if (!rootNode_)
- {
- rootNode_ = GetNode()->CreateChild("RootNode", LOCAL);
- rootNode_->SetTemporary(true);
- }
- timelineNodes_.Resize(animation_->GetNumTimelines());
- timelineTransformInfos_.Resize(animation_->GetNumTimelines());
- for (unsigned i = 0; i < animation_->GetNumTimelines(); ++i)
- {
- const Timeline2D& timeline = animation->GetTimeline(i);
- SharedPtr<Node> timelineNode(rootNode_->GetChild(timeline.name_));
- StaticSprite2D* staticSprite = 0;
- if (timelineNode)
- {
- // Enable timeline node
- timelineNode->SetEnabled(true);
- // Get StaticSprite2D component
- if (timeline.type_ == OT_SPRITE)
- staticSprite = timelineNode->GetComponent<StaticSprite2D>();
- }
- else
- {
- // Create new timeline node
- timelineNode = rootNode_->CreateChild(timeline.name_, LOCAL);
- // Create StaticSprite2D component
- if (timeline.type_ == OT_SPRITE)
- staticSprite = timelineNode->CreateComponent<StaticSprite2D>();
- }
- if (staticSprite)
- {
- staticSprite->SetLayer(layer_);
- staticSprite->SetBlendMode(blendMode_);
- staticSprite->SetFlip(flipX_, flipY_);
- staticSprite->SetUseHotSpot(true);
- }
- timelineNodes_[i] = timelineNode;
- timelineTransformInfos_[i].parent_ = timeline.parent_;
- }
- SetLoopMode(loopMode);
- UpdateAnimation(0.0f);
- MarkNetworkUpdate();
- }
- void AnimatedSprite2D::UpdateAnimation(float timeStep)
- {
- if (!animation_)
- return;
- currentTime_ += timeStep * speed_;
- float time;
- float animtationLength = animation_->GetLength();
- if (looped_)
- {
- time = fmodf(currentTime_, animtationLength);
- if (time < 0.0f)
- time += animation_->GetLength();
- }
- else
- time = Clamp(currentTime_, 0.0f, animtationLength);
- // Update timeline's local transform
- for (unsigned i = 0; i < timelineTransformInfos_.Size(); ++i)
- {
- const Timeline2D& timeline = animation_->GetTimeline(i);
- const Vector<TimelineKey2D>& objectKeys = timeline.timelineKeys_;
- unsigned index = objectKeys.Size() - 1;
- for (unsigned j = 0; j < objectKeys.Size() - 1; ++j)
- {
- if (time <= objectKeys[j + 1].time_)
- {
- index = j;
- break;
- }
- }
- const TimelineKey2D& currKey = objectKeys[index];
- if (index < objectKeys.Size() - 1)
- {
- const TimelineKey2D& nextKey = objectKeys[index + 1];
- float t = (time - currKey.time_) / (nextKey.time_ - currKey.time_);
- timelineTransformInfos_[i].worldSpace_ = false;
- timelineTransformInfos_[i].transform_ = currKey.transform_.Lerp(nextKey.transform_, t, currKey.spin_);
- // Update sprite's sprite and hot spot and color
- Node* timelineNode = timelineNodes_[i];
- if (timelineNode)
- {
- StaticSprite2D* staticSprite = timelineNode->GetComponent<StaticSprite2D>();
- if (staticSprite)
- {
- staticSprite->SetSprite(currKey.sprite_);
- staticSprite->SetHotSpot(currKey.hotSpot_.Lerp(nextKey.hotSpot_, t));
- float alpha = Lerp(currKey.alpha_, nextKey.alpha_, t);
- staticSprite->SetColor(Color(color_.r_, color_.g_, color_.b_, color_.a_ * alpha));
- }
- }
- }
- else
- {
- timelineTransformInfos_[i].worldSpace_ = false;
- timelineTransformInfos_[i].transform_ = currKey.transform_;
- // Update sprite's sprite and hot spot and color
- Node* timelineNode = timelineNodes_[i];
- if (timelineNode)
- {
- StaticSprite2D* staticSprite = timelineNode->GetComponent<StaticSprite2D>();
- if (staticSprite)
- {
- staticSprite->SetSprite(currKey.sprite_);
- staticSprite->SetHotSpot(currKey.hotSpot_);
- staticSprite->SetColor(Color(color_.r_, color_.g_, color_.b_, color_.a_ * currKey.alpha_));
- }
- }
- }
- }
- // Calculate timeline world transform.
- for (unsigned i = 0; i < timelineTransformInfos_.Size(); ++i)
- CalculateTimelineWorldTransform(i);
- // Get mainline key
- const Vector<MainlineKey2D>& mainlineKeys = animation_->GetMainlineKeys();
- const MainlineKey2D* mainlineKey = 0;
- for (unsigned i = 1; i < mainlineKeys.Size(); ++i)
- {
- if (time < mainlineKeys[i].time_)
- {
- mainlineKey = &mainlineKeys[i - 1];
- break;
- }
- }
- if (!mainlineKey)
- mainlineKey = &mainlineKeys.Back();
- // Update node's transform and sprite's z order
- for (unsigned i = 0; i < timelineNodes_.Size(); ++i)
- {
- Node* timelineNode = timelineNodes_[i];
- if (!timelineNode)
- continue;
- const Reference2D* ref = mainlineKey->GetReference(i);
- if (!ref)
- {
- // Disable node
- if (timelineNode->IsEnabled())
- timelineNode->SetEnabled(false);
- }
- else
- {
- // Enable node
- if (!timelineNode->IsEnabled())
- timelineNode->SetEnabled(true);
- // Update node's transform
- const Transform2D& transform = timelineTransformInfos_[i].transform_;
- Vector2 position = transform.position_ * PIXEL_SIZE;
- if (flipX_)
- position.x_ = -position.x_;
- if (flipY_)
- position.y_ = -position.y_;
- timelineNode->SetPosition(position);
- float angle = transform.angle_;
- if (flipX_ != flipY_)
- angle = -angle;
- timelineNode->SetRotation(angle);
- timelineNode->SetScale(transform.scale_);
- // Update sprite's z order
- StaticSprite2D* staticSprite = timelineNode->GetComponent<StaticSprite2D>();
- if (staticSprite)
- staticSprite->SetOrderInLayer(orderInLayer_ + ref->zIndex_);
- }
- }
- MarkForUpdate();
- }
- void AnimatedSprite2D::CalculateTimelineWorldTransform(unsigned index)
- {
- TransformInfo& info = timelineTransformInfos_[index];
- if (info.worldSpace_)
- return;
- info.worldSpace_ = true;
- if (info.parent_ != -1)
- {
- CalculateTimelineWorldTransform(info.parent_);
- info.transform_ = timelineTransformInfos_[info.parent_].transform_ * info.transform_;
- }
- }
- void AnimatedSprite2D::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
- {
- using namespace ScenePostUpdate;
- float timeStep = eventData[P_TIMESTEP].GetFloat();
- UpdateAnimation(timeStep);
- }
- }
|