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 p.property->SetValue(*value);
75 }
76 break;
77 case AnimationTargetState::RUNNING:
78 // Evaluate current value
79 Evaluate();
80 // Add ourselves to the target property's stack
81 p.stack->AddModifier(GetSelf<IModifier>());
82 break;
83 default:
84 break;
85 }
86 }
87 }
88
ProcessOnGet(IAny & value)89 EvaluationResult TrackAnimation::ProcessOnGet(IAny& value)
90 {
91 if (auto& currentValue = GetState().GetCurrentValue()) {
92 if (auto result = value.CopyFrom(*currentValue)) {
93 return result == AnyReturn::NOTHING_TO_DO ? EvaluationResult::EVAL_CONTINUE
94 : EvaluationResult::EVAL_VALUE_CHANGED;
95 }
96 }
97 return EvaluationResult::EVAL_CONTINUE;
98 }
99
Start()100 void TrackAnimation::Start()
101 {
102 GetState().Start();
103 }
104
Stop()105 void TrackAnimation::Stop()
106 {
107 GetState().Stop();
108 }
109
Pause()110 void TrackAnimation::Pause()
111 {
112 GetState().Pause();
113 }
114
Restart()115 void TrackAnimation::Restart()
116 {
117 GetState().Restart();
118 }
119
Finish()120 void TrackAnimation::Finish()
121 {
122 GetState().Finish();
123 }
124
Seek(float position)125 void TrackAnimation::Seek(float position)
126 {
127 GetState().Seek(position);
128 }
129
Step(const IClock::ConstPtr & clock)130 void TrackAnimation::Step(const IClock::ConstPtr& clock)
131 {
132 GetState().Step(clock);
133 }
134
Evaluate()135 void TrackAnimation::Evaluate()
136 {
137 float progress = META_ACCESS_PROPERTY_VALUE(Progress);
138 if (auto curve = META_ACCESS_PROPERTY_VALUE(Curve)) {
139 progress = curve->Transform(progress);
140 }
141 const auto trackState = GetState().UpdateIndex(progress);
142 const PropertyAnimationState::EvaluationData data { GetState().GetCurrentValue(), GetState().GetCurrentTrackStart(),
143 GetState().GetCurrentTrackEnd(), trackState.second,
144 META_ACCESS_PROPERTY(KeyframeCurves)->GetValueAt(trackState.first) };
145 const auto status = GetState().EvaluateValue(data);
146 UpdateCurrentTrack(trackState.first);
147 if (status == AnyReturn::SUCCESS) {
148 NotifyChanged();
149 }
150 }
151
RemoveModifier(const IStackProperty::Ptr & stack)152 void TrackAnimation::RemoveModifier(const IStackProperty::Ptr& stack)
153 {
154 if (stack) {
155 stack->RemoveModifier(GetSelf<IModifier>());
156 }
157 }
158
OnPropertyChanged(const TargetProperty & property,const IStackProperty::Ptr & previous)159 void TrackAnimation::OnPropertyChanged(const TargetProperty& property, const IStackProperty::Ptr& previous)
160 {
161 if (previous && GetState().IsRunning()) {
162 // Property changed while running, clean up previous property's stack
163 RemoveModifier(previous);
164 if (auto p = interface_cast<IProperty>(previous)) {
165 p->SetValue(*GetState().GetCurrentValue());
166 }
167 }
168
169 Initialize();
170
171 if (auto p = GetTargetProperty()) {
172 auto& property = p.property;
173 auto& value = property->GetValue();
174 bool alreadyCompatible = value.GetTypeId() == GetState().GetKeyframeItemTypeId();
175 if (!alreadyCompatible) {
176 IAny::Ptr array {};
177 if (!value.IsArray()) {
178 // Clone the target property's value to an array of the value's underlying type
179 array = value.Clone(AnyCloneOptions { CloneValueType::DEFAULT_VALUE, TypeIdRole::ARRAY });
180 } else {
181 CORE_LOG_E("TrackAnimation: Cannot animate array types");
182 }
183 if (!array) {
184 CORE_LOG_E("TrackAnimation: Failed to create an array of target property type");
185 }
186 if (auto kf = interface_pointer_cast<IArrayAny>(array)) {
187 keyframes_->SetValue(*kf);
188 } else {
189 keyframes_->ResetValue();
190 }
191 }
192 }
193
194 UpdateValid();
195 }
196
AddKeyframe(float timestamp,const IAny::ConstPtr & value)197 size_t TrackAnimation::AddKeyframe(float timestamp, const IAny::ConstPtr& value)
198 {
199 auto index = GetState().AddKeyframe(timestamp, value);
200 if (index != ITrackAnimation::INVALID_INDEX) {
201 keyframes_->NotifyChange();
202 }
203 return index;
204 }
205
RemoveKeyframe(size_t index)206 bool TrackAnimation::RemoveKeyframe(size_t index)
207 {
208 bool success = false;
209 if (GetState().RemoveKeyframe(index)) {
210 keyframes_->NotifyChange();
211 success = true;
212 } else {
213 CORE_LOG_E("TrackAnimation: Cannot remove keyframe from index %u.", static_cast<uint32_t>(index));
214 }
215 return success;
216 }
217
RemoveAllKeyframes()218 void TrackAnimation::RemoveAllKeyframes()
219 {
220 Stop();
221 META_ACCESS_PROPERTY(Timestamps)->Reset();
222 keyframes_->ResetValue();
223 UpdateValid();
224 }
225
UpdateKeyframes()226 void TrackAnimation::UpdateKeyframes()
227 {
228 IArrayAny::Ptr kfArray;
229 if (auto stack = interface_cast<IStackProperty>(keyframes_)) {
230 // Get the topmost IArrayAny value, that should be our keyframe array
231 auto values = stack->GetValues({}, true);
232 for (auto it = values.rbegin(); it != values.rend(); ++it) {
233 if (auto arr = interface_pointer_cast<IArrayAny>(*it)) {
234 kfArray = arr;
235 break;
236 }
237 }
238 }
239 GetState().SetKeyframes(kfArray);
240 UpdateValid();
241 }
242
UpdateValid()243 void TrackAnimation::UpdateValid()
244 {
245 bool valid = false;
246 auto& timestamps = META_ACCESS_PROPERTY(Timestamps);
247
248 if (const auto p = GetTargetProperty(); p && timestamps) {
249 valid = GetState().UpdateValid();
250 }
251
252 if (valid != META_ACCESS_PROPERTY_VALUE(Valid)) {
253 if (!valid) {
254 Stop();
255 ResetTrack();
256 }
257 SetValue(META_ACCESS_PROPERTY(Valid), valid);
258 }
259
260 GetState().ResetCurrentTrack();
261 }
262
ResetTrack()263 void TrackAnimation::ResetTrack()
264 {
265 GetState().ResetCurrentTrack();
266 SetValue(META_ACCESS_PROPERTY(CurrentKeyframeIndex), -1);
267 }
268
UpdateCurrentTrack(uint32_t index)269 void TrackAnimation::UpdateCurrentTrack(uint32_t index)
270 {
271 auto currentIndex = META_ACCESS_PROPERTY_VALUE(CurrentKeyframeIndex);
272 if (currentIndex != index) {
273 SetValue(META_ACCESS_PROPERTY(CurrentKeyframeIndex), index);
274 if (auto f = META_ACCESS_PROPERTY(KeyframeHandlers)->GetValueAt(index)) {
275 CallMetaFunction<void>(f);
276 }
277 }
278 }
279
Export(IExportContext & c) const280 ReturnError TrackAnimation::Export(IExportContext& c) const
281 {
282 return Serializer(c) & AutoSerialize() & NamedValue("Keyframes", keyframes_);
283 }
Import(IImportContext & c)284 ReturnError TrackAnimation::Import(IImportContext& c)
285 {
286 return Serializer(c) & AutoSerialize() & NamedValue("Keyframes", keyframes_);
287 }
Finalize(IImportFunctions & f)288 ReturnError TrackAnimation::Finalize(IImportFunctions& f)
289 {
290 auto res = Super::Finalize(f);
291 if (res) {
292 UpdateKeyframes();
293 }
294 return res;
295 }
296 } // namespace Internal
297
298 META_END_NAMESPACE()
299