]> git.mxchange.org Git - simgear.git/blob - simgear/props/easing_functions.cxx
New interpolation/animation system.
[simgear.git] / simgear / props / easing_functions.cxx
1 ///@file
2 /// Easing functions for property interpolation.
3 ///
4 /// Based on easing functions by Robert Penner
5 /// (http://www.robertpenner.com/easing)
6 //
7 // Copyright (C) 2013  Thomas Geymayer <tomgey@gmail.com>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Library General Public
11 // License as published by the Free Software Foundation; either
12 // version 2 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 // Library General Public License for more details.
18 //
19 // You should have received a copy of the GNU Library General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
22
23 #include "easing_functions.hxx"
24 #include <cmath>
25 #include <cstddef>
26
27 namespace simgear
28 {
29   // TODO move somewhere to math
30   template<size_t N>
31   double pow(double base)
32   {
33     return base * pow<N - 1>(base);
34   }
35
36   template<>
37   double pow<0>(double)
38   {
39     return 1.0;
40   }
41
42   /// Simple linear easing.
43   double easingLinear(double t)
44   {
45     return t;
46   }
47
48   /// http://easings.net/#easeInSine
49   double easeInSine(double t)
50   {
51     return 1 - std::cos(t * M_PI_2);
52   }
53
54   /// http://easings.net/#easeOutSine
55   double easeOutSine(double t)
56   {
57     return std::sin(t * M_PI_2);
58   }
59
60   /// http://easings.net/#easeInOutSine
61   double easeInOutSine(double t)
62   {
63     return 0.5 - 0.5 * std::cos(t * M_PI);
64   }
65
66   template<easing_func_t easeIn, easing_func_t easeOut>
67   double easeInOut(double t)
68   {
69     if( (t *= 2) < 1 )
70       return 0.5 * (*easeIn)(t);
71     else
72       return 0.5 + 0.5 * (*easeOut)(t - 1);
73   }
74
75   template<size_t N, bool is_odd>
76   struct easeOutImpl;
77
78   /// http://easings.net/#easeOutCubic (N = 3)
79   /// http://easings.net/#easeOutQuint (N = 5)
80   template<size_t N>
81   struct easeOutImpl<N, true>
82   {
83     static double calc(double t)
84     {
85       return pow<N>(t - 1) + 1;
86     }
87   };
88
89   /// http://easings.net/#easeOutQuad  (N = 2)
90   /// http://easings.net/#easeOutQuart (N = 4)
91   template<size_t N>
92   struct easeOutImpl<N, false>
93   {
94     static double calc(double t)
95     {
96       return -pow<N>(t - 1) + 1;
97     }
98   };
99
100   /// http://easings.net/#easeOutQuad  (N = 2)
101   /// http://easings.net/#easeOutCubic (N = 3)
102   /// http://easings.net/#easeOutQuart (N = 4)
103   /// http://easings.net/#easeOutQuint (N = 5)
104   template<size_t N>
105   double easeOutPow(double t)
106   {
107     return easeOutImpl<N, N & 1>::calc(t);
108   }
109
110   /// http://easings.net/#easeInOutQuad  (N = 2)
111   /// http://easings.net/#easeInOutCubic (N = 3)
112   /// http://easings.net/#easeInOutQuart (N = 4)
113   /// http://easings.net/#easeInOutQuint (N = 5)
114   template<size_t N>
115   double easeInOutPow(double t)
116   {
117     return easeInOut<&pow<N>, &easeOutPow<N> >(t);
118   }
119
120   /// http://easings.net/#easeInExpo
121   double easeInExpo(double t)
122   {
123     return (t == 0) ? 0 : std::pow(2, 10 * (t - 1));
124   }
125
126   /// http://easings.net/#easeOutExpo
127   double easeOutExpo(double t)
128   {
129     return (t == 1) ? 1 : 1 - std::pow(2, -10 * t);
130   }
131
132   /// http://easings.net/#easeInCirc
133   double easeInCirc(double t)
134   {
135     return 1 - std::sqrt(1 - pow<2>(t));
136   }
137
138   /// http://easings.net/#easeOutCirc
139   double easeOutCirc(double t)
140   {
141     return std::sqrt(1 - pow<2>(t - 1));
142   }
143
144   static const double ease_s = 1.70158;
145
146   /// http://easings.net/#easeInBack
147   double easeInBack(double t)
148   {
149
150     return pow<2>(t) * ((ease_s + 1) * t - ease_s);
151   }
152
153   /// http://easings.net/#easeOutBack
154   double easeOutBack(double t)
155   {
156     t -= 1;
157     return pow<2>(t) * ((ease_s + 1) * t + ease_s) + 1;
158   }
159
160   /// http://easings.net/#easeOutBack
161   double easeInElastic(double t)
162   {
163     if( t == 0 )
164       return 0;
165     if( t == 1 )
166       return 1;
167
168     t -= 1;
169     const double p = .3;
170     const double s = p * 0.25;
171
172     return -std::pow(2, 10 * t) * std::sin((t - s) * 2 * M_PI / p);
173   }
174
175   /// http://easings.net/#easeOutBack
176   double easeOutElastic(double t)
177   {
178     if( t == 0 )
179       return 0;
180     if( t == 1 )
181       return 1;
182
183     const double p = .3;
184     const double s = p * 0.25;
185
186     return std::pow(2, -10 * t) * std::sin((t - s) * 2 * M_PI / p) + 1;
187   }
188
189   /// http://easings.net/#easeOutBounce
190   double easeOutBounce(double t)
191   {
192     if( t < 1/2.75 )
193       return 7.5625 * pow<2>(t);
194     else if( t < 2/2.75 )
195       return 7.5625 * pow<2>(t - 1.5/2.75) + .75;
196     else if( t < 2.5/2.75 )
197       return 7.5625 * pow<2>(t - 2.25/2.75) + .9375;
198     else
199       return 7.5625 * pow<2>(t - 2.625/2.75) + .984375;
200   }
201
202   /// http://easings.net/#easeInBounce
203   double easeInBounce(double time)
204   {
205     return 1 - easeOutBounce(1 - time);
206   }
207
208 #define SG_ADD_EASING(name) {#name, &name},
209 #define SG_STR(str) #str
210 #define SG_ADD_EASING_IN_OUT(name)\
211           SG_ADD_EASING(easeIn##name)\
212           SG_ADD_EASING(easeOut##name)\
213           {SG_STR(easeInOut##name), &easeInOut<&easeIn##name, &easeOut##name>},
214
215   const EasingMapEntry easing_functions[] = {
216     {"linear", &easingLinear},
217     {"swing", &easeInOutSine},
218     SG_ADD_EASING_IN_OUT(Sine)
219     {"easeInQuad",    &pow<2>},
220     {"easeInCubic",   &pow<3>},
221     {"easeInQuart",   &pow<4>},
222     {"easeInQuint",   &pow<5>},
223     {"easeOutQuad",   &easeOutPow<2>},
224     {"easeOutCubic",  &easeOutPow<3>},
225     {"easeOutQuart",  &easeOutPow<4>},
226     {"easeOutQuint",  &easeOutPow<5>},
227     {"easeInOutQuad", &easeInOutPow<2>},
228     {"easeInOutCubic",&easeInOutPow<3>},
229     {"easeInOutQuart",&easeInOutPow<4>},
230     {"easeInOutQuint",&easeInOutPow<5>},
231     SG_ADD_EASING_IN_OUT(Expo)
232     SG_ADD_EASING_IN_OUT(Circ)
233     SG_ADD_EASING_IN_OUT(Back)
234     SG_ADD_EASING_IN_OUT(Elastic)
235     SG_ADD_EASING_IN_OUT(Bounce)
236     {0, 0}
237   };
238
239 #undef SG_ADD_EASING
240 #undef SG_STR
241 #undef SG_ADD_EASING_IN_OUT
242
243 } // namespace simgear