kodi
Tween.h
1 /*
2  * Copyright (C) 2005-2018 Team Kodi
3  * This file is part of Kodi - https://kodi.tv
4  *
5  * SPDX-License-Identifier: GPL-2.0-or-later
6  * See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
12 // Tween.h
13 // A couple of tweening classes implemented in C++.
14 // ref: http://www.robertpenner.com/easing/
15 //
16 // Author: d4rk <d4rk@xbmc.org>
18 
19 
21 // Current list of classes:
22 //
23 // LinearTweener
24 // QuadTweener
25 // CubicTweener
26 // SineTweener
27 // CircleTweener
28 // BackTweener
29 // BounceTweener
30 // ElasticTweener
31 //
33 
34 #include <math.h>
35 
36 #ifndef M_PI
37 #define M_PI 3.14159265358979323846
38 #endif
39 
40 enum TweenerType
41 {
42  EASE_IN,
43  EASE_OUT,
44  EASE_INOUT
45 };
46 
47 
48 class Tweener
49 {
50 public:
51  explicit Tweener(TweenerType tweenerType = EASE_OUT) { m_tweenerType = tweenerType; }
52  virtual ~Tweener() = default;
53 
54  void SetEasing(TweenerType type) { m_tweenerType = type; }
55  virtual float Tween(float time, float start, float change, float duration)=0;
56  virtual bool HasResumePoint() const { return m_tweenerType == EASE_INOUT; }
57 protected:
58  TweenerType m_tweenerType;
59 };
60 
61 
62 class LinearTweener : public Tweener
63 {
64 public:
65  float Tween(float time, float start, float change, float duration) override
66  {
67  return change * time / duration + start;
68  }
69  bool HasResumePoint() const override { return false; }
70 };
71 
72 
73 class QuadTweener : public Tweener
74 {
75 public:
76  explicit QuadTweener(float a = 1.0f) { _a=a; }
77  float Tween(float time, float start, float change, float duration) override
78  {
79  switch (m_tweenerType)
80  {
81  case EASE_IN:
82  time /= duration;
83  return change * time * (_a * time + 1 - _a) + start;
84  break;
85 
86  case EASE_OUT:
87  time /= duration;
88  return -change * time * (_a * time - 1 - _a) + start;
89  break;
90 
91  case EASE_INOUT:
92  time /= duration/2;
93  if (time < 1)
94  return (change) * time * (_a * time + 1 - _a) + start;
95  time--;
96  return (-change) * time * (_a * time - 1 - _a) + start;
97  break;
98  }
99  return change * time * time + start;
100  }
101 private:
102  float _a;
103 };
104 
105 
106 class CubicTweener : public Tweener
107 {
108 public:
109  float Tween(float time, float start, float change, float duration) override
110  {
111  switch (m_tweenerType)
112  {
113  case EASE_IN:
114  time /= duration;
115  return change * time * time * time + start;
116  break;
117 
118  case EASE_OUT:
119  time /= duration;
120  time--;
121  return change * (time * time * time + 1) + start;
122  break;
123 
124  case EASE_INOUT:
125  time /= duration/2;
126  if (time < 1)
127  return (change/2) * time * time * time + start;
128  time-=2;
129  return (change/2) * (time * time * time + 2) + start;
130  break;
131  }
132  return change * time * time + start;
133  }
134 };
135 
136 class CircleTweener : public Tweener
137 {
138 public:
139  float Tween(float time, float start, float change, float duration) override
140  {
141  switch (m_tweenerType)
142  {
143  case EASE_IN:
144  time /= duration;
145  return (-change) * (sqrt(1 - time * time) - 1) + start;
146  break;
147 
148  case EASE_OUT:
149  time /= duration;
150  time--;
151  return change * sqrt(1 - time * time) + start;
152  break;
153 
154  case EASE_INOUT:
155  time /= duration/2;
156  if (time < 1)
157  return (-change/2) * (sqrt(1 - time * time) - 1) + start;
158  time-=2;
159  return change/2 * (sqrt(1 - time * time) + 1) + start;
160  break;
161  }
162  return change * sqrt(1 - time * time) + start;
163  }
164 };
165 
166 class BackTweener : public Tweener
167 {
168 public:
169  explicit BackTweener(float s=1.70158) { _s=s; }
170 
171  float Tween(float time, float start, float change, float duration) override
172  {
173  float s = _s;
174  switch (m_tweenerType)
175  {
176  case EASE_IN:
177  time /= duration;
178  return change * time * time * ((s + 1) * time - s) + start;
179  break;
180 
181  case EASE_OUT:
182  time /= duration;
183  time--;
184  return change * (time * time * ((s + 1) * time + s) + 1) + start;
185  break;
186 
187  case EASE_INOUT:
188  time /= duration/2;
189  s*=(1.525f);
190  if ((time ) < 1)
191  {
192  return (change/2) * (time * time * ((s + 1) * time - s)) + start;
193  }
194  time-=2;
195  return (change/2) * (time * time * ((s + 1) * time + s) + 2) + start;
196  break;
197  }
198  return change * ((time-1) * time * ((s + 1) * time + s) + 1) + start;
199  }
200 private:
201  float _s;
202 
203 };
204 
205 
206 class SineTweener : public Tweener
207 {
208 public:
209  float Tween(float time, float start, float change, float duration) override
210  {
211  time /= duration;
212  switch (m_tweenerType)
213  {
214  case EASE_IN:
215  return change * (1 - cos(time * static_cast<float>(M_PI) / 2.0f)) + start;
216  break;
217 
218  case EASE_OUT:
219  return change * sin(time * static_cast<float>(M_PI) / 2.0f) + start;
220  break;
221 
222  case EASE_INOUT:
223  return change / 2 * (1 - cos(static_cast<float>(M_PI) * time)) + start;
224  break;
225  }
226  return (change / 2) * (1 - cos(static_cast<float>(M_PI) * time)) + start;
227  }
228 };
229 
230 
231 class BounceTweener : public Tweener
232 {
233 public:
234  float Tween(float time, float start, float change, float duration) override
235  {
236  switch (m_tweenerType)
237  {
238  case EASE_IN:
239  return (change - easeOut(duration - time, 0, change, duration)) + start;
240  break;
241 
242  case EASE_OUT:
243  return easeOut(time, start, change, duration);
244  break;
245 
246  case EASE_INOUT:
247  if (time < duration/2)
248  return (change - easeOut (duration - (time * 2), 0, change, duration) + start) * .5f + start;
249  else
250  return (easeOut (time * 2 - duration, 0, change, duration) * .5f + change * .5f) + start;
251  break;
252  }
253 
254  return easeOut(time, start, change, duration);
255  }
256 protected:
257  static float easeOut(float time, float start, float change, float duration)
258  {
259  time /= duration;
260  if (time < (1 / 2.75f))
261  {
262  return change * (7.5625f * time * time) + start;
263  }
264  else if (time < (2 / 2.75f))
265  {
266  time -= (1.5f/2.75f);
267  return change * (7.5625f * time * time + .75f) + start;
268  }
269  else if (time < (2.5f / 2.75f))
270  {
271  time -= (2.25f/2.75f);
272  return change * (7.5625f * time * time + .9375f) + start;
273  }
274  else
275  {
276  time -= (2.625f/2.75f);
277  return change * (7.5625f * time * time + .984375f) + start;
278  }
279  }
280 };
281 
282 
283 class ElasticTweener : public Tweener
284 {
285 public:
286  ElasticTweener(float a=0.0, float p=0.0) { _a=a; _p=p; }
287 
288  float Tween(float time, float start, float change, float duration) override
289  {
290  switch (m_tweenerType)
291  {
292  case EASE_IN:
293  return easeIn(time, start, change, duration);
294  break;
295 
296  case EASE_OUT:
297  return easeOut(time, start, change, duration);
298  break;
299 
300  case EASE_INOUT:
301  return easeInOut(time, start, change, duration);
302  break;
303  }
304  return easeOut(time, start, change, duration);
305  }
306 protected:
307  float _a;
308  float _p;
309 
310  float easeIn(float time, float start, float change, float duration) const
311  {
312  float s=0;
313  float a=_a;
314  float p=_p;
315 
316  if (time==0)
317  return start;
318  time /= duration;
319  if (time==1)
320  return start + change;
321  if (!p)
322  p=duration*.3f;
323  if (!a || a < fabs(change))
324  {
325  a = change;
326  s = p / 4.0f;
327  }
328  else
329  {
330  s = p / (2 * static_cast<float>(M_PI)) * asin(change / a);
331  }
332  time--;
333  return -(a * pow(2.0f, 10 * time) *
334  sin((time * duration - s) * (2 * static_cast<float>(M_PI)) / p)) +
335  start;
336  }
337 
338  float easeOut(float time, float start, float change, float duration) const
339  {
340  float s=0;
341  float a=_a;
342  float p=_p;
343 
344  if (time==0)
345  return start;
346  time /= duration;
347  if (time==1)
348  return start + change;
349  if (!p)
350  p=duration*.3f;
351  if (!a || a < fabs(change))
352  {
353  a = change;
354  s = p / 4.0f;
355  }
356  else
357  {
358  s = p / (2 * static_cast<float>(M_PI)) * asin(change / a);
359  }
360  return (a * pow(2.0f, -10 * time) *
361  sin((time * duration - s) * (2 * static_cast<float>(M_PI)) / p)) +
362  change + start;
363  }
364 
365  float easeInOut(float time, float start, float change, float duration) const
366  {
367  float s=0;
368  float a=_a;
369  float p=_p;
370 
371  if (time==0)
372  return start;
373  time /= duration/2;
374  if (time==2)
375  return start + change;
376  if (!p)
377  p=duration*.3f*1.5f;
378  if (!a || a < fabs(change))
379  {
380  a = change;
381  s = p / 4.0f;
382  }
383  else
384  {
385  s = p / (2 * static_cast<float>(M_PI)) * asin(change / a);
386  }
387 
388  if (time < 1)
389  {
390  time--;
391  return -.5f * (a * pow(2.0f, 10 * (time)) *
392  sin((time * duration - s) * (2 * static_cast<float>(M_PI)) / p)) +
393  start;
394  }
395  time--;
396  return a * pow(2.0f, -10 * (time)) *
397  sin((time * duration - s) * (2 * static_cast<float>(M_PI)) / p) * .5f +
398  change + start;
399  }
400 };
401 
Definition: Tween.h:283
Definition: Tween.h:62
Definition: Tween.h:166
Definition: Tween.h:106
Definition: Tween.h:231
Definition: Tween.h:136
Definition: Tween.h:73
Definition: Tween.h:48
Definition: Tween.h:206