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