• 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 "track_animation_state.h"
17 
18 #include <limits>
19 
20 META_BEGIN_NAMESPACE()
21 
22 namespace Internal {
23 
SetTrackDataParams(TrackDataParams && params)24 void TrackAnimationState::SetTrackDataParams(TrackDataParams&& params)
25 {
26     trackParams_ = BASE_NS::move(params);
27 }
28 
AddKeyframe(float timestamp,const IAny::ConstPtr & value)29 size_t TrackAnimationState::AddKeyframe(float timestamp, const IAny::ConstPtr& value)
30 {
31     if (!keyframeArray_ || !value) {
32         CORE_LOG_E("Invalid keyframe array target.");
33         return ITrackAnimation::INVALID_INDEX;
34     }
35 
36     timestamp = BASE_NS::Math::clamp01(timestamp);
37     size_t index = 0;
38 
39     // Find index for timestamp which maintains ascending timestamp order
40     auto timestamps = GetTimeStamps()->GetValue();
41 
42     for (auto t : timestamps) {
43         if (t > timestamp) {
44             break;
45         }
46         index++;
47     }
48 
49     if (keyframeArray_->InsertAnyAt(index, *value)) {
50         GetTimeStamps()->InsertValueAt(index, timestamp);
51         ValidateValues();
52     } else {
53         CORE_LOG_E("Failed to add keyframe to TrackAnimation");
54         index = ITrackAnimation::INVALID_INDEX;
55     }
56 
57     return index;
58 }
59 
RemoveKeyframe(size_t index)60 bool TrackAnimationState::RemoveKeyframe(size_t index)
61 {
62     if (!keyframeArray_ || index >= GetTimeStamps()->GetSize()) {
63         return false;
64     }
65     if (keyframeArray_->RemoveAt(index)) {
66         GetTimeStamps()->RemoveAt(index);
67         return true;
68     }
69     return false;
70 }
71 
UpdateValid()72 bool TrackAnimationState::UpdateValid()
73 {
74     if (!(keyframeArray_ && trackStart_ && trackEnd_ && currentValue_)) {
75         return false;
76     }
77     auto& timestamps = GetTimeStamps();
78     if (timestamps) {
79         auto size = timestamps->GetSize();
80         if (size > 1 && keyframeArray_->GetSize() == size) {
81             // Update our timestamp range
82             startProgress_ = timestamps->GetValueAt(0);
83             endProgress_ = timestamps->GetValueAt(size - 1);
84             return true;
85         }
86     }
87     return false;
88 }
89 
ResetCurrentTrack()90 void TrackAnimationState::ResetCurrentTrack()
91 {
92     currentRangeStartTs_ = std::numeric_limits<float>::max();
93     currentRangeEndTs_ = {};
94     currentIndex_ = ITrackAnimation::INVALID_INDEX;
95 }
96 
Reset()97 void TrackAnimationState::Reset()
98 {
99     trackStart_.reset();
100     trackEnd_.reset();
101     currentValue_.reset();
102 }
103 
ValidateValues()104 bool TrackAnimationState::ValidateValues()
105 {
106     if (!keyframeArray_) {
107         return false;
108     }
109     if (trackStart_ && trackStart_->GetTypeId() != keyframeArray_->GetTypeId(TypeIdRole::ITEM)) {
110         Reset();
111     }
112     if (!trackStart_) {
113         if (auto size = keyframeArray_->GetSize()) {
114             if (trackStart_ = keyframeArray_->Clone({ CloneValueType::DEFAULT_VALUE, TypeIdRole::ITEM }); trackStart_) {
115                 trackEnd_ = trackStart_->Clone(false);
116                 keyframeArray_->GetAnyAt(0, *trackStart_);
117                 keyframeArray_->GetAnyAt(size - 1, *trackEnd_);
118                 currentValue_ = trackStart_->Clone(true);
119             }
120         } else {
121             Reset();
122         }
123     }
124     return trackStart_ != nullptr;
125 }
126 
SetKeyframes(const IArrayAny::Ptr & keyframes)127 bool TrackAnimationState::SetKeyframes(const IArrayAny::Ptr& keyframes)
128 {
129     bool valid = false;
130     if (keyframes) {
131         if (keyframes != keyframeArray_) {
132             keyframeArray_ = keyframes;
133             valid = ValidateValues();
134         } else {
135             valid = true;
136         }
137     }
138     if (auto& timestamps = GetTimeStamps()) {
139         if (const auto size = timestamps->GetSize()) {
140             startProgress_ = timestamps->GetValueAt(0);
141             endProgress_ = timestamps->GetValueAt(size - 1);
142         }
143     }
144     if (!valid) {
145         Reset();
146     }
147     return valid;
148 }
149 
IsBetween(float value,float rangeStart,float rangeEnd,bool includeEnd)150 inline static constexpr bool IsBetween(float value, float rangeStart, float rangeEnd, bool includeEnd)
151 {
152     if (includeEnd) {
153         return value >= rangeStart && value <= rangeEnd;
154     }
155     return value >= rangeStart && value < rangeEnd;
156 }
157 
IsInCurrentRange(float progress) const158 bool TrackAnimationState::IsInCurrentRange(float progress) const noexcept
159 {
160     if (currentIndex_ == ITrackAnimation::INVALID_INDEX || !keyframeArray_) {
161         return false;
162     }
163 
164     // Include also end in the range if last keyframe
165     return IsBetween(
166         progress, currentRangeStartTs_, currentRangeEndTs_, currentIndex_ == keyframeArray_->GetSize() - 1);
167 }
168 
UpdateIndex(float progress)169 BASE_NS::pair<uint32_t, float> TrackAnimationState::UpdateIndex(float progress)
170 {
171     uint32_t index = static_cast<uint32_t>(currentIndex_);
172     if (IsInCurrentRange(progress)) {
173         return { index, GetCurrentTrackProgress(progress) };
174     }
175 
176     const auto size = keyframeArray_ ? keyframeArray_->GetSize() : 0;
177     auto& timestamps = GetTimeStamps();
178     if (!size || !timestamps || timestamps->GetSize() != size) {
179         index = JumpTo(size_t(ITrackAnimation::INVALID_INDEX), progress);
180     } else {
181         size_t lo = 0;
182         auto hi = size - 1;
183         auto startTs = timestamps->GetValueAt(lo);
184         auto endTs = timestamps->GetValueAt(hi);
185         if (progress < startTs || progress > endTs) {
186             index = JumpTo(size_t(ITrackAnimation::INVALID_INDEX), progress);
187         } else {
188             while (lo <= hi) {
189                 const auto mid = lo + (hi - lo) / 2;
190                 const auto endIndex = mid < size - 1 ? mid + 1 : mid;
191                 startTs = timestamps->GetValueAt(mid);
192                 endTs = timestamps->GetValueAt(endIndex);
193                 if (IsBetween(progress, startTs, endTs, mid >= endIndex)) {
194                     // Found correct keyframe
195                     index = JumpTo(mid, progress);
196                     break;
197                 }
198                 if (progress < startTs) {
199                     hi = mid - 1;
200                 } else {
201                     lo = mid + 1;
202                 }
203             }
204         }
205     }
206     return { index, GetCurrentTrackProgress(progress) };
207 }
208 
SetPrePostFrameValues(float progress)209 void TrackAnimationState::SetPrePostFrameValues(float progress)
210 {
211     auto& timestamps = GetTimeStamps();
212     auto size = keyframeArray_ ? keyframeArray_->GetSize() : 0;
213     if (size && timestamps && timestamps->GetSize() == size) {
214         if (progress < timestamps->GetValueAt(0)) {
215             keyframeArray_->GetAnyAt(0, *trackEnd_);
216             keyframeArray_->GetAnyAt(0, *trackStart_);
217         }
218         if (progress > timestamps->GetValueAt(size - 1)) {
219             keyframeArray_->GetAnyAt(size - 1, *trackEnd_);
220             keyframeArray_->GetAnyAt(size - 1, *trackStart_);
221         }
222     }
223 }
224 
JumpTo(size_t index,float progress)225 uint32_t TrackAnimationState::JumpTo(size_t index, float progress)
226 {
227     if (index == ITrackAnimation::INVALID_INDEX) {
228         currentIndex_ = index;
229         ResetCurrentTrack();
230         SetPrePostFrameValues(progress);
231         return static_cast<uint32_t>(currentIndex_);
232     }
233     if (index == currentIndex_) {
234         return currentIndex_;
235     }
236 
237     const auto size = keyframeArray_ ? keyframeArray_->GetSize() : 0;
238     auto& timestamps = GetTimeStamps();
239     if (!size || !timestamps || timestamps->GetSize() != size || !trackStart_ || !trackEnd_) {
240         return ITrackAnimation::INVALID_INDEX;
241     }
242     index = BASE_NS::Math::min(index, size - 1);
243 
244     bool last = index == size - 1;
245     auto start = last && index > 0 ? index - 1 : index;
246     auto end = BASE_NS::Math::min(start + 1, size - 1);
247 
248     keyframeArray_->GetAnyAt(end, *trackEnd_);
249     keyframeArray_->GetAnyAt(start, *trackStart_);
250     currentRangeStartTs_ = timestamps->GetValueAt(start);
251     currentRangeEndTs_ = timestamps->GetValueAt(end);
252     currentIndex_ = last ? end : index;
253 
254     return static_cast<uint32_t>(currentIndex_);
255 }
256 
GetCurrentTrackProgress(float progress) const257 float TrackAnimationState::GetCurrentTrackProgress(float progress) const noexcept
258 {
259     if (currentIndex_ == ITrackAnimation::INVALID_INDEX) {
260         return 0.f;
261     }
262     float currentTrackRange = currentRangeEndTs_ - currentRangeStartTs_;
263     auto rangeProgress = BASE_NS::Math::clamp(progress, startProgress_, endProgress_);
264     if (currentTrackRange < BASE_NS::Math::EPSILON) {
265         return 1.f;
266     }
267     return 1.f / currentTrackRange * (rangeProgress - currentRangeStartTs_);
268 }
269 
270 } // namespace Internal
271 
272 META_END_NAMESPACE()
273