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 "track_animation.h"
17
18 #include <meta/ext/serialization/serializer.h>
19
20 META_BEGIN_NAMESPACE()
21
22 namespace Internal {
23
GetParams()24 AnimationState::AnimationStateParams TrackAnimation::GetParams()
25 {
26 AnimationState::AnimationStateParams params;
27 params.owner = GetSelf<IAnimation>();
28 params.runningProperty = META_ACCESS_PROPERTY(Running);
29 params.progressProperty = META_ACCESS_PROPERTY(Progress);
30 params.totalDuration = META_ACCESS_PROPERTY(TotalDuration);
31 return params;
32 }
33
Build(const IMetadata::Ptr & data)34 bool TrackAnimation::Build(const IMetadata::Ptr& data)
35 {
36 if (Super::Build(data)) {
37 TrackAnimationState::TrackDataParams params { META_ACCESS_PROPERTY(Timestamps) };
38 GetState().SetTrackDataParams(BASE_NS::move(params));
39
40 auto updateKf = MakeCallback<IOnChanged>(this, &TrackAnimation::UpdateKeyframes);
41
42 META_ACCESS_PROPERTY(Timestamps)->OnChanged()->AddHandler(updateKf);
43 constexpr BASE_NS::string_view name = "Keyframes";
44 keyframes_ = GetObjectRegistry().GetPropertyRegister().Create(ClassId::StackProperty, name);
45 if (keyframes_) {
46 keyframes_->OnChanged()->AddHandler(updateKf);
47 AddProperty(keyframes_);
48 }
49 UpdateKeyframes();
50 return keyframes_ != nullptr;
51 }
52 return false;
53 }
54
Initialize()55 void TrackAnimation::Initialize()
56 {
57 ResetTrack();
58 }
59
OnAnimationStateChanged(const IAnimationInternal::AnimationStateChangedInfo & info)60 void TrackAnimation::OnAnimationStateChanged(const IAnimationInternal::AnimationStateChangedInfo& info)
61 {
62 using AnimationTargetState = IAnimationInternal::AnimationTargetState;
63 if (auto p = GetTargetProperty()) {
64 switch (info.state) {
65 case AnimationTargetState::FINISHED:
66 [[fallthrough]];
67 case AnimationTargetState::STOPPED:
68 // Evaluate current value
69 Evaluate();
70 // Remove ourselves from the target property's stack
71 RemoveModifier(p.stack);
72 // Then set the correct keyframe value to the underlying property
73 if (auto value = GetState().GetCurrentValue()) {
74 PropertyLock lock { p.property };
75 lock->SetValueAny(*value);
76 }
77 break;
78 case AnimationTargetState::RUNNING:
79 // Evaluate current value
80 Evaluate();
81 // Add ourselves to the target property's stack
82 p.stack->AddModifier(GetSelf<IModifier>());
83 break;
84 case AnimationTargetState::PAUSED: {
85 // Evaluate current value
86 Evaluate();
87 // Make sure we are in the target property's stack
88 auto mymod = GetSelf<IModifier>();
89 for (auto&& v : p.stack->GetModifiers({ ITrackAnimation::UID }, false)) {
90 if (v == mymod) {
91 mymod.reset();
92 }
93 }
94 if (mymod) {
95 p.stack->AddModifier(mymod);
96 }
97 } break;
98 default:
99 break;
100 }
101 }
102 }
103
ProcessOnGet(IAny & value)104 EvaluationResult TrackAnimation::ProcessOnGet(IAny& value)
105 {
106 if (auto& currentValue = GetState().GetCurrentValue()) {
107 if (auto result = value.CopyFrom(*currentValue)) {
108 return result == AnyReturn::NOTHING_TO_DO ? EvaluationResult::EVAL_CONTINUE
109 : EvaluationResult::EVAL_VALUE_CHANGED;
110 }
111 }
112 return EvaluationResult::EVAL_CONTINUE;
113 }
114
Start()115 void TrackAnimation::Start()
116 {
117 GetState().Start();
118 }
119
Stop()120 void TrackAnimation::Stop()
121 {
122 GetState().Stop();
123 }
124
Pause()125 void TrackAnimation::Pause()
126 {
127 GetState().Pause();
128 }
129
Restart()130 void TrackAnimation::Restart()
131 {
132 GetState().Restart();
133 }
134
Finish()135 void TrackAnimation::Finish()
136 {
137 GetState().Finish();
138 }
139
Seek(float position)140 void TrackAnimation::Seek(float position)
141 {
142 GetState().Seek(position);
143 }
144
Step(const IClock::ConstPtr & clock)145 void TrackAnimation::Step(const IClock::ConstPtr& clock)
146 {
147 GetState().Step(clock);
148 }
149
Evaluate()150 void TrackAnimation::Evaluate()
151 {
152 float progress = META_ACCESS_PROPERTY_VALUE(Progress);
153 if (auto curve = META_ACCESS_PROPERTY_VALUE(Curve)) {
154 progress = curve->Transform(progress);
155 }
156 const auto trackState = GetState().UpdateIndex(progress);
157 const PropertyAnimationState::EvaluationData data { GetState().GetCurrentValue(), GetState().GetCurrentTrackStart(),
158 GetState().GetCurrentTrackEnd(), trackState.second,
159 META_ACCESS_PROPERTY(KeyframeCurves)->GetValueAt(trackState.first) };
160 const auto status = GetState().EvaluateValue(data);
161 UpdateCurrentTrack(trackState.first);
162 if (status == AnyReturn::SUCCESS) {
163 NotifyChanged();
164 if (auto prop = GetTargetProperty()) {
165 PropertyLock lock { prop.property };
166 prop.stack->EvaluateAndStore();
167 }
168 }
169 }
170
RemoveModifier(const IStackProperty::Ptr & stack)171 void TrackAnimation::RemoveModifier(const IStackProperty::Ptr& stack)
172 {
173 if (stack) {
174 stack->RemoveModifier(GetSelf<IModifier>());
175 }
176 }
177
OnPropertyChanged(const TargetProperty & property,const IStackProperty::Ptr & previous)178 void TrackAnimation::OnPropertyChanged(const TargetProperty& property, const IStackProperty::Ptr& previous)
179 {
180 if (previous && GetState().IsRunning()) {
181 // Property changed while running, clean up previous property's stack
182 RemoveModifier(previous);
183 if (auto p = interface_cast<IProperty>(previous)) {
184 PropertyLock lock { p };
185 lock->SetValueAny(*GetState().GetCurrentValue());
186 }
187 }
188
189 Initialize();
190
191 if (auto p = GetTargetProperty()) {
192 PropertyLock lock { p.property };
193 auto& value = lock->GetValueAny();
194 bool alreadyCompatible = value.GetTypeId() == GetState().GetKeyframeItemTypeId();
195 if (!alreadyCompatible) {
196 IAny::Ptr array {};
197 if (!value.IsArray()) {
198 // Clone the target property's value to an array of the value's underlying type
199 array = value.Clone(AnyCloneOptions { CloneValueType::DEFAULT_VALUE, TypeIdRole::ARRAY });
200 } else {
201 CORE_LOG_E("TrackAnimation: Cannot animate array types");
202 }
203 if (!array) {
204 CORE_LOG_E("TrackAnimation: Failed to create an array of target property type");
205 }
206 if (auto kf = interface_pointer_cast<IArrayAny>(array)) {
207 keyframes_->SetValue(*kf);
208 } else {
209 keyframes_->ResetValue();
210 }
211 }
212 }
213
214 UpdateValid();
215 }
216
AddKeyframe(float timestamp,const IAny::ConstPtr & value)217 size_t TrackAnimation::AddKeyframe(float timestamp, const IAny::ConstPtr& value)
218 {
219 auto index = GetState().AddKeyframe(timestamp, value);
220 if (index != ITrackAnimation::INVALID_INDEX) {
221 keyframes_->NotifyChange();
222 }
223 return index;
224 }
225
RemoveKeyframe(size_t index)226 bool TrackAnimation::RemoveKeyframe(size_t index)
227 {
228 bool success = false;
229 if (GetState().RemoveKeyframe(index)) {
230 keyframes_->NotifyChange();
231 success = true;
232 } else {
233 CORE_LOG_E("TrackAnimation: Cannot remove keyframe from index %u.", static_cast<uint32_t>(index));
234 }
235 return success;
236 }
237
RemoveAllKeyframes()238 void TrackAnimation::RemoveAllKeyframes()
239 {
240 Stop();
241 META_ACCESS_PROPERTY(Timestamps)->Reset();
242 keyframes_->ResetValue();
243 UpdateValid();
244 }
245
UpdateKeyframes()246 void TrackAnimation::UpdateKeyframes()
247 {
248 IArrayAny::Ptr kfArray;
249 if (auto stack = interface_cast<IStackProperty>(keyframes_)) {
250 // Get the topmost IArrayAny value, that should be our keyframe array
251 auto values = stack->GetValues({}, true);
252 for (auto it = values.rbegin(); it != values.rend(); ++it) {
253 if (auto arr = interface_pointer_cast<IArrayAny>(*it)) {
254 kfArray = arr;
255 break;
256 }
257 }
258 }
259 GetState().SetKeyframes(kfArray);
260 UpdateValid();
261 }
262
UpdateValid()263 void TrackAnimation::UpdateValid()
264 {
265 bool valid = false;
266 auto timestamps = META_ACCESS_PROPERTY(Timestamps);
267
268 if (const auto p = GetTargetProperty(); p && timestamps) {
269 valid = GetState().UpdateValid();
270 }
271
272 if (valid != META_ACCESS_PROPERTY_VALUE(Valid)) {
273 if (!valid) {
274 Stop();
275 ResetTrack();
276 }
277 SetValue(META_ACCESS_PROPERTY(Valid), valid);
278 }
279
280 GetState().ResetCurrentTrack();
281 }
282
ResetTrack()283 void TrackAnimation::ResetTrack()
284 {
285 GetState().ResetCurrentTrack();
286 SetValue(META_ACCESS_PROPERTY(CurrentKeyframeIndex), -1);
287 }
288
UpdateCurrentTrack(uint32_t index)289 void TrackAnimation::UpdateCurrentTrack(uint32_t index)
290 {
291 auto currentIndex = META_ACCESS_PROPERTY_VALUE(CurrentKeyframeIndex);
292 if (currentIndex != index) {
293 SetValue(META_ACCESS_PROPERTY(CurrentKeyframeIndex), index);
294 if (auto f = META_ACCESS_PROPERTY(KeyframeHandlers)->GetValueAt(index)) {
295 CallMetaFunction<void>(f);
296 }
297 }
298 }
299
Export(IExportContext & c) const300 ReturnError TrackAnimation::Export(IExportContext& c) const
301 {
302 return Serializer(c) & AutoSerialize() & NamedValue("Keyframes", keyframes_);
303 }
Import(IImportContext & c)304 ReturnError TrackAnimation::Import(IImportContext& c)
305 {
306 return Serializer(c) & AutoSerialize() & NamedValue("Keyframes", keyframes_);
307 }
Finalize(IImportFunctions & f)308 ReturnError TrackAnimation::Finalize(IImportFunctions& f)
309 {
310 auto res = Super::Finalize(f);
311 if (res) {
312 UpdateKeyframes();
313 }
314 return res;
315 }
316 } // namespace Internal
317
318 META_END_NAMESPACE()
319