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