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
16 #include "ecs_animation.h"
17
18 #include <meta/api/make_callback.h>
19 #include <meta/interface/animation/modifiers/intf_loop.h>
20 #include <meta/interface/animation/modifiers/intf_speed.h>
21
22 #include "converting_value.h"
23
24 SCENE_BEGIN_NAMESPACE()
25
26 struct LoopCountConverter {
27 using SourceType = int32_t;
28 using TargetType = uint32_t;
ConvertToSourceLoopCountConverter29 static SourceType ConvertToSource(META_NS::IAny&, const TargetType& v)
30 {
31 return v == CORE3D_NS::AnimationComponent::REPEAT_COUNT_INFINITE ? -1 : static_cast<int32_t>(v) + 1;
32 }
ConvertToTargetLoopCountConverter33 static TargetType ConvertToTarget(const SourceType& v)
34 {
35 // we don't support v == 0 to stop animation for now
36 return v <= 0 ? CORE3D_NS::AnimationComponent::REPEAT_COUNT_INFINITE : static_cast<uint32_t>(v) - 1;
37 }
38 };
39
~EcsAnimation()40 EcsAnimation::~EcsAnimation()
41 {
42 if (anim_) {
43 anim_->Time()->OnChanged()->RemoveHandler(intptr_t(this));
44 anim_->Speed()->OnChanged()->RemoveHandler(intptr_t(this));
45 anim_->RepeatCount()->OnChanged()->RemoveHandler(intptr_t(this));
46 anim_->Duration()->OnChanged()->RemoveHandler(intptr_t(this));
47 }
48 }
49
SetEcsObject(const IEcsObject::Ptr & obj)50 bool EcsAnimation::SetEcsObject(const IEcsObject::Ptr& obj)
51 {
52 auto p = META_NS::GetObjectRegistry().Create<IInternalAnimation>(ClassId::AnimationComponent);
53 if (auto acc = interface_cast<IEcsObjectAccess>(p)) {
54 if (acc->SetEcsObject(obj)) {
55 anim_ = p;
56 Init();
57 }
58 }
59 return anim_ != nullptr;
60 }
Init()61 void EcsAnimation::Init()
62 {
63 Name()->SetValue(GetName());
64 Name()->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>([&] {
65 if (auto obj = GetEcsObject()) {
66 obj->SetName(Name()->GetValue());
67 }
68 }), intptr_t(this));
69 META_ACCESS_PROPERTY(Valid)->SetValue(true);
70 anim_->RepeatCount()->SetValue(0);
71 anim_->Time()->OnChanged()->AddHandler(
72 META_NS::MakeCallback<META_NS::IOnChanged>([this] { UpdateProgressFromEcs(); }), intptr_t(this));
73 anim_->Speed()->OnChanged()->AddHandler(
74 META_NS::MakeCallback<META_NS::IOnChanged>([this] { UpdateTotalDuration(); }), intptr_t(this));
75 anim_->RepeatCount()->OnChanged()->AddHandler(
76 META_NS::MakeCallback<META_NS::IOnChanged>([this] { UpdateTotalDuration(); }), intptr_t(this));
77 anim_->Duration()->OnChanged()->AddHandler(
78 META_NS::MakeCallback<META_NS::IOnChanged>([this] { UpdateTotalDuration(); }), intptr_t(this));
79
80 Enabled()->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>([this] {
81 if (!Enabled()->GetValue()) {
82 InternalStop();
83 }
84 }),
85 intptr_t(this));
86
87 UpdateTotalDuration();
88 }
GetEcsObject() const89 IEcsObject::Ptr EcsAnimation::GetEcsObject() const
90 {
91 auto acc = interface_cast<IEcsObjectAccess>(anim_);
92 return acc ? acc->GetEcsObject() : nullptr;
93 }
GetName() const94 BASE_NS::string EcsAnimation::GetName() const
95 {
96 auto obj = GetEcsObject();
97 return obj ? obj->GetName() : "";
98 }
UpdateProgressFromEcs()99 void EcsAnimation::UpdateProgressFromEcs()
100 {
101 auto currentTime = anim_->Time()->GetValue();
102 auto totalDuration = TotalDuration()->GetValue().ToSecondsFloat();
103 auto progress = totalDuration != 0.f ? currentTime / totalDuration : 1.f;
104 META_ACCESS_PROPERTY(Progress)->SetValue(progress);
105
106 if (progress >= 1.f) {
107 META_ACCESS_PROPERTY(Running)->SetValue(false);
108 META_NS::Invoke<META_NS::IOnChanged>(EventOnFinished(META_NS::MetadataQuery::EXISTING));
109 }
110 }
UpdateTotalDuration()111 void EcsAnimation::UpdateTotalDuration()
112 {
113 auto speed = anim_->Speed()->GetValue();
114 auto dur = anim_->Duration()->GetValue();
115 uint32_t rcount = anim_->RepeatCount()->GetValue();
116 META_NS::TimeSpan newDur = META_NS::TimeSpan::Infinite();
117 if (rcount != CORE3D_NS::AnimationComponent::REPEAT_COUNT_INFINITE && speed != 0.f) {
118 float times = 1.0f + rcount;
119 newDur = META_NS::TimeSpan::Seconds(dur * times / speed);
120 }
121 META_ACCESS_PROPERTY(TotalDuration)->SetValue(newDur);
122 }
InternalStop()123 void EcsAnimation::InternalStop()
124 {
125 anim_->State()->SetValue(CORE3D_NS::AnimationComponent::PlaybackState::STOP);
126 META_ACCESS_PROPERTY(Running)->SetValue(false);
127 SetProgress(0.0f);
128 }
SetProgress(float progress)129 void EcsAnimation::SetProgress(float progress)
130 {
131 progress = Base::Math::clamp01(progress);
132 anim_->Time()->SetValue(progress * GetValue(TotalDuration()).ToSecondsFloat());
133 META_ACCESS_PROPERTY(Progress)->SetValue(progress);
134 }
Pause()135 void EcsAnimation::Pause()
136 {
137 if (META_ACCESS_PROPERTY_VALUE(Enabled)) {
138 anim_->State()->SetValue(CORE3D_NS::AnimationComponent::PlaybackState::PAUSE);
139 META_ACCESS_PROPERTY(Running)->SetValue(false);
140 }
141 }
Restart()142 void EcsAnimation::Restart()
143 {
144 Stop();
145 Start();
146 }
Seek(float position)147 void EcsAnimation::Seek(float position)
148 {
149 if (META_ACCESS_PROPERTY_VALUE(Enabled)) {
150 SetProgress(position);
151 }
152 }
Start()153 void EcsAnimation::Start()
154 {
155 if (META_ACCESS_PROPERTY_VALUE(Enabled)) {
156 anim_->State()->SetValue(CORE3D_NS::AnimationComponent::PlaybackState::PLAY);
157 META_ACCESS_PROPERTY(Running)->SetValue(true);
158 META_NS::Invoke<META_NS::IOnChanged>(EventOnStarted(META_NS::MetadataQuery::EXISTING));
159 }
160 }
Stop()161 void EcsAnimation::Stop()
162 {
163 if (META_ACCESS_PROPERTY_VALUE(Enabled)) {
164 InternalStop();
165 }
166 }
Finish()167 void EcsAnimation::Finish()
168 {
169 if (META_ACCESS_PROPERTY_VALUE(Enabled)) {
170 anim_->State()->SetValue(CORE3D_NS::AnimationComponent::PlaybackState::STOP);
171 META_ACCESS_PROPERTY(Running)->SetValue(false);
172 Seek(1.0f);
173 META_NS::Invoke<META_NS::IOnChanged>(EventOnFinished(META_NS::MetadataQuery::EXISTING));
174 }
175 }
Attach(const META_NS::IObject::Ptr & attachment,const META_NS::IObject::Ptr & dataContext)176 bool EcsAnimation::Attach(const META_NS::IObject::Ptr& attachment, const META_NS::IObject::Ptr& dataContext)
177 {
178 bool res = Super::Attach(attachment, dataContext);
179 if (res) {
180 if (auto loop = interface_pointer_cast<META_NS::AnimationModifiers::ILoop>(attachment)) {
181 auto value = loop->LoopCount()->GetValue();
182 anim_->RepeatCount()->SetValue(LoopCountConverter::ConvertToTarget(value));
183 loop->LoopCount()->PushValue(
184 META_NS::IValue::Ptr(new ConvertingValue<LoopCountConverter>(anim_->RepeatCount())));
185 } else if (auto speed = interface_pointer_cast<META_NS::AnimationModifiers::ISpeed>(attachment)) {
186 auto value = speed->SpeedFactor()->GetValue();
187 anim_->Speed()->SetValue(value);
188 speed->SpeedFactor()->PushValue(anim_->Speed().GetProperty());
189 }
190 }
191 return res;
192 }
Detach(const META_NS::IObject::Ptr & attachment)193 bool EcsAnimation::Detach(const META_NS::IObject::Ptr& attachment)
194 {
195 bool res = Super::Detach(attachment);
196 if (res) {
197 if (auto loop = interface_cast<META_NS::AnimationModifiers::ILoop>(attachment)) {
198 loop->LoopCount()->ResetValue();
199 anim_->RepeatCount()->SetValue(0);
200 } else if (auto speed = interface_cast<META_NS::AnimationModifiers::ISpeed>(attachment)) {
201 speed->SpeedFactor()->ResetValue();
202 anim_->Speed()->SetValue(1.f);
203 }
204 }
205 return res;
206 }
AttachTo(const META_NS::IAttach::Ptr & target,const META_NS::IObject::Ptr & dataContext)207 bool EcsAnimation::AttachTo(const META_NS::IAttach::Ptr& target, const META_NS::IObject::Ptr& dataContext)
208 {
209 return true;
210 }
DetachFrom(const META_NS::IAttach::Ptr & target)211 bool EcsAnimation::DetachFrom(const META_NS::IAttach::Ptr& target)
212 {
213 return true;
214 }
215
216 SCENE_END_NAMESPACE()