1 /*
2  * Copyright (c) 2023 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_interpolating_spring_animation.h"
17 
18 #include "animation/rs_value_estimator.h"
19 #include "command/rs_animation_command.h"
20 #include "command/rs_message_processor.h"
21 #include "pipeline/rs_render_node.h"
22 #include "platform/common/rs_log.h"
23 
24 namespace OHOS {
25 namespace Rosen {
26 namespace {
27 constexpr float SECOND_TO_MILLISECOND = 1e3;
28 constexpr float MILLISECOND_TO_SECOND = 1e-3;
29 constexpr float FRAME_TIME_INTERVAL = 1.0f / 90.0f;
30 } // namespace
31 
RSRenderInterpolatingSpringAnimation(AnimationId id,const PropertyId & propertyId,const std::shared_ptr<RSRenderPropertyBase> & originValue,const std::shared_ptr<RSRenderPropertyBase> & startValue,const std::shared_ptr<RSRenderPropertyBase> & endValue)32 RSRenderInterpolatingSpringAnimation::RSRenderInterpolatingSpringAnimation(AnimationId id, const PropertyId& propertyId,
33     const std::shared_ptr<RSRenderPropertyBase>& originValue, const std::shared_ptr<RSRenderPropertyBase>& startValue,
34     const std::shared_ptr<RSRenderPropertyBase>& endValue)
35     : RSRenderPropertyAnimation(id, propertyId, originValue), RSSpringModel<float>(), startValue_(startValue),
36       endValue_(endValue)
37 {
38     // spring model is not initialized, so we can't calculate estimated duration
39 }
40 
DumpAnimationType(std::string & out) const41 void RSRenderInterpolatingSpringAnimation::DumpAnimationType(std::string& out) const
42 {
43     out += "Type:RSRenderInterpolatingSpringAnimation";
44 }
45 
SetSpringParameters(float response,float dampingRatio,float normalizedInitialVelocity,float minimumAmplitudeRatio)46 void RSRenderInterpolatingSpringAnimation::SetSpringParameters(
47     float response, float dampingRatio, float normalizedInitialVelocity, float minimumAmplitudeRatio)
48 {
49     response_ = response;
50     dampingRatio_ = dampingRatio;
51     normalizedInitialVelocity_ = normalizedInitialVelocity;
52     minimumAmplitudeRatio_ = minimumAmplitudeRatio;
53 }
54 
SetZeroThreshold(float zeroThreshold)55 void RSRenderInterpolatingSpringAnimation::SetZeroThreshold(float zeroThreshold)
56 {
57     constexpr float ZERO = 0.0f;
58     if (zeroThreshold < ZERO) {
59         ROSEN_LOGE("RSRenderInterpolatingSpringAnimation::SetZeroThreshold: invalid threshold value.");
60         needLogicallyFinishCallback_ = false;
61         return;
62     }
63     zeroThreshold_ = zeroThreshold;
64     needLogicallyFinishCallback_ = true;
65 }
66 
67 #ifdef ROSEN_OHOS
Marshalling(Parcel & parcel) const68 bool RSRenderInterpolatingSpringAnimation::Marshalling(Parcel& parcel) const
69 {
70     if (!RSRenderPropertyAnimation::Marshalling(parcel)) {
71         ROSEN_LOGE("RSRenderInterpolatingSpringAnimation::Marshalling, RenderPropertyAnimation failed");
72         return false;
73     }
74     if (!(RSRenderPropertyBase::Marshalling(parcel, startValue_) &&
75             RSRenderPropertyBase::Marshalling(parcel, endValue_))) {
76         ROSEN_LOGE("RSRenderInterpolatingSpringAnimation::Marshalling, MarshallingHelper failed");
77         return false;
78     }
79 
80     if (!(RSMarshallingHelper::Marshalling(parcel, response_) &&
81             RSMarshallingHelper::Marshalling(parcel, dampingRatio_) &&
82             RSMarshallingHelper::Marshalling(parcel, normalizedInitialVelocity_) &&
83             RSMarshallingHelper::Marshalling(parcel, minimumAmplitudeRatio_) &&
84             RSMarshallingHelper::Marshalling(parcel, needLogicallyFinishCallback_) &&
85             RSMarshallingHelper::Marshalling(parcel, zeroThreshold_))) {
86         ROSEN_LOGE("RSRenderInterpolatingSpringAnimation::Marshalling, invalid parametter failed");
87         return false;
88     }
89 
90     return true;
91 }
92 
Unmarshalling(Parcel & parcel)93 RSRenderInterpolatingSpringAnimation* RSRenderInterpolatingSpringAnimation::Unmarshalling(Parcel& parcel)
94 {
95     auto* renderInterpolatingSpringAnimation = new RSRenderInterpolatingSpringAnimation();
96     if (!renderInterpolatingSpringAnimation->ParseParam(parcel)) {
97         ROSEN_LOGE("RenderInterpolatingSpringAnimation::Unmarshalling, failed");
98         delete renderInterpolatingSpringAnimation;
99         return nullptr;
100     }
101     return renderInterpolatingSpringAnimation;
102 }
103 
ParseParam(Parcel & parcel)104 bool RSRenderInterpolatingSpringAnimation::ParseParam(Parcel& parcel)
105 {
106     if (!RSRenderPropertyAnimation::ParseParam(parcel)) {
107         ROSEN_LOGE("RSRenderInterpolatingSpringAnimation::ParseParam, ParseParam Fail");
108         return false;
109     }
110 
111     if (!(RSRenderPropertyBase::Unmarshalling(parcel, startValue_) &&
112             RSRenderPropertyBase::Unmarshalling(parcel, endValue_))) {
113         return false;
114     }
115 
116     if (!(RSMarshallingHelper::Unmarshalling(parcel, response_) &&
117             RSMarshallingHelper::Unmarshalling(parcel, dampingRatio_) &&
118             RSMarshallingHelper::Unmarshalling(parcel, normalizedInitialVelocity_) &&
119             RSMarshallingHelper::Unmarshalling(parcel, minimumAmplitudeRatio_) &&
120             RSMarshallingHelper::Unmarshalling(parcel, needLogicallyFinishCallback_) &&
121             RSMarshallingHelper::Unmarshalling(parcel, zeroThreshold_))) {
122         return false;
123     }
124 
125     return true;
126 }
127 #endif
128 
OnSetFraction(float fraction)129 void RSRenderInterpolatingSpringAnimation::OnSetFraction(float fraction)
130 {
131     if (valueEstimator_ == nullptr) {
132         return;
133     }
134     valueEstimator_->UpdateAnimationValue(fraction, GetAdditive());
135     SetValueFraction(fraction);
136     fractionChangeInfo_ = { true, fraction };
137 }
138 
UpdateFractionAfterContinue()139 void RSRenderInterpolatingSpringAnimation::UpdateFractionAfterContinue()
140 {
141     auto& [bChangeFraction, valueFraction] = fractionChangeInfo_;
142     if (bChangeFraction) {
143         SetFractionInner(CalculateTimeFraction(valueFraction));
144         bChangeFraction = false;
145         valueFraction = 0.0f;
146     }
147 }
148 
CalculateTimeFraction(float targetFraction)149 float RSRenderInterpolatingSpringAnimation::CalculateTimeFraction(float targetFraction)
150 {
151     int secondTime = std::ceil(static_cast<float>(GetDuration()) / SECOND_TO_MS);
152     if (secondTime <= 0) {
153         return FRACTION_MIN;
154     }
155     int64_t frameTimes = MAX_FRAME_TIME_FRACTION * secondTime;
156     float lastFraction = FRACTION_MIN;
157     for (int time = 1; time <= frameTimes; time++) {
158         float frameFraction = static_cast<float>(time) / frameTimes;
159         frameFraction = std::clamp(frameFraction, 0.0f, 1.0f);
160         auto mappedTime = frameFraction * GetDuration() * MILLISECOND_TO_SECOND;
161         float displacement = 1.0f + CalculateDisplacement(mappedTime);
162         if (lastFraction <= targetFraction && displacement >= targetFraction) {
163             return frameFraction;
164         }
165         lastFraction = displacement;
166     }
167     return FRACTION_MIN;
168 }
169 
OnAnimate(float fraction)170 void RSRenderInterpolatingSpringAnimation::OnAnimate(float fraction)
171 {
172     if (valueEstimator_ == nullptr) {
173         ROSEN_LOGD("RSRenderInterpolatingSpringAnimation::OnAnimate, valueEstimator_ is nullptr.");
174         return;
175     }
176     if (GetPropertyId() == 0) {
177         // calculateAnimationValue_ is embedded modify for stat animate frame drop
178         calculateAnimationValue_ = false;
179         return;
180     } else if (ROSEN_EQ(fraction, 1.0f)) {
181         valueEstimator_->UpdateAnimationValue(1.0f, GetAdditive());
182         return;
183     }
184     auto mappedTime = fraction * GetDuration() * MILLISECOND_TO_SECOND;
185     float displacement = 1.0f + CalculateDisplacement(mappedTime);
186     SetValueFraction(displacement);
187     valueEstimator_->UpdateAnimationValue(displacement, GetAdditive());
188     if (GetNeedLogicallyFinishCallback() && (animationFraction_.GetRemainingRepeatCount() == 1)) {
189         auto interpolationValue = valueEstimator_->Estimate(displacement, startValue_, endValue_);
190         auto endValue = animationFraction_.GetCurrentIsReverseCycle() ? startValue_ : endValue_;
191         auto velocity = CalculateVelocity(mappedTime);
192         auto zeroValue = startValue_ - startValue_;
193         if (interpolationValue != nullptr && !interpolationValue->IsNearEqual(endValue, zeroThreshold_)) {
194             return;
195         }
196         if (velocity != nullptr && (velocity * FRAME_TIME_INTERVAL)->IsNearEqual(zeroValue, zeroThreshold_)) {
197             CallLogicallyFinishCallback();
198             needLogicallyFinishCallback_ = false;
199         }
200     }
201 }
202 
OnInitialize(int64_t time)203 void RSRenderInterpolatingSpringAnimation::OnInitialize(int64_t time)
204 {
205     // set the initial status of spring model
206     initialOffset_ = -1.0f;
207     initialVelocity_ = initialOffset_ * (-normalizedInitialVelocity_);
208     CalculateSpringParameters();
209     // use duration calculated by spring model as animation duration
210     SetDuration(std::lroundf(EstimateDuration() * SECOND_TO_MILLISECOND));
211     // this will set needInitialize_ to false
212     RSRenderPropertyAnimation::OnInitialize(time);
213 }
214 
InitValueEstimator()215 void RSRenderInterpolatingSpringAnimation::InitValueEstimator()
216 {
217     if (valueEstimator_ == nullptr) {
218         valueEstimator_ = property_->CreateRSValueEstimator(RSValueEstimatorType::CURVE_VALUE_ESTIMATOR);
219     }
220     if (valueEstimator_) {
221         valueEstimator_->InitCurveAnimationValue(property_, startValue_, endValue_, lastValue_);
222     } else {
223         ROSEN_LOGE("RSRenderInterpolatingSpringAnimation::InitValueEstimator, valueEstimator_ is nullptr.");
224     }
225 }
226 
CalculateVelocity(float time) const227 std::shared_ptr<RSRenderPropertyBase> RSRenderInterpolatingSpringAnimation::CalculateVelocity(float time) const
228 {
229     if (valueEstimator_ == nullptr) {
230         ROSEN_LOGE("RSRenderInterpolatingSpringAnimation::CalculateVelocity, valueEstimator_ is nullptr.");
231         return nullptr;
232     }
233     constexpr float TIME_INTERVAL = 1e-6f; // 1e-6f : 1 microsecond
234     float currentDisplacement = 1.0f + CalculateDisplacement(time);
235     float nextDisplacement = 1.0f + CalculateDisplacement(time + TIME_INTERVAL);
236     auto velocity = (valueEstimator_->Estimate(nextDisplacement, startValue_, endValue_) -
237         valueEstimator_->Estimate(currentDisplacement, startValue_, endValue_)) * (1 / TIME_INTERVAL);
238 
239     return velocity;
240 }
241 
GetNeedLogicallyFinishCallback() const242 bool RSRenderInterpolatingSpringAnimation::GetNeedLogicallyFinishCallback() const
243 {
244     return needLogicallyFinishCallback_;
245 }
246 
CallLogicallyFinishCallback() const247 void RSRenderInterpolatingSpringAnimation::CallLogicallyFinishCallback() const
248 {
249     NodeId targetId = GetTargetId();
250     AnimationId animationId = GetAnimationId();
251 
252     std::unique_ptr<RSCommand> command =
253         std::make_unique<RSAnimationCallback>(targetId, animationId, LOGICALLY_FINISHED);
254     RSMessageProcessor::Instance().AddUIMessage(ExtractPid(animationId), std::move(command));
255 }
256 } // namespace Rosen
257 } // namespace OHOS