1 /*
2 * Copyright (c) 2022 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 "animation/rs_render_spring_animation.h"
17
18 #include "pipeline/rs_render_node.h"
19 #include "platform/common/rs_log.h"
20
21 namespace OHOS {
22 namespace Rosen {
23 namespace {
24 constexpr static float SECOND_TO_MILLISECOND = 1e3;
25 constexpr static float MILLISECOND_TO_SECOND = 1e-3;
26 constexpr static float SECOND_TO_NANOSECOND = 1e9;
27 constexpr static float RESPONSE_THRESHOLD = 0.001f;
28 constexpr static float FRACTION_THRESHOLD = 0.001f;
29 } // namespace
30
RSRenderSpringAnimation(AnimationId id,const PropertyId & propertyId,const std::shared_ptr<RSRenderPropertyBase> & originValue,const std::shared_ptr<RSRenderPropertyBase> & startValue,const std::shared_ptr<RSRenderPropertyBase> & endValue)31 RSRenderSpringAnimation::RSRenderSpringAnimation(AnimationId id, const PropertyId& propertyId,
32 const std::shared_ptr<RSRenderPropertyBase>& originValue,
33 const std::shared_ptr<RSRenderPropertyBase>& startValue,
34 const std::shared_ptr<RSRenderPropertyBase>& endValue)
35 : RSRenderPropertyAnimation(id, propertyId, originValue),
36 RSSpringModel<std::shared_ptr<RSRenderPropertyBase>>(),
37 startValue_(startValue), endValue_(endValue)
38 {
39 // spring model is not initialized, so we can't calculate estimated duration
40 }
41
SetSpringParameters(float response,float dampingRatio,float blendDuration)42 void RSRenderSpringAnimation::SetSpringParameters(float response, float dampingRatio, float blendDuration)
43 {
44 response_ = response;
45 finalResponse_ = response;
46 dampingRatio_ = dampingRatio;
47 blendDuration_ = blendDuration * SECOND_TO_NANOSECOND; // convert to ns
48 }
49
50 #ifdef ROSEN_OHOS
Marshalling(Parcel & parcel) const51 bool RSRenderSpringAnimation::Marshalling(Parcel& parcel) const
52 {
53 if (!RSRenderPropertyAnimation::Marshalling(parcel)) {
54 ROSEN_LOGE("RSRenderSpringAnimation::Marshalling, RenderPropertyAnimation failed");
55 return false;
56 }
57 if (!(RSRenderPropertyBase::Marshalling(parcel, startValue_) &&
58 RSRenderPropertyBase::Marshalling(parcel, endValue_))) {
59 ROSEN_LOGE("RSRenderSpringAnimation::Marshalling, MarshallingHelper failed");
60 return false;
61 }
62
63 if (!(RSMarshallingHelper::Marshalling(parcel, response_) &&
64 RSMarshallingHelper::Marshalling(parcel, dampingRatio_) &&
65 RSMarshallingHelper::Marshalling(parcel, blendDuration_))) {
66 return false;
67 }
68
69 return true;
70 }
71
Unmarshalling(Parcel & parcel)72 RSRenderSpringAnimation* RSRenderSpringAnimation::Unmarshalling(Parcel& parcel)
73 {
74 auto* renderSpringAnimation = new RSRenderSpringAnimation();
75 if (!renderSpringAnimation->ParseParam(parcel)) {
76 ROSEN_LOGE("RSRenderSpringAnimation::Unmarshalling, failed");
77 delete renderSpringAnimation;
78 return nullptr;
79 }
80 return renderSpringAnimation;
81 }
82
ParseParam(Parcel & parcel)83 bool RSRenderSpringAnimation::ParseParam(Parcel& parcel)
84 {
85 if (!RSRenderPropertyAnimation::ParseParam(parcel)) {
86 ROSEN_LOGE("RSRenderSpringAnimation::ParseParam, ParseParam Fail");
87 return false;
88 }
89
90 if (!(RSRenderPropertyBase::Unmarshalling(parcel, startValue_) &&
91 RSRenderPropertyBase::Unmarshalling(parcel, endValue_))) {
92 return false;
93 }
94
95 if (!(RSMarshallingHelper::Unmarshalling(parcel, response_) &&
96 RSMarshallingHelper::Unmarshalling(parcel, dampingRatio_) &&
97 RSMarshallingHelper::Unmarshalling(parcel, blendDuration_))) {
98 return false;
99 }
100 // copy response to final response
101 finalResponse_ = response_;
102
103 return true;
104 }
105 #endif
106
OnSetFraction(float fraction)107 void RSRenderSpringAnimation::OnSetFraction(float fraction)
108 {
109 // spring animation should not support set fraction
110 OnAnimate(fraction);
111 }
112
OnAnimate(float fraction)113 void RSRenderSpringAnimation::OnAnimate(float fraction)
114 {
115 if (GetPropertyId() == 0) {
116 return;
117 } else if (ROSEN_EQ(fraction, 1.0f, FRACTION_THRESHOLD)) {
118 SetAnimationValue(endValue_);
119 prevMappedTime_ = GetDuration() * MILLISECOND_TO_SECOND;
120 return;
121 }
122 auto mappedTime = fraction * GetDuration() * MILLISECOND_TO_SECOND;
123 auto displacement = CalculateDisplacement(mappedTime);
124 SetAnimationValue(endValue_ + displacement);
125
126 // keep the mapped time, this will be used to calculate instantaneous velocity
127 prevMappedTime_ = mappedTime;
128 }
129
OnAttach()130 void RSRenderSpringAnimation::OnAttach()
131 {
132 auto target = GetTarget();
133 if (target == nullptr) {
134 ROSEN_LOGE("RSRenderSpringAnimation::OnAttach, target is nullptr");
135 return;
136 }
137 // check if any other spring animation running on this property
138 auto propertyId = GetPropertyId();
139 auto prevAnimation = target->GetAnimationManager().QuerySpringAnimation(propertyId);
140 target->GetAnimationManager().RegisterSpringAnimation(propertyId, GetAnimationId());
141
142 // return if no other spring animation(s) running, or the other animation is finished
143 // meanwhile, align run time for both spring animations, prepare for status inheritance
144 if (prevAnimation == nullptr || prevAnimation->Animate(animationFraction_.GetLastFrameTime())) {
145 blendDuration_ = 0;
146 return;
147 }
148
149 // extract spring status from previous spring animation
150 auto prevSpringAnimation = std::static_pointer_cast<RSRenderSpringAnimation>(prevAnimation);
151
152 // inherit spring status from previous spring animation
153 InheritSpringStatus(prevSpringAnimation.get());
154 // inherit spring response
155 response_ = prevSpringAnimation->response_;
156 if (ROSEN_EQ(response_, finalResponse_, RESPONSE_THRESHOLD)) {
157 // if response is not changed, we can skip blend duration
158 blendDuration_ = 0;
159 } else if (blendDuration_ == 0) {
160 // if blend duration is not set, we can skip blend duration
161 response_ = finalResponse_;
162 } else if (ROSEN_EQ(finalResponse_, prevSpringAnimation->finalResponse_, RESPONSE_THRESHOLD)) {
163 // if previous spring is blending to the same final response, we can continue previous blending process
164 blendDuration_ = prevSpringAnimation->blendDuration_;
165 }
166
167 // set previous spring animation to FINISHED
168 prevSpringAnimation->FinishOnCurrentPosition();
169 }
170
OnDetach()171 void RSRenderSpringAnimation::OnDetach()
172 {
173 auto target = GetTarget();
174 if (target == nullptr) {
175 ROSEN_LOGE("RSRenderSpringAnimation::OnDetach, target is nullptr");
176 return;
177 }
178 auto propertyId = GetPropertyId();
179 auto id = GetAnimationId();
180 target->GetAnimationManager().UnregisterSpringAnimation(propertyId, id);
181 }
182
OnInitialize(int64_t time)183 void RSRenderSpringAnimation::OnInitialize(int64_t time)
184 {
185 if (blendDuration_) {
186 auto lastFrameTime = animationFraction_.GetLastFrameTime();
187
188 // reset animation fraction
189 InheritSpringStatus(this);
190 animationFraction_.ResetFraction();
191 prevMappedTime_ = 0.0f;
192
193 // blend response by linear interpolation
194 uint64_t blendTime = (time - lastFrameTime) * animationFraction_.GetAnimationScale();
195 if (blendTime < blendDuration_) {
196 auto blendRatio = static_cast<float>(blendTime) / static_cast<float>(blendDuration_);
197 response_ += (finalResponse_ - response_) * blendRatio;
198 blendDuration_ -= blendTime;
199 } else {
200 // if blend duration is over, set response to final response
201 response_ = finalResponse_;
202 blendDuration_ = 0;
203 }
204 }
205
206 // set the initial status of spring model
207 initialOffset_ = startValue_ - endValue_;
208 if (initialVelocity_ == nullptr) {
209 initialVelocity_ = initialOffset_ * 0.f;
210 }
211 CalculateSpringParameters();
212
213 if (blendDuration_) {
214 // blend is still in progress, no need to estimate duration, use 300ms as default
215 SetDuration(300);
216 } else {
217 // blend finished, estimate duration until the spring system reaches rest
218 SetDuration(std::lroundf(EstimateDuration() * SECOND_TO_MILLISECOND));
219 // this will set needInitialize_ to false
220 RSRenderPropertyAnimation::OnInitialize(time);
221 }
222 }
223
224 std::tuple<std::shared_ptr<RSRenderPropertyBase>, std::shared_ptr<RSRenderPropertyBase>>
GetSpringStatus() const225 RSRenderSpringAnimation::GetSpringStatus() const
226 {
227 // if animation is never started, return start value and initial velocity
228 if (ROSEN_EQ(prevMappedTime_, 0.0f, FRACTION_THRESHOLD)) {
229 return { startValue_, initialVelocity_ };
230 }
231
232 auto displacement = lastValue_ - endValue_;
233
234 // use average velocity over a small time interval to estimate instantaneous velocity
235 constexpr double TIME_INTERVAL = 1e-6f; // 1e-6f : 1 microsecond to seconds
236 auto velocity = (CalculateDisplacement(prevMappedTime_ + TIME_INTERVAL) - displacement) * (1 / TIME_INTERVAL);
237
238 // return current position and velocity
239 return { lastValue_->Clone(), velocity };
240 }
241
InheritSpringStatus(const RSRenderSpringAnimation * from)242 void RSRenderSpringAnimation::InheritSpringStatus(const RSRenderSpringAnimation* from)
243 {
244 // inherit spring status from another spring animation
245 std::tie(startValue_, initialVelocity_) = from->GetSpringStatus();
246 originValue_ = startValue_->Clone();
247 lastValue_ = startValue_->Clone();
248 }
249 } // namespace Rosen
250 } // namespace OHOS
251