18bf80f4bSopenharmony_ci/* 28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License. 58bf80f4bSopenharmony_ci * You may obtain a copy of the License at 68bf80f4bSopenharmony_ci * 78bf80f4bSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 88bf80f4bSopenharmony_ci * 98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and 138bf80f4bSopenharmony_ci * limitations under the License. 148bf80f4bSopenharmony_ci */ 158bf80f4bSopenharmony_ci#include <scene_plugin/api/scene_uid.h> 168bf80f4bSopenharmony_ci 178bf80f4bSopenharmony_ci#include <3d/ecs/components/mesh_component.h> 188bf80f4bSopenharmony_ci 198bf80f4bSopenharmony_ci#include <meta/ext/concrete_base_object.h> 208bf80f4bSopenharmony_ci#include <meta/interface/animation/modifiers/intf_loop.h> 218bf80f4bSopenharmony_ci#include <meta/interface/animation/modifiers/intf_speed.h> 228bf80f4bSopenharmony_ci 238bf80f4bSopenharmony_ci#include "bind_templates.inl" 248bf80f4bSopenharmony_ci#include "intf_node_private.h" 258bf80f4bSopenharmony_ci#include "intf_submesh_bridge.h" 268bf80f4bSopenharmony_ci#include "node_impl.h" 278bf80f4bSopenharmony_ci#include "submesh_handler_uid.h" 288bf80f4bSopenharmony_ci#include "task_utils.h" 298bf80f4bSopenharmony_ci 308bf80f4bSopenharmony_ciusing SCENE_NS::MakeTask; 318bf80f4bSopenharmony_cinamespace { 328bf80f4bSopenharmony_ciclass AnimImpl 338bf80f4bSopenharmony_ci : public META_NS::ConcreteBaseMetaObjectFwd<AnimImpl, NodeImpl, SCENE_NS::ClassId::Animation, 348bf80f4bSopenharmony_ci META_NS::IParallelAnimation, META_NS::IAttachment, META_NS::ITimedAnimation, META_NS::IStartableAnimation> { 358bf80f4bSopenharmony_ci using Super = META_NS::ConcreteBaseMetaObjectFwd<AnimImpl, NodeImpl, SCENE_NS::ClassId::Animation, 368bf80f4bSopenharmony_ci META_NS::IParallelAnimation, META_NS::IAttachment, META_NS::ITimedAnimation, META_NS::IStartableAnimation>; 378bf80f4bSopenharmony_ci 388bf80f4bSopenharmony_ci // From IEcsAnimation 398bf80f4bSopenharmony_ci // META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IEcsAnimation, bool, ReadOnly, false, 408bf80f4bSopenharmony_ci // META_NS::DefaultPropFlags::R_FLAGS) 418bf80f4bSopenharmony_ci 428bf80f4bSopenharmony_ci // From INamed 438bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_PROPERTY(META_NS::INamed, BASE_NS::string, Name, {}) 448bf80f4bSopenharmony_ci 458bf80f4bSopenharmony_ci // From IAnimation 468bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_PROPERTY(IAnimation, bool, Enabled, true) 478bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, bool, Valid, false, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER) 488bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, META_NS::TimeSpan, TotalDuration, 498bf80f4bSopenharmony_ci META_NS::TimeSpan::Milliseconds(500), META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER) 508bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, bool, Running, false, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER) 518bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, float, Progress, 0, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER) 528bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_PROPERTY(IAnimation, META_NS::ICurve1D::Ptr, Curve) 538bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_PROPERTY( 548bf80f4bSopenharmony_ci IAnimation, META_NS::IAnimationController::WeakPtr, Controller, {}, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER) 558bf80f4bSopenharmony_ci 568bf80f4bSopenharmony_ci // from IAttachment IAnimationWithModifiableDuration 578bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(META_NS::IAttachment, META_NS::IObject::WeakPtr, DataContext) 588bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(META_NS::IAttachment, META_NS::IAttach::WeakPtr, AttachedTo) 598bf80f4bSopenharmony_ci 608bf80f4bSopenharmony_ci // from ITimedAnimation 618bf80f4bSopenharmony_ci META_IMPLEMENT_INTERFACE_PROPERTY( 628bf80f4bSopenharmony_ci META_NS::ITimedAnimation, META_NS::TimeSpan, Duration, META_NS::TimeSpan::Milliseconds(500)) 638bf80f4bSopenharmony_ci 648bf80f4bSopenharmony_ci META_IMPLEMENT_EVENT(META_NS::IOnChanged, OnFinished) 658bf80f4bSopenharmony_ci META_IMPLEMENT_EVENT(META_NS::IOnChanged, OnStarted) 668bf80f4bSopenharmony_ci 678bf80f4bSopenharmony_ci // IAttach 688bf80f4bSopenharmony_ci bool Attach( 698bf80f4bSopenharmony_ci const BASE_NS::shared_ptr<META_NS::IObject>& attachment, const META_NS::IObject::Ptr& dataContext) override; 708bf80f4bSopenharmony_ci bool Detach(const META_NS::IObject::Ptr& attachment) override; 718bf80f4bSopenharmony_ci 728bf80f4bSopenharmony_ci /** 738bf80f4bSopenharmony_ci * @brief Called by the framework when an the attachment is being attached to an IObject. If this 748bf80f4bSopenharmony_ci * function succeeds, the object is attached to the target. 758bf80f4bSopenharmony_ci * @param object The IObject instance the attachment is attached to. 768bf80f4bSopenharmony_ci * @param dataContext The data context for this attachment. 778bf80f4bSopenharmony_ci * @note The data context can be the same object as the object being attached to, or 788bf80f4bSopenharmony_ci * something else. It is up to the attachment to decide how to handle them. 798bf80f4bSopenharmony_ci * @return The implementation should return true if the attachment can be attached to target object. 808bf80f4bSopenharmony_ci * If the attachment cannot be added, the implementation should return false. 818bf80f4bSopenharmony_ci */ 828bf80f4bSopenharmony_ci bool Attaching(const IAttach::Ptr& target, const IObject::Ptr& dataContext) override 838bf80f4bSopenharmony_ci { 848bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(AttachedTo)->SetValue(target); 858bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(DataContext)->SetValue(dataContext); 868bf80f4bSopenharmony_ci return true; 878bf80f4bSopenharmony_ci } 888bf80f4bSopenharmony_ci /** 898bf80f4bSopenharmony_ci * @brief Detach the attachment from an object. 908bf80f4bSopenharmony_ci * @param object The object to attach to. 918bf80f4bSopenharmony_ci * @return If the attachment can be detached from the target, the implementation should return true. 928bf80f4bSopenharmony_ci * If detaching is not possible, the implementation should return false. In such a case the 938bf80f4bSopenharmony_ci * target may choose to not remove the attachment. During for example object destruction, 948bf80f4bSopenharmony_ci * the target will ignore the return value. 958bf80f4bSopenharmony_ci */ 968bf80f4bSopenharmony_ci bool Detaching(const IAttach::Ptr& target) override 978bf80f4bSopenharmony_ci { 988bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(AttachedTo)->SetValue({}); 998bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(DataContext)->SetValue({}); 1008bf80f4bSopenharmony_ci 1018bf80f4bSopenharmony_ci // TODO: Remove this line of code, once framework automatically removes animations 1028bf80f4bSopenharmony_ci // from animation controller when objects are destroyed. 1038bf80f4bSopenharmony_ci 1048bf80f4bSopenharmony_ci auto animation = GetSelf<IAnimation>(); 1058bf80f4bSopenharmony_ci if (animation) { 1068bf80f4bSopenharmony_ci auto controller = META_NS::GetValue(animation->Controller()).lock(); 1078bf80f4bSopenharmony_ci if (controller) { 1088bf80f4bSopenharmony_ci controller->RemoveAnimation(animation); 1098bf80f4bSopenharmony_ci } 1108bf80f4bSopenharmony_ci } 1118bf80f4bSopenharmony_ci 1128bf80f4bSopenharmony_ci return true; 1138bf80f4bSopenharmony_ci } 1148bf80f4bSopenharmony_ci 1158bf80f4bSopenharmony_ci void AddAnimation(const IAnimation::Ptr&) override {} 1168bf80f4bSopenharmony_ci void RemoveAnimation(const IAnimation::Ptr&) override {} 1178bf80f4bSopenharmony_ci 1188bf80f4bSopenharmony_ci BASE_NS::vector<META_NS::IAnimation::Ptr> GetAnimations() const override 1198bf80f4bSopenharmony_ci { 1208bf80f4bSopenharmony_ci return {}; 1218bf80f4bSopenharmony_ci } 1228bf80f4bSopenharmony_ci 1238bf80f4bSopenharmony_ci void Step(const META_NS::IClock::ConstPtr& clock) override 1248bf80f4bSopenharmony_ci { 1258bf80f4bSopenharmony_ci // Nothing to do. Animation is stepped by Engine. 1268bf80f4bSopenharmony_ci } 1278bf80f4bSopenharmony_ci 1288bf80f4bSopenharmony_ci void Start() override 1298bf80f4bSopenharmony_ci { 1308bf80f4bSopenharmony_ci // Set ecs animation to pause 1318bf80f4bSopenharmony_ci if (META_ACCESS_PROPERTY_VALUE(Enabled)) { 1328bf80f4bSopenharmony_ci META_NS::SetValue(animationState_, (uint8_t)CORE3D_NS::AnimationComponent::PlaybackState::PLAY); 1338bf80f4bSopenharmony_ci 1348bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(Running)->SetValue(true); 1358bf80f4bSopenharmony_ci META_NS::Invoke<META_NS::IOnChanged>(OnStarted()); 1368bf80f4bSopenharmony_ci } 1378bf80f4bSopenharmony_ci } 1388bf80f4bSopenharmony_ci 1398bf80f4bSopenharmony_ci void InternalStop() 1408bf80f4bSopenharmony_ci { 1418bf80f4bSopenharmony_ci // Set ecs animation to pause 1428bf80f4bSopenharmony_ci META_NS::SetValue(animationState_, (uint8_t)CORE3D_NS::AnimationComponent::PlaybackState::STOP); 1438bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(Running)->SetValue(false); 1448bf80f4bSopenharmony_ci SetProgress(0.0f); 1458bf80f4bSopenharmony_ci } 1468bf80f4bSopenharmony_ci 1478bf80f4bSopenharmony_ci void Stop() override 1488bf80f4bSopenharmony_ci { 1498bf80f4bSopenharmony_ci if (META_ACCESS_PROPERTY_VALUE(Enabled)) { 1508bf80f4bSopenharmony_ci InternalStop(); 1518bf80f4bSopenharmony_ci } 1528bf80f4bSopenharmony_ci } 1538bf80f4bSopenharmony_ci 1548bf80f4bSopenharmony_ci void Pause() override 1558bf80f4bSopenharmony_ci { 1568bf80f4bSopenharmony_ci if (META_ACCESS_PROPERTY_VALUE(Enabled)) { 1578bf80f4bSopenharmony_ci META_NS::SetValue(animationState_, (uint8_t)CORE3D_NS::AnimationComponent::PlaybackState::PAUSE); 1588bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(Running)->SetValue(false); 1598bf80f4bSopenharmony_ci } 1608bf80f4bSopenharmony_ci } 1618bf80f4bSopenharmony_ci 1628bf80f4bSopenharmony_ci void Restart() override 1638bf80f4bSopenharmony_ci { 1648bf80f4bSopenharmony_ci Stop(); 1658bf80f4bSopenharmony_ci Start(); 1668bf80f4bSopenharmony_ci } 1678bf80f4bSopenharmony_ci 1688bf80f4bSopenharmony_ci void Finish() override 1698bf80f4bSopenharmony_ci { 1708bf80f4bSopenharmony_ci if (META_ACCESS_PROPERTY_VALUE(Enabled)) { 1718bf80f4bSopenharmony_ci META_NS::SetValue(animationState_, (uint8_t)CORE3D_NS::AnimationComponent::PlaybackState::STOP); 1728bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(Running)->SetValue(false); 1738bf80f4bSopenharmony_ci Seek(1.0f); 1748bf80f4bSopenharmony_ci META_NS::Invoke<META_NS::IOnChanged>(OnFinished()); 1758bf80f4bSopenharmony_ci } 1768bf80f4bSopenharmony_ci } 1778bf80f4bSopenharmony_ci 1788bf80f4bSopenharmony_ci void Seek(float position) override 1798bf80f4bSopenharmony_ci { 1808bf80f4bSopenharmony_ci if (META_ACCESS_PROPERTY_VALUE(Enabled)) { 1818bf80f4bSopenharmony_ci position = BASE_NS::Math::clamp01(position); 1828bf80f4bSopenharmony_ci SetProgress(position); 1838bf80f4bSopenharmony_ci } 1848bf80f4bSopenharmony_ci } 1858bf80f4bSopenharmony_ci 1868bf80f4bSopenharmony_ci void SetProgress(float progress) 1878bf80f4bSopenharmony_ci { 1888bf80f4bSopenharmony_ci progress = Base::Math::clamp(progress, 0.0f, 1.0f); 1898bf80f4bSopenharmony_ci animationStateTime_->SetValue(progress * GetValue(TotalDuration()).ToSecondsFloat()); 1908bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(Progress)->SetValue(progress); 1918bf80f4bSopenharmony_ci } 1928bf80f4bSopenharmony_ci 1938bf80f4bSopenharmony_ci // void AddKey(IEcsTrackAnimation::Ptr track, float time) override {} 1948bf80f4bSopenharmony_ci // void RemoveKey(IEcsTrackAnimation::Ptr track, uint32_t index) override {} 1958bf80f4bSopenharmony_ci // void UpdateKey(IEcsTrackAnimation::Ptr track, uint32_t oldKeyIndex, uint32_t newKeyIndex, float time) 1968bf80f4bSopenharmony_ci // override {} 1978bf80f4bSopenharmony_ci 1988bf80f4bSopenharmony_ci static constexpr BASE_NS::string_view ANIMATION_COMPONENT_NAME = "AnimationComponent"; 1998bf80f4bSopenharmony_ci static constexpr size_t ANIMATION_COMPONENT_NAME_LEN = ANIMATION_COMPONENT_NAME.size() + 1; 2008bf80f4bSopenharmony_ci static constexpr BASE_NS::string_view ANIMATION_STATE = "AnimationComponent.state"; 2018bf80f4bSopenharmony_ci static constexpr BASE_NS::string_view ANIMATION_REPEATS = "AnimationComponent.repeatCount"; 2028bf80f4bSopenharmony_ci static constexpr BASE_NS::string_view ANIMATION_SOFFSET = "AnimationComponent.startOffset"; 2038bf80f4bSopenharmony_ci static constexpr BASE_NS::string_view ANIMATION_DURATION = "AnimationComponent.duration"; 2048bf80f4bSopenharmony_ci static constexpr BASE_NS::string_view ANIMATION_WEIGHT = "AnimationComponent.weight"; 2058bf80f4bSopenharmony_ci static constexpr BASE_NS::string_view ANIMATION_SPEED = "AnimationComponent.speed"; 2068bf80f4bSopenharmony_ci static constexpr BASE_NS::string_view ANIMATION_TRACKS = "AnimationComponent.tracks"; 2078bf80f4bSopenharmony_ci 2088bf80f4bSopenharmony_ci static constexpr BASE_NS::string_view ANIMATION_STATE_COMPONENT_NAME = "AnimationStateComponent"; 2098bf80f4bSopenharmony_ci static constexpr size_t ANIMATION_STATE_COMPONENT_NAME_LEN = ANIMATION_STATE_COMPONENT_NAME.size() + 1; 2108bf80f4bSopenharmony_ci static constexpr BASE_NS::string_view ANIMATION_STATE_TIME = "AnimationStateComponent.time"; 2118bf80f4bSopenharmony_ci static constexpr BASE_NS::string_view ANIMATION_OPTIONS = "AnimationStateComponent.options"; 2128bf80f4bSopenharmony_ci 2138bf80f4bSopenharmony_ci bool Build(const IMetadata::Ptr& data) override 2148bf80f4bSopenharmony_ci { 2158bf80f4bSopenharmony_ci bool ret = false; 2168bf80f4bSopenharmony_ci if (ret = NodeImpl::Build(data); ret) { 2178bf80f4bSopenharmony_ci PropertyNameMask()[ANIMATION_COMPONENT_NAME] = { ANIMATION_STATE.substr(ANIMATION_COMPONENT_NAME_LEN), 2188bf80f4bSopenharmony_ci ANIMATION_REPEATS.substr(ANIMATION_COMPONENT_NAME_LEN), 2198bf80f4bSopenharmony_ci ANIMATION_SOFFSET.substr(ANIMATION_COMPONENT_NAME_LEN), 2208bf80f4bSopenharmony_ci ANIMATION_DURATION.substr(ANIMATION_COMPONENT_NAME_LEN), 2218bf80f4bSopenharmony_ci ANIMATION_SPEED.substr(ANIMATION_COMPONENT_NAME_LEN), 2228bf80f4bSopenharmony_ci ANIMATION_TRACKS.substr(ANIMATION_COMPONENT_NAME_LEN) }; 2238bf80f4bSopenharmony_ci PropertyNameMask()[ANIMATION_STATE_COMPONENT_NAME] = { ANIMATION_STATE_TIME.substr( 2248bf80f4bSopenharmony_ci ANIMATION_STATE_COMPONENT_NAME_LEN), 2258bf80f4bSopenharmony_ci ANIMATION_OPTIONS.substr(ANIMATION_STATE_COMPONENT_NAME_LEN) }; 2268bf80f4bSopenharmony_ci } 2278bf80f4bSopenharmony_ci return ret; 2288bf80f4bSopenharmony_ci } 2298bf80f4bSopenharmony_ci 2308bf80f4bSopenharmony_ci void SetValid(bool valid) 2318bf80f4bSopenharmony_ci { 2328bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(Valid)->SetValue(valid); 2338bf80f4bSopenharmony_ci if (valid) { 2348bf80f4bSopenharmony_ci if (auto ecsScene = EcsScene()) { 2358bf80f4bSopenharmony_ci // Animation controller does not add animation unless it is valid (i.e. connected) 2368bf80f4bSopenharmony_ci ecsScene->AddApplicationTask(MakeTask( 2378bf80f4bSopenharmony_ci [](const auto& attachment, const auto& controller) { 2388bf80f4bSopenharmony_ci if (attachment && controller) { 2398bf80f4bSopenharmony_ci controller->AddAnimation(attachment); 2408bf80f4bSopenharmony_ci } 2418bf80f4bSopenharmony_ci return false; 2428bf80f4bSopenharmony_ci }, 2438bf80f4bSopenharmony_ci GetSelf<META_NS::IAnimation>(), 2448bf80f4bSopenharmony_ci interface_pointer_cast<META_NS::IAnimationController>(ecsScene)), 2458bf80f4bSopenharmony_ci false); 2468bf80f4bSopenharmony_ci } 2478bf80f4bSopenharmony_ci } 2488bf80f4bSopenharmony_ci } 2498bf80f4bSopenharmony_ci 2508bf80f4bSopenharmony_ci void UpdateTotalDuration() const 2518bf80f4bSopenharmony_ci { 2528bf80f4bSopenharmony_ci const auto speed = animationSpeed_ ? animationSpeed_->GetValue() : 1.f; 2538bf80f4bSopenharmony_ci const auto origDuration = animationOrigDuration_ ? animationOrigDuration_->GetValue() : 0.f; 2548bf80f4bSopenharmony_ci 2558bf80f4bSopenharmony_ci // By default we will play once. 2568bf80f4bSopenharmony_ci float times = 1.0f; 2578bf80f4bSopenharmony_ci 2588bf80f4bSopenharmony_ci // In case we have repeats requested, then play also them. 2598bf80f4bSopenharmony_ci if (animationRepeatCount_) { 2608bf80f4bSopenharmony_ci times += static_cast<float>(animationRepeatCount_->GetValue()); 2618bf80f4bSopenharmony_ci } 2628bf80f4bSopenharmony_ci const auto newTotalDuration = 2638bf80f4bSopenharmony_ci speed != 0.f ? META_NS::TimeSpan::Seconds(origDuration * times / speed) : META_NS::TimeSpan::Infinite(); 2648bf80f4bSopenharmony_ci 2658bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(TotalDuration)->SetValue(newTotalDuration); 2668bf80f4bSopenharmony_ci } 2678bf80f4bSopenharmony_ci 2688bf80f4bSopenharmony_ci void UpdateProgress() const 2698bf80f4bSopenharmony_ci { 2708bf80f4bSopenharmony_ci const auto currentTime = animationStateTime_ ? animationStateTime_->GetValue() : 0.f; 2718bf80f4bSopenharmony_ci const auto totalDuration = TotalDuration()->GetValue().ToSecondsFloat(); 2728bf80f4bSopenharmony_ci const auto newProgress = totalDuration != 0.f ? currentTime / totalDuration : 1.f; 2738bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(Progress)->SetValue(newProgress); 2748bf80f4bSopenharmony_ci } 2758bf80f4bSopenharmony_ci 2768bf80f4bSopenharmony_ci bool CompleteInitialization(const BASE_NS::string& path) override 2778bf80f4bSopenharmony_ci { 2788bf80f4bSopenharmony_ci // At the end we would not even like to call this, to be refactored 2798bf80f4bSopenharmony_ci if (!NodeImpl::CompleteInitialization(path)) { 2808bf80f4bSopenharmony_ci return false; 2818bf80f4bSopenharmony_ci } 2828bf80f4bSopenharmony_ci 2838bf80f4bSopenharmony_ci auto meta = interface_pointer_cast<META_NS::IMetadata>(ecsObject_); 2848bf80f4bSopenharmony_ci BindChanges(propHandler_, Name(), meta, "Name"); 2858bf80f4bSopenharmony_ci // Track timestamps do not scale automatically when total duration changes, have engine duration separated 2868bf80f4bSopenharmony_ci // from ours BindChanges<float, META_NS::TimeSpan>( 2878bf80f4bSopenharmony_ci 2888bf80f4bSopenharmony_ci animationState_ = meta->GetPropertyByName<uint8_t>(ANIMATION_STATE); 2898bf80f4bSopenharmony_ci animationOptions_ = meta->GetPropertyByName<uint8_t>(ANIMATION_OPTIONS); 2908bf80f4bSopenharmony_ci animationStateTime_ = meta->GetPropertyByName<float>(ANIMATION_STATE_TIME); 2918bf80f4bSopenharmony_ci animationSpeed_ = meta->GetPropertyByName<float>(ANIMATION_SPEED); 2928bf80f4bSopenharmony_ci animationRepeatCount_ = meta->GetPropertyByName<uint32_t>(ANIMATION_REPEATS); 2938bf80f4bSopenharmony_ci animationOrigDuration_ = meta->GetPropertyByName<float>(ANIMATION_DURATION); 2948bf80f4bSopenharmony_ci if (animationSpeed_) { 2958bf80f4bSopenharmony_ci propHandler_.NewHandler(nullptr, nullptr).Subscribe(animationSpeed_, [this]() { UpdateTotalDuration(); }); 2968bf80f4bSopenharmony_ci } 2978bf80f4bSopenharmony_ci if (animationRepeatCount_) { 2988bf80f4bSopenharmony_ci propHandler_.NewHandler(nullptr, nullptr).Subscribe(animationRepeatCount_, [this]() { 2998bf80f4bSopenharmony_ci UpdateTotalDuration(); 3008bf80f4bSopenharmony_ci }); 3018bf80f4bSopenharmony_ci } 3028bf80f4bSopenharmony_ci if (animationOrigDuration_) { 3038bf80f4bSopenharmony_ci propHandler_.NewHandler(nullptr, nullptr).Subscribe(animationOrigDuration_, [this]() { 3048bf80f4bSopenharmony_ci UpdateTotalDuration(); 3058bf80f4bSopenharmony_ci }); 3068bf80f4bSopenharmony_ci } 3078bf80f4bSopenharmony_ci if (animationStateTime_) { 3088bf80f4bSopenharmony_ci propHandler_.NewHandler(nullptr, nullptr).Subscribe(animationStateTime_, [this]() { UpdateProgress(); }); 3098bf80f4bSopenharmony_ci } 3108bf80f4bSopenharmony_ci propHandler_.NewHandler(nullptr, nullptr).Subscribe(Enabled(), [this] { 3118bf80f4bSopenharmony_ci if (!Enabled()->GetValue()) { 3128bf80f4bSopenharmony_ci InternalStop(); 3138bf80f4bSopenharmony_ci } 3148bf80f4bSopenharmony_ci }); 3158bf80f4bSopenharmony_ci TotalDuration()->OnChanged()->AddHandler( 3168bf80f4bSopenharmony_ci META_NS::MakeCallback<META_NS::IOnChanged>([this] { UpdateProgress(); })); 3178bf80f4bSopenharmony_ci if (animationOptions_) { 3188bf80f4bSopenharmony_ci animationOptions_->SetValue(0); 3198bf80f4bSopenharmony_ci } 3208bf80f4bSopenharmony_ci 3218bf80f4bSopenharmony_ci if (animationStateTime_) { 3228bf80f4bSopenharmony_ci } 3238bf80f4bSopenharmony_ci if (animationRepeatCount_) { 3248bf80f4bSopenharmony_ci animationRepeatCount_->SetValue(0); 3258bf80f4bSopenharmony_ci } 3268bf80f4bSopenharmony_ci UpdateTotalDuration(); 3278bf80f4bSopenharmony_ci 3288bf80f4bSopenharmony_ci // properties are suitable for direct value binding, adding the custom handlers for the rest: 3298bf80f4bSopenharmony_ci 3308bf80f4bSopenharmony_ci // We interpret the animation valid if it is connected 3318bf80f4bSopenharmony_ci SetValid(true); 3328bf80f4bSopenharmony_ci 3338bf80f4bSopenharmony_ci propHandler_.NewHandler(nullptr, nullptr) 3348bf80f4bSopenharmony_ci .Subscribe(META_ACCESS_PROPERTY(ConnectionStatus), META_NS::MakeCallback<META_NS::IOnChanged>([this]() { 3358bf80f4bSopenharmony_ci SetValid(META_ACCESS_PROPERTY(ConnectionStatus)->GetValue() == ECS_OBJ_STATUS_CONNECTED); 3368bf80f4bSopenharmony_ci })); 3378bf80f4bSopenharmony_ci 3388bf80f4bSopenharmony_ci propHandler_.NewHandler(nullptr, nullptr) 3398bf80f4bSopenharmony_ci .Subscribe(META_ACCESS_PROPERTY(Progress), META_NS::MakeCallback<META_NS::IOnChanged>([this]() { 3408bf80f4bSopenharmony_ci if (META_NS::GetValue(META_ACCESS_PROPERTY(Progress)) >= 1.0f) { 3418bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(Running)->SetValue(false); 3428bf80f4bSopenharmony_ci META_NS::Invoke<META_NS::IOnChanged>(OnFinished()); 3438bf80f4bSopenharmony_ci } 3448bf80f4bSopenharmony_ci })); 3458bf80f4bSopenharmony_ci return true; 3468bf80f4bSopenharmony_ci } 3478bf80f4bSopenharmony_ci 3488bf80f4bSopenharmony_ci bool BuildChildren(SCENE_NS::INode::BuildBehavior) override 3498bf80f4bSopenharmony_ci { 3508bf80f4bSopenharmony_ci // in typical cases we should not have children 3518bf80f4bSopenharmony_ci if (META_NS::GetValue(META_ACCESS_PROPERTY(Status)) == SCENE_NS::INode::NODE_STATUS_CONNECTED) { 3528bf80f4bSopenharmony_ci SetStatus(SCENE_NS::INode::NODE_STATUS_FULLY_CONNECTED); 3538bf80f4bSopenharmony_ci META_NS::Invoke<META_NS::IOnChanged>(OnBound()); 3548bf80f4bSopenharmony_ci bound_ = true; 3558bf80f4bSopenharmony_ci } 3568bf80f4bSopenharmony_ci return true; 3578bf80f4bSopenharmony_ci } 3588bf80f4bSopenharmony_ci 3598bf80f4bSopenharmony_ci void AttachModifier(const BASE_NS::shared_ptr<META_NS::IAnimationModifier>& attachment); 3608bf80f4bSopenharmony_ci void DetachModifier(const BASE_NS::shared_ptr<META_NS::IAnimationModifier>& attachment); 3618bf80f4bSopenharmony_ci 3628bf80f4bSopenharmony_ci mutable META_NS::EventImpl<META_NS::IOnChanged> onFinished_; 3638bf80f4bSopenharmony_ci mutable META_NS::EventImpl<META_NS::IOnChanged> onStarted_; 3648bf80f4bSopenharmony_ci 3658bf80f4bSopenharmony_ci META_NS::Property<float> animationStateTime_; 3668bf80f4bSopenharmony_ci META_NS::Property<float> animationSpeed_; 3678bf80f4bSopenharmony_ci META_NS::Property<float> animationOrigDuration_; 3688bf80f4bSopenharmony_ci META_NS::Property<uint8_t> animationOptions_; 3698bf80f4bSopenharmony_ci META_NS::Property<uint8_t> animationState_; 3708bf80f4bSopenharmony_ci META_NS::Property<uint32_t> animationRepeatCount_; 3718bf80f4bSopenharmony_ci}; 3728bf80f4bSopenharmony_cistruct LoopCountConverter { 3738bf80f4bSopenharmony_ci static uint32_t ToEcs(SceneHolder& sceneHolder, const int32_t& v) 3748bf80f4bSopenharmony_ci { 3758bf80f4bSopenharmony_ci return v < 0 ? CORE3D_NS::AnimationComponent::REPEAT_COUNT_INFINITE : static_cast<uint32_t>(v); 3768bf80f4bSopenharmony_ci } 3778bf80f4bSopenharmony_ci static int32_t ToUi(SceneHolder& sceneHolder, const uint32_t& v) 3788bf80f4bSopenharmony_ci { 3798bf80f4bSopenharmony_ci return v == CORE3D_NS::AnimationComponent::REPEAT_COUNT_INFINITE ? -1 : static_cast<int32_t>(v); 3808bf80f4bSopenharmony_ci } 3818bf80f4bSopenharmony_ci}; 3828bf80f4bSopenharmony_ci 3838bf80f4bSopenharmony_cibool AnimImpl::Attach(const BASE_NS::shared_ptr<META_NS::IObject>& attachment, const IObject::Ptr& dataContext) 3848bf80f4bSopenharmony_ci{ 3858bf80f4bSopenharmony_ci if (auto am = interface_pointer_cast<META_NS::IAnimationModifier>(attachment)) { 3868bf80f4bSopenharmony_ci AttachModifier(am); 3878bf80f4bSopenharmony_ci } 3888bf80f4bSopenharmony_ci return Super::Attach(attachment, dataContext); 3898bf80f4bSopenharmony_ci} 3908bf80f4bSopenharmony_ci 3918bf80f4bSopenharmony_cibool AnimImpl::Detach(const META_NS::IObject::Ptr& attachment) 3928bf80f4bSopenharmony_ci{ 3938bf80f4bSopenharmony_ci if (auto am = interface_pointer_cast<META_NS::IAnimationModifier>(attachment)) { 3948bf80f4bSopenharmony_ci DetachModifier(am); 3958bf80f4bSopenharmony_ci } 3968bf80f4bSopenharmony_ci return Super::Detach(attachment); 3978bf80f4bSopenharmony_ci} 3988bf80f4bSopenharmony_ci 3998bf80f4bSopenharmony_civoid AnimImpl::AttachModifier(const BASE_NS::shared_ptr<META_NS::IAnimationModifier>& attachment) 4008bf80f4bSopenharmony_ci{ 4018bf80f4bSopenharmony_ci if (auto loop = interface_pointer_cast<META_NS::AnimationModifiers::ILoop>(attachment)) { 4028bf80f4bSopenharmony_ci BindPropChanges<int32_t, uint32_t, LoopCountConverter>(propHandler_, loop->LoopCount(), animationRepeatCount_); 4038bf80f4bSopenharmony_ci } else if (auto speed = interface_pointer_cast<META_NS::AnimationModifiers::ISpeed>(attachment)) { 4048bf80f4bSopenharmony_ci BindPropChanges<float, float>(propHandler_, speed->SpeedFactor(), animationSpeed_); 4058bf80f4bSopenharmony_ci } else { 4068bf80f4bSopenharmony_ci CORE_LOG_E("Not implemented!"); 4078bf80f4bSopenharmony_ci } 4088bf80f4bSopenharmony_ci} 4098bf80f4bSopenharmony_civoid AnimImpl::DetachModifier(const BASE_NS::shared_ptr<META_NS::IAnimationModifier>& attachment) 4108bf80f4bSopenharmony_ci{ 4118bf80f4bSopenharmony_ci if (auto loop = interface_pointer_cast<META_NS::AnimationModifiers::ILoop>(attachment)) { 4128bf80f4bSopenharmony_ci propHandler_.EraseHandler(animationRepeatCount_, loop->LoopCount()); 4138bf80f4bSopenharmony_ci animationRepeatCount_->SetValue(0); 4148bf80f4bSopenharmony_ci } else if (auto speed = interface_pointer_cast<META_NS::AnimationModifiers::ISpeed>(attachment)) { 4158bf80f4bSopenharmony_ci propHandler_.EraseHandler(animationSpeed_, speed->SpeedFactor()); 4168bf80f4bSopenharmony_ci animationSpeed_->SetValue(1.f); 4178bf80f4bSopenharmony_ci } else { 4188bf80f4bSopenharmony_ci CORE_LOG_E("Not implemented!"); 4198bf80f4bSopenharmony_ci } 4208bf80f4bSopenharmony_ci} 4218bf80f4bSopenharmony_ci} // namespace 4228bf80f4bSopenharmony_ciSCENE_BEGIN_NAMESPACE() 4238bf80f4bSopenharmony_ci 4248bf80f4bSopenharmony_civoid RegisterAnimImpl() 4258bf80f4bSopenharmony_ci{ 4268bf80f4bSopenharmony_ci META_NS::GetObjectRegistry().RegisterObjectType<AnimImpl>(); 4278bf80f4bSopenharmony_ci} 4288bf80f4bSopenharmony_civoid UnregisterAnimImpl() 4298bf80f4bSopenharmony_ci{ 4308bf80f4bSopenharmony_ci META_NS::GetObjectRegistry().UnregisterObjectType<AnimImpl>(); 4318bf80f4bSopenharmony_ci} 4328bf80f4bSopenharmony_ciSCENE_END_NAMESPACE(); 433