• 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 <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()