• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()