1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <scene_plugin/api/scene_uid.h>
16 
17 #include <3d/ecs/components/mesh_component.h>
18 
19 #include <meta/ext/concrete_base_object.h>
20 #include <meta/interface/animation/modifiers/intf_loop.h>
21 #include <meta/interface/animation/modifiers/intf_speed.h>
22 
23 #include "bind_templates.inl"
24 #include "intf_node_private.h"
25 #include "intf_submesh_bridge.h"
26 #include "node_impl.h"
27 #include "submesh_handler_uid.h"
28 #include "task_utils.h"
29 
30 using SCENE_NS::MakeTask;
31 namespace {
32 class AnimImpl
33     : public META_NS::ConcreteBaseMetaObjectFwd<AnimImpl, NodeImpl, SCENE_NS::ClassId::Animation,
34           META_NS::IParallelAnimation, META_NS::IAttachment, META_NS::ITimedAnimation, META_NS::IStartableAnimation> {
35     using Super = META_NS::ConcreteBaseMetaObjectFwd<AnimImpl, NodeImpl, SCENE_NS::ClassId::Animation,
36         META_NS::IParallelAnimation, META_NS::IAttachment, META_NS::ITimedAnimation, META_NS::IStartableAnimation>;
37 
38     // From IEcsAnimation
39     // META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IEcsAnimation, bool, ReadOnly, false,
40     // META_NS::DefaultPropFlags::R_FLAGS)
41 
42     // From INamed
43     META_IMPLEMENT_INTERFACE_PROPERTY(META_NS::INamed, BASE_NS::string, Name, {})
44 
45     // From IAnimation
46     META_IMPLEMENT_INTERFACE_PROPERTY(IAnimation, bool, Enabled, true)
47     META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, bool, Valid, false, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
48     META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, META_NS::TimeSpan, TotalDuration,
49         META_NS::TimeSpan::Milliseconds(500), META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
50     META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, bool, Running, false, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
51     META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(IAnimation, float, Progress, 0, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
52     META_IMPLEMENT_INTERFACE_PROPERTY(IAnimation, META_NS::ICurve1D::Ptr, Curve)
53     META_IMPLEMENT_INTERFACE_PROPERTY(
54         IAnimation, META_NS::IAnimationController::WeakPtr, Controller, {}, META_NS::DEFAULT_PROPERTY_FLAGS_NO_SER)
55 
56     // from IAttachment IAnimationWithModifiableDuration
57     META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(META_NS::IAttachment, META_NS::IObject::WeakPtr, DataContext)
58     META_IMPLEMENT_INTERFACE_READONLY_PROPERTY(META_NS::IAttachment, META_NS::IAttach::WeakPtr, AttachedTo)
59 
60     // from ITimedAnimation
61     META_IMPLEMENT_INTERFACE_PROPERTY(
62         META_NS::ITimedAnimation, META_NS::TimeSpan, Duration, META_NS::TimeSpan::Milliseconds(500))
63 
64     META_IMPLEMENT_EVENT(META_NS::IOnChanged, OnFinished)
65     META_IMPLEMENT_EVENT(META_NS::IOnChanged, OnStarted)
66 
67     // IAttach
68     bool Attach(
69         const BASE_NS::shared_ptr<META_NS::IObject>& attachment, const META_NS::IObject::Ptr& dataContext) override;
70     bool Detach(const META_NS::IObject::Ptr& attachment) override;
71 
72     /**
73      * @brief Called by the framework when an the attachment is being attached to an IObject. If this
74      *        function succeeds, the object is attached to the target.
75      * @param object The IObject instance the attachment is attached to.
76      * @param dataContext The data context for this attachment.
77      * @note The data context can be the same object as the object being attached to, or
78      *       something else. It is up to the attachment to decide how to handle them.
79      * @return The implementation should return true if the attachment can be attached to target object.
80      *         If the attachment cannot be added, the implementation should return false.
81      */
Attaching(const IAttach::Ptr & target,const IObject::Ptr & dataContext)82     bool Attaching(const IAttach::Ptr& target, const IObject::Ptr& dataContext) override
83     {
84         META_ACCESS_PROPERTY(AttachedTo)->SetValue(target);
85         META_ACCESS_PROPERTY(DataContext)->SetValue(dataContext);
86         return true;
87     }
88     /**
89      * @brief Detach the attachment from an object.
90      * @param object The object to attach to.
91      * @return If the attachment can be detached from the target, the implementation should return true.
92      *         If detaching is not possible, the implementation should return false. In such a case the
93      *         target may choose to not remove the attachment. During for example object destruction,
94      *         the target will ignore the return value.
95      */
Detaching(const IAttach::Ptr & target)96     bool Detaching(const IAttach::Ptr& target) override
97     {
98         META_ACCESS_PROPERTY(AttachedTo)->SetValue({});
99         META_ACCESS_PROPERTY(DataContext)->SetValue({});
100 
101         // TODO: Remove this line of code, once framework automatically removes animations
102         // from animation controller when objects are destroyed.
103 
104         auto animation = GetSelf<IAnimation>();
105         if (animation) {
106             auto controller = META_NS::GetValue(animation->Controller()).lock();
107             if (controller) {
108                 controller->RemoveAnimation(animation);
109             }
110         }
111 
112         return true;
113     }
114 
AddAnimation(const IAnimation::Ptr &)115     void AddAnimation(const IAnimation::Ptr&) override {}
RemoveAnimation(const IAnimation::Ptr &)116     void RemoveAnimation(const IAnimation::Ptr&) override {}
117 
GetAnimations() const118     BASE_NS::vector<META_NS::IAnimation::Ptr> GetAnimations() const override
119     {
120         return {};
121     }
122 
Step(const META_NS::IClock::ConstPtr & clock)123     void Step(const META_NS::IClock::ConstPtr& clock) override
124     {
125         // Nothing to do. Animation is stepped by Engine.
126     }
127 
Start()128     void Start() override
129     {
130         // Set ecs animation to pause
131 	if (META_ACCESS_PROPERTY_VALUE(Enabled)) {
132             META_NS::SetValue(animationState_, (uint8_t)CORE3D_NS::AnimationComponent::PlaybackState::PLAY);
133 
134             META_ACCESS_PROPERTY(Running)->SetValue(true);
135             META_NS::Invoke<META_NS::IOnChanged>(OnStarted());
136         }
137     }
138 
InternalStop()139     void InternalStop()
140     {
141         // Set ecs animation to pause
142         META_NS::SetValue(animationState_, (uint8_t)CORE3D_NS::AnimationComponent::PlaybackState::STOP);
143         META_ACCESS_PROPERTY(Running)->SetValue(false);
144         SetProgress(0.0f);
145     }
146 
Stop()147     void Stop() override
148     {
149 	if (META_ACCESS_PROPERTY_VALUE(Enabled)) {
150             InternalStop();
151 	}
152     }
153 
Pause()154     void Pause() override
155     {
156         if (META_ACCESS_PROPERTY_VALUE(Enabled)) {
157             META_NS::SetValue(animationState_, (uint8_t)CORE3D_NS::AnimationComponent::PlaybackState::PAUSE);
158             META_ACCESS_PROPERTY(Running)->SetValue(false);
159         }
160     }
161 
Restart()162     void Restart() override
163     {
164         Stop();
165         Start();
166     }
167 
Finish()168     void Finish() override
169     {
170         if (META_ACCESS_PROPERTY_VALUE(Enabled)) {
171             META_NS::SetValue(animationState_, (uint8_t)CORE3D_NS::AnimationComponent::PlaybackState::STOP);
172             META_ACCESS_PROPERTY(Running)->SetValue(false);
173             Seek(1.0f);
174             META_NS::Invoke<META_NS::IOnChanged>(OnFinished());
175         }
176     }
177 
Seek(float position)178     void Seek(float position) override
179     {
180         if (META_ACCESS_PROPERTY_VALUE(Enabled)) {
181             position = BASE_NS::Math::clamp01(position);
182             SetProgress(position);
183         }
184     }
185 
SetProgress(float progress)186     void SetProgress(float progress)
187     {
188         progress = Base::Math::clamp(progress, 0.0f, 1.0f);
189         animationStateTime_->SetValue(progress * GetValue(TotalDuration()).ToSecondsFloat());
190         META_ACCESS_PROPERTY(Progress)->SetValue(progress);
191     }
192 
193     // void AddKey(IEcsTrackAnimation::Ptr track, float time) override {}
194     // void RemoveKey(IEcsTrackAnimation::Ptr track, uint32_t index) override {}
195     // void UpdateKey(IEcsTrackAnimation::Ptr track, uint32_t oldKeyIndex, uint32_t newKeyIndex, float time)
196     // override {}
197 
198     static constexpr BASE_NS::string_view ANIMATION_COMPONENT_NAME = "AnimationComponent";
199     static constexpr size_t ANIMATION_COMPONENT_NAME_LEN = ANIMATION_COMPONENT_NAME.size() + 1;
200     static constexpr BASE_NS::string_view ANIMATION_STATE = "AnimationComponent.state";
201     static constexpr BASE_NS::string_view ANIMATION_REPEATS = "AnimationComponent.repeatCount";
202     static constexpr BASE_NS::string_view ANIMATION_SOFFSET = "AnimationComponent.startOffset";
203     static constexpr BASE_NS::string_view ANIMATION_DURATION = "AnimationComponent.duration";
204     static constexpr BASE_NS::string_view ANIMATION_WEIGHT = "AnimationComponent.weight";
205     static constexpr BASE_NS::string_view ANIMATION_SPEED = "AnimationComponent.speed";
206     static constexpr BASE_NS::string_view ANIMATION_TRACKS = "AnimationComponent.tracks";
207 
208     static constexpr BASE_NS::string_view ANIMATION_STATE_COMPONENT_NAME = "AnimationStateComponent";
209     static constexpr size_t ANIMATION_STATE_COMPONENT_NAME_LEN = ANIMATION_STATE_COMPONENT_NAME.size() + 1;
210     static constexpr BASE_NS::string_view ANIMATION_STATE_TIME = "AnimationStateComponent.time";
211     static constexpr BASE_NS::string_view ANIMATION_OPTIONS = "AnimationStateComponent.options";
212 
Build(const IMetadata::Ptr & data)213     bool Build(const IMetadata::Ptr& data) override
214     {
215         bool ret = false;
216         if (ret = NodeImpl::Build(data); ret) {
217             PropertyNameMask()[ANIMATION_COMPONENT_NAME] = { ANIMATION_STATE.substr(ANIMATION_COMPONENT_NAME_LEN),
218                 ANIMATION_REPEATS.substr(ANIMATION_COMPONENT_NAME_LEN),
219                 ANIMATION_SOFFSET.substr(ANIMATION_COMPONENT_NAME_LEN),
220                 ANIMATION_DURATION.substr(ANIMATION_COMPONENT_NAME_LEN),
221                 ANIMATION_SPEED.substr(ANIMATION_COMPONENT_NAME_LEN),
222                 ANIMATION_TRACKS.substr(ANIMATION_COMPONENT_NAME_LEN) };
223             PropertyNameMask()[ANIMATION_STATE_COMPONENT_NAME] = { ANIMATION_STATE_TIME.substr(
224                                                                        ANIMATION_STATE_COMPONENT_NAME_LEN),
225                 ANIMATION_OPTIONS.substr(ANIMATION_STATE_COMPONENT_NAME_LEN) };
226         }
227         return ret;
228     }
229 
SetValid(bool valid)230     void SetValid(bool valid)
231     {
232         META_ACCESS_PROPERTY(Valid)->SetValue(valid);
233         if (valid) {
234             if (auto ecsScene = EcsScene()) {
235                 // Animation controller does not add animation unless it is valid (i.e. connected)
236                 ecsScene->AddApplicationTask(MakeTask(
237                                                  [](const auto& attachment, const auto& controller) {
238                                                      if (attachment && controller) {
239                                                          controller->AddAnimation(attachment);
240                                                      }
241                                                      return false;
242                                                  },
243                                                  GetSelf<META_NS::IAnimation>(),
244                                                  interface_pointer_cast<META_NS::IAnimationController>(ecsScene)),
245                     false);
246             }
247         }
248     }
249 
UpdateTotalDuration() const250     void UpdateTotalDuration() const
251     {
252         const auto speed = animationSpeed_ ? animationSpeed_->GetValue() : 1.f;
253         const auto origDuration = animationOrigDuration_ ? animationOrigDuration_->GetValue() : 0.f;
254 
255 	// By default we will play once.
256 	float times = 1.0f;
257 
258         // In case we have repeats requested, then play also them.
259         if (animationRepeatCount_) {
260             times += static_cast<float>(animationRepeatCount_->GetValue());
261         }
262         const auto newTotalDuration =
263             speed != 0.f ? META_NS::TimeSpan::Seconds(origDuration * times / speed) : META_NS::TimeSpan::Infinite();
264 
265         META_ACCESS_PROPERTY(TotalDuration)->SetValue(newTotalDuration);
266     }
267 
UpdateProgress() const268     void UpdateProgress() const
269     {
270         const auto currentTime = animationStateTime_ ? animationStateTime_->GetValue() : 0.f;
271         const auto totalDuration = TotalDuration()->GetValue().ToSecondsFloat();
272         const auto newProgress = totalDuration != 0.f ? currentTime / totalDuration : 1.f;
273         META_ACCESS_PROPERTY(Progress)->SetValue(newProgress);
274     }
275 
CompleteInitialization(const BASE_NS::string & path)276     bool CompleteInitialization(const BASE_NS::string& path) override
277     {
278         // At the end we would not even like to call this, to be refactored
279         if (!NodeImpl::CompleteInitialization(path)) {
280             return false;
281         }
282 
283         auto meta = interface_pointer_cast<META_NS::IMetadata>(ecsObject_);
284         BindChanges(propHandler_, Name(), meta, "Name");
285         // Track timestamps do not scale automatically when total duration changes, have engine duration separated
286         // from ours BindChanges<float, META_NS::TimeSpan>(
287 
288         animationState_ = meta->GetPropertyByName<uint8_t>(ANIMATION_STATE);
289         animationOptions_ = meta->GetPropertyByName<uint8_t>(ANIMATION_OPTIONS);
290         animationStateTime_ = meta->GetPropertyByName<float>(ANIMATION_STATE_TIME);
291         animationSpeed_ = meta->GetPropertyByName<float>(ANIMATION_SPEED);
292         animationRepeatCount_ = meta->GetPropertyByName<uint32_t>(ANIMATION_REPEATS);
293         animationOrigDuration_ = meta->GetPropertyByName<float>(ANIMATION_DURATION);
294         if (animationSpeed_) {
295             propHandler_.NewHandler(nullptr, nullptr).Subscribe(animationSpeed_, [this]() { UpdateTotalDuration(); });
296         }
297         if (animationRepeatCount_) {
298             propHandler_.NewHandler(nullptr, nullptr).Subscribe(animationRepeatCount_, [this]() {
299                 UpdateTotalDuration();
300             });
301         }
302         if (animationOrigDuration_) {
303             propHandler_.NewHandler(nullptr, nullptr).Subscribe(animationOrigDuration_, [this]() {
304                 UpdateTotalDuration();
305             });
306         }
307         if (animationStateTime_) {
308             propHandler_.NewHandler(nullptr, nullptr).Subscribe(animationStateTime_, [this]() { UpdateProgress(); });
309         }
310         propHandler_.NewHandler(nullptr, nullptr).Subscribe(Enabled(), [this] {
311             if (!Enabled()->GetValue()) {
312                 InternalStop();
313             }
314         });
315         TotalDuration()->OnChanged()->AddHandler(
316             META_NS::MakeCallback<META_NS::IOnChanged>([this] { UpdateProgress(); }));
317         if (animationOptions_) {
318             animationOptions_->SetValue(0);
319         }
320 
321         if (animationStateTime_) {
322         }
323         if (animationRepeatCount_) {
324             animationRepeatCount_->SetValue(0);
325         }
326         UpdateTotalDuration();
327 
328         // properties are suitable for direct value binding, adding the custom handlers for the rest:
329 
330         // We interpret the animation valid if it is connected
331         SetValid(true);
332 
333         propHandler_.NewHandler(nullptr, nullptr)
334             .Subscribe(META_ACCESS_PROPERTY(ConnectionStatus), META_NS::MakeCallback<META_NS::IOnChanged>([this]() {
335                 SetValid(META_ACCESS_PROPERTY(ConnectionStatus)->GetValue() == ECS_OBJ_STATUS_CONNECTED);
336             }));
337 
338         propHandler_.NewHandler(nullptr, nullptr)
339             .Subscribe(META_ACCESS_PROPERTY(Progress), META_NS::MakeCallback<META_NS::IOnChanged>([this]() {
340                 if (META_NS::GetValue(META_ACCESS_PROPERTY(Progress)) >= 1.0f) {
341                     META_ACCESS_PROPERTY(Running)->SetValue(false);
342                     META_NS::Invoke<META_NS::IOnChanged>(OnFinished());
343                 }
344             }));
345         return true;
346     }
347 
BuildChildren(SCENE_NS::INode::BuildBehavior)348     bool BuildChildren(SCENE_NS::INode::BuildBehavior) override
349     {
350         // in typical cases we should not have children
351         if (META_NS::GetValue(META_ACCESS_PROPERTY(Status)) == SCENE_NS::INode::NODE_STATUS_CONNECTED) {
352             SetStatus(SCENE_NS::INode::NODE_STATUS_FULLY_CONNECTED);
353             META_NS::Invoke<META_NS::IOnChanged>(OnBound());
354             bound_ = true;
355         }
356         return true;
357     }
358 
359     void AttachModifier(const BASE_NS::shared_ptr<META_NS::IAnimationModifier>& attachment);
360     void DetachModifier(const BASE_NS::shared_ptr<META_NS::IAnimationModifier>& attachment);
361 
362     mutable META_NS::EventImpl<META_NS::IOnChanged> onFinished_;
363     mutable META_NS::EventImpl<META_NS::IOnChanged> onStarted_;
364 
365     META_NS::Property<float> animationStateTime_;
366     META_NS::Property<float> animationSpeed_;
367     META_NS::Property<float> animationOrigDuration_;
368     META_NS::Property<uint8_t> animationOptions_;
369     META_NS::Property<uint8_t> animationState_;
370     META_NS::Property<uint32_t> animationRepeatCount_;
371 };
372 struct LoopCountConverter {
ToEcs__anona08761e50110::LoopCountConverter373     static uint32_t ToEcs(SceneHolder& sceneHolder, const int32_t& v)
374     {
375         return v < 0 ? CORE3D_NS::AnimationComponent::REPEAT_COUNT_INFINITE : static_cast<uint32_t>(v);
376     }
ToUi__anona08761e50110::LoopCountConverter377     static int32_t ToUi(SceneHolder& sceneHolder, const uint32_t& v)
378     {
379         return v == CORE3D_NS::AnimationComponent::REPEAT_COUNT_INFINITE ? -1 : static_cast<int32_t>(v);
380     }
381 };
382 
Attach(const BASE_NS::shared_ptr<META_NS::IObject> & attachment,const IObject::Ptr & dataContext)383 bool AnimImpl::Attach(const BASE_NS::shared_ptr<META_NS::IObject>& attachment, const IObject::Ptr& dataContext)
384 {
385     if (auto am = interface_pointer_cast<META_NS::IAnimationModifier>(attachment)) {
386         AttachModifier(am);
387     }
388     return Super::Attach(attachment, dataContext);
389 }
390 
Detach(const META_NS::IObject::Ptr & attachment)391 bool AnimImpl::Detach(const META_NS::IObject::Ptr& attachment)
392 {
393     if (auto am = interface_pointer_cast<META_NS::IAnimationModifier>(attachment)) {
394         DetachModifier(am);
395     }
396     return Super::Detach(attachment);
397 }
398 
AttachModifier(const BASE_NS::shared_ptr<META_NS::IAnimationModifier> & attachment)399 void AnimImpl::AttachModifier(const BASE_NS::shared_ptr<META_NS::IAnimationModifier>& attachment)
400 {
401     if (auto loop = interface_pointer_cast<META_NS::AnimationModifiers::ILoop>(attachment)) {
402         BindPropChanges<int32_t, uint32_t, LoopCountConverter>(propHandler_, loop->LoopCount(), animationRepeatCount_);
403     } else if (auto speed = interface_pointer_cast<META_NS::AnimationModifiers::ISpeed>(attachment)) {
404         BindPropChanges<float, float>(propHandler_, speed->SpeedFactor(), animationSpeed_);
405     } else {
406         CORE_LOG_E("Not implemented!");
407     }
408 }
DetachModifier(const BASE_NS::shared_ptr<META_NS::IAnimationModifier> & attachment)409 void AnimImpl::DetachModifier(const BASE_NS::shared_ptr<META_NS::IAnimationModifier>& attachment)
410 {
411     if (auto loop = interface_pointer_cast<META_NS::AnimationModifiers::ILoop>(attachment)) {
412         propHandler_.EraseHandler(animationRepeatCount_, loop->LoopCount());
413         animationRepeatCount_->SetValue(0);
414     } else if (auto speed = interface_pointer_cast<META_NS::AnimationModifiers::ISpeed>(attachment)) {
415         propHandler_.EraseHandler(animationSpeed_, speed->SpeedFactor());
416         animationSpeed_->SetValue(1.f);
417     } else {
418         CORE_LOG_E("Not implemented!");
419     }
420 }
421 } // namespace
SCENE_BEGIN_NAMESPACE()422 SCENE_BEGIN_NAMESPACE()
423 
424 void RegisterAnimImpl()
425 {
426     META_NS::GetObjectRegistry().RegisterObjectType<AnimImpl>();
427 }
UnregisterAnimImpl()428 void UnregisterAnimImpl()
429 {
430     META_NS::GetObjectRegistry().UnregisterObjectType<AnimImpl>();
431 }
432 SCENE_END_NAMESPACE();
433