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