1/*
2 * Copyright (c) 2020-2021 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 "animator/easing_equation.h"
17#include "gfx_utils/graphic_math.h"
18
19namespace OHOS {
20double EasingEquation::overshoot_ = 1.7; // The empirical value commonly used in easing equation
21
22void EasingEquation::SetBackOvershoot(double overshoot)
23{
24    if ((overshoot >= OVERSHOOT_MIN) && (overshoot <= OVERSHOOT_MAX)) {
25        overshoot_ = overshoot;
26    }
27}
28
29int16_t EasingEquation::BackEaseIn(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
30{
31    if (curTime < durationTime) {
32        double t = -(static_cast<double>(curTime) / durationTime);
33        double x = -t * t * ((overshoot_ + 1) * t + overshoot_);
34        return static_cast<int16_t>((x * (static_cast<int32_t>(endPos) - startPos)) + startPos);
35    }
36
37    return endPos;
38}
39
40int16_t EasingEquation::BackEaseOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
41{
42    if (curTime < durationTime) {
43        double t = static_cast<double>(curTime) / durationTime;
44        t -= 1.0;
45        double x = t * t * ((overshoot_ + 1) * t + overshoot_) + 1;
46        return static_cast<int16_t>((x * (static_cast<int32_t>(endPos) - startPos)) + startPos);
47    }
48
49    return endPos;
50}
51
52int16_t EasingEquation::BackEaseInOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
53{
54    uint16_t halfTime = durationTime >> 1;
55    int16_t halfStep = (endPos >> 1) + (startPos >> 1);
56    if (curTime < halfTime) {
57        return BackEaseIn(startPos, halfStep, curTime, halfTime);
58    }
59    return BackEaseOut(halfStep, endPos, curTime - halfTime, halfTime);
60}
61
62/* 1 - sqrt(1 - t^2) */
63int16_t EasingEquation::CircEaseIn(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
64{
65    if (curTime < durationTime) {
66        int32_t t = (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
67        uint32_t x = INTERPOLATION_RANGE - static_cast<int32_t>(Sqrt(INTERPOLATION_RANGE_SQUARE - t * t));
68        return static_cast<int16_t>(((x * (static_cast<int32_t>(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
69                                    startPos);
70    }
71
72    return endPos;
73}
74
75/* sqrt(1 - (1 - t)^2) */
76int16_t EasingEquation::CircEaseOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
77{
78    if (curTime < durationTime) {
79        int32_t t = INTERPOLATION_RANGE - (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
80        uint32_t x = static_cast<uint32_t>(Sqrt(INTERPOLATION_RANGE_SQUARE - t * t));
81        return static_cast<int16_t>(((x * (static_cast<int32_t>(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
82                                    startPos);
83    }
84
85    return endPos;
86}
87
88int16_t EasingEquation::CircEaseInOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
89{
90    uint16_t halfTime = durationTime >> 1;
91    int16_t halfStep = (endPos >> 1) + (startPos >> 1);
92    if (curTime < halfTime) {
93        return CircEaseIn(startPos, halfStep, curTime, halfTime);
94    }
95    return CircEaseOut(halfStep, endPos, curTime - halfTime, halfTime);
96}
97
98/* t^3 */
99int16_t EasingEquation::CubicEaseIn(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
100{
101    if (curTime < durationTime) {
102        int32_t t = (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
103        int16_t x = (t * t * t) >> (INTERPOLATION_RANGE_OFFSET << 1);
104        return static_cast<int16_t>(((x * (static_cast<int32_t>(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
105                                    startPos);
106    }
107
108    return endPos;
109}
110
111/* 1 - (1 - t)^3 */
112int16_t EasingEquation::CubicEaseOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
113{
114    if (curTime < durationTime) {
115        int32_t t = (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
116        t = INTERPOLATION_RANGE - t;
117        int16_t x = INTERPOLATION_RANGE - ((t * t * t) >> (INTERPOLATION_RANGE_OFFSET << 1));
118        return static_cast<int16_t>(((x * (static_cast<int32_t>(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
119                                    startPos);
120    }
121
122    return endPos;
123}
124
125int16_t EasingEquation::CubicEaseInOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
126{
127    uint16_t halfTime = durationTime >> 1;
128    int16_t halfStep = (endPos >> 1) + (startPos >> 1);
129    if (curTime < halfTime) {
130        return CubicEaseIn(startPos, halfStep, curTime, halfTime);
131    }
132    return CubicEaseOut(halfStep, endPos, curTime - halfTime, halfTime);
133}
134
135int16_t EasingEquation::LinearEaseNone(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
136{
137    if (curTime < durationTime) {
138        int32_t t = (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
139        return static_cast<int16_t>(((t * (static_cast<int32_t>(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
140                                    startPos);
141    }
142
143    return endPos;
144}
145
146/* t^2 */
147int16_t EasingEquation::QuadEaseIn(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
148{
149    if (curTime < durationTime) {
150        int32_t t = (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
151        int16_t x = (t * t) >> INTERPOLATION_RANGE_OFFSET;
152        return static_cast<int16_t>(((x * (static_cast<int32_t>(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
153                                    startPos);
154    }
155
156    return endPos;
157}
158
159/* 1 - (1 - t)^2 */
160int16_t EasingEquation::QuadEaseOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
161{
162    if (curTime < durationTime) {
163        int32_t t = INTERPOLATION_RANGE - (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
164        int16_t x = INTERPOLATION_RANGE - ((t * t) >> INTERPOLATION_RANGE_OFFSET);
165        return static_cast<int16_t>(((x * (static_cast<int32_t>(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
166                                    startPos);
167    }
168
169    return endPos;
170}
171
172int16_t EasingEquation::QuadEaseInOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
173{
174    uint16_t halfTime = durationTime >> 1;
175    int16_t halfStep = (endPos >> 1) + (startPos >> 1);
176    if (curTime < halfTime) {
177        return QuadEaseIn(startPos, halfStep, curTime, halfTime);
178    }
179    return QuadEaseOut(halfStep, endPos, curTime - halfTime, halfTime);
180}
181
182/* t^5 */
183int16_t EasingEquation::QuintEaseIn(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
184{
185    if (curTime < durationTime) {
186        int64_t t = (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
187
188        /* 4: the fourth power of t */
189        int16_t x = (t * t * t * t * t) >> (INTERPOLATION_RANGE_OFFSET * 4);
190        return static_cast<int16_t>(((x * (static_cast<int32_t>(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
191                                    startPos);
192    }
193
194    return endPos;
195}
196
197/* 1 - (1 - t)^5 */
198int16_t EasingEquation::QuintEaseOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
199{
200    if (curTime < durationTime) {
201        int64_t t = (curTime << INTERPOLATION_RANGE_OFFSET) / durationTime;
202        t = INTERPOLATION_RANGE - t;
203
204        /* 4: the fourth power of t */
205        int16_t x = INTERPOLATION_RANGE - ((t * t * t * t * t) >> (INTERPOLATION_RANGE_OFFSET * 4));
206        return static_cast<int16_t>(((x * (static_cast<int32_t>(endPos) - startPos)) >> INTERPOLATION_RANGE_OFFSET) +
207                                    startPos);
208    }
209
210    return endPos;
211}
212
213int16_t EasingEquation::QuintEaseInOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
214{
215    uint16_t halfTime = durationTime >> 1;
216    int16_t halfStep = (endPos >> 1) + (startPos >> 1);
217    if (curTime < halfTime) {
218        return QuintEaseIn(startPos, halfStep, curTime, halfTime);
219    }
220    return QuintEaseOut(halfStep, endPos, curTime - halfTime, halfTime);
221}
222
223int16_t EasingEquation::SineEaseIn(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
224{
225    if (curTime < durationTime) {
226        int16_t t = (curTime * QUARTER_IN_DEGREE) / durationTime - QUARTER_IN_DEGREE;
227        float x = Sin(t) + 1;
228        return static_cast<int16_t>(x * (endPos - startPos)) + startPos;
229    }
230
231    return endPos;
232}
233
234int16_t EasingEquation::SineEaseOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
235{
236    if (curTime < durationTime) {
237        int16_t t = (curTime * QUARTER_IN_DEGREE) / durationTime;
238        float x = Sin(t);
239        return static_cast<int16_t>(x * (endPos - startPos)) + startPos;
240    }
241
242    return endPos;
243}
244
245int16_t EasingEquation::SineEaseInOut(int16_t startPos, int16_t endPos, uint16_t curTime, uint16_t durationTime)
246{
247    uint16_t halfTime = durationTime >> 1;
248    int16_t halfStep = (endPos >> 1) + (startPos >> 1);
249    if (curTime < halfTime) {
250        return SineEaseIn(startPos, halfStep, curTime, halfTime);
251    }
252    return SineEaseOut(halfStep, endPos, curTime - halfTime, halfTime);
253}
254} // namespace OHOS
255