]> git.mxchange.org Git - simgear.git/blob - simgear/props/easing_functions.cxx
Fix #1783: repeated error message on console
[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 <simgear/math/SGMath.hxx>
25
26
27 namespace simgear
28 {
29
30   /// Simple linear easing.
31   double easingLinear(double t)
32   {
33     return t;
34   }
35
36   /// http://easings.net/#easeInSine
37   double easeInSine(double t)
38   {
39     return 1 - std::cos(t * M_PI_2);
40   }
41
42   /// http://easings.net/#easeOutSine
43   double easeOutSine(double t)
44   {
45     return std::sin(t * M_PI_2);
46   }
47
48   /// http://easings.net/#easeInOutSine
49   double easeInOutSine(double t)
50   {
51     return 0.5 - 0.5 * std::cos(t * M_PI);
52   }
53
54   template<easing_func_t easeIn, easing_func_t easeOut>
55   double easeInOut(double t)
56   {
57     if( (t *= 2) < 1 )
58       return 0.5 * (*easeIn)(t);
59     else
60       return 0.5 + 0.5 * (*easeOut)(t - 1);
61   }
62
63   /**
64    * Helper for exponential ease out with integer exponent.
65    *
66    * @tparam N      Exponent.
67    * @tparam is_odd If the exponent is odd.
68    */
69   template<size_t N, bool is_odd>
70   struct easeOutImpl;
71
72   /**
73    * Ease out with odd integer exponent.
74    *
75    * @tparam N Exponent.
76    * @see http://easings.net/#easeOutCubic (N = 3)
77    * @see http://easings.net/#easeOutQuint (N = 5)
78    */
79   template<size_t N>
80   struct easeOutImpl<N, true>
81   {
82     static double calc(double t)
83     {
84       return SGMiscd::pow<N>(t - 1) + 1;
85     }
86   };
87
88   /**
89    * Ease out with even integer exponent.
90    *
91    * @tparam N Exponent.
92    * @see http://easings.net/#easeOutQuad  (N = 2)
93    * @see http://easings.net/#easeOutQuart (N = 4)
94    */
95   template<size_t N>
96   struct easeOutImpl<N, false>
97   {
98     static double calc(double t)
99     {
100       return -SGMiscd::pow<N>(t - 1) + 1;
101     }
102   };
103
104   /**
105    * Exponential ease out with integer exponent.
106    *
107    * @see http://easings.net/#easeOutQuad  (N = 2)
108    * @see http://easings.net/#easeOutCubic (N = 3)
109    * @see http://easings.net/#easeOutQuart (N = 4)
110    * @see http://easings.net/#easeOutQuint (N = 5)
111    * @see easeOutImpl
112    */
113   template<size_t N>
114   double easeOutPow(double t)
115   {
116     return easeOutImpl<N, N & 1>::calc(t);
117   }
118
119   /// http://easings.net/#easeInOutQuad  (N = 2)
120   /// http://easings.net/#easeInOutCubic (N = 3)
121   /// http://easings.net/#easeInOutQuart (N = 4)
122   /// http://easings.net/#easeInOutQuint (N = 5)
123   template<size_t N>
124   double easeInOutPow(double t)
125   {
126     return easeInOut<&SGMiscd::pow<N>, &easeOutPow<N> >(t);
127   }
128
129   /// http://easings.net/#easeInExpo
130   double easeInExpo(double t)
131   {
132     return (t == 0) ? 0 : std::pow(2, 10 * (t - 1));
133   }
134
135   /// http://easings.net/#easeOutExpo
136   double easeOutExpo(double t)
137   {
138     return (t == 1) ? 1 : 1 - std::pow(2, -10 * t);
139   }
140
141   /// http://easings.net/#easeInCirc
142   double easeInCirc(double t)
143   {
144     return 1 - std::sqrt(1 - SGMiscd::pow<2>(t));
145   }
146
147   /// http://easings.net/#easeOutCirc
148   double easeOutCirc(double t)
149   {
150     return std::sqrt(1 - SGMiscd::pow<2>(t - 1));
151   }
152
153   static const double ease_s = 1.70158;
154
155   /// http://easings.net/#easeInBack
156   double easeInBack(double t)
157   {
158
159     return SGMiscd::pow<2>(t) * ((ease_s + 1) * t - ease_s);
160   }
161
162   /// http://easings.net/#easeOutBack
163   double easeOutBack(double t)
164   {
165     t -= 1;
166     return SGMiscd::pow<2>(t) * ((ease_s + 1) * t + ease_s) + 1;
167   }
168
169   /// http://easings.net/#easeOutBack
170   double easeInElastic(double t)
171   {
172     if( t == 0 )
173       return 0;
174     if( t == 1 )
175       return 1;
176
177     t -= 1;
178     const double p = .3;
179     const double s = p * 0.25;
180
181     return -std::pow(2, 10 * t) * std::sin((t - s) * 2 * M_PI / p);
182   }
183
184   /// http://easings.net/#easeOutBack
185   double easeOutElastic(double t)
186   {
187     if( t == 0 )
188       return 0;
189     if( t == 1 )
190       return 1;
191
192     const double p = .3;
193     const double s = p * 0.25;
194
195     return std::pow(2, -10 * t) * std::sin((t - s) * 2 * M_PI / p) + 1;
196   }
197
198   /// http://easings.net/#easeOutBounce
199   double easeOutBounce(double t)
200   {
201     if( t < 1/2.75 )
202       return 7.5625 * SGMiscd::pow<2>(t);
203     else if( t < 2/2.75 )
204       return 7.5625 * SGMiscd::pow<2>(t - 1.5/2.75) + .75;
205     else if( t < 2.5/2.75 )
206       return 7.5625 * SGMiscd::pow<2>(t - 2.25/2.75) + .9375;
207     else
208       return 7.5625 * SGMiscd::pow<2>(t - 2.625/2.75) + .984375;
209   }
210
211   /// http://easings.net/#easeInBounce
212   double easeInBounce(double time)
213   {
214     return 1 - easeOutBounce(1 - time);
215   }
216
217 #define SG_ADD_EASING(name) {#name, &name},
218 #define SG_STR(str) #str
219 #define SG_ADD_EASING_IN_OUT(name)\
220           SG_ADD_EASING(easeIn##name)\
221           SG_ADD_EASING(easeOut##name)\
222           {SG_STR(easeInOut##name), &easeInOut<&easeIn##name, &easeOut##name>},
223
224   const EasingMapEntry easing_functions[] = {
225     {"linear", &easingLinear},
226     {"swing", &easeInOutSine},
227     SG_ADD_EASING_IN_OUT(Sine)
228     {"easeInQuad",    &SGMiscd::pow<2>},
229     {"easeInCubic",   &SGMiscd::pow<3>},
230     {"easeInQuart",   &SGMiscd::pow<4>},
231     {"easeInQuint",   &SGMiscd::pow<5>},
232     {"easeOutQuad",   &easeOutPow<2>},
233     {"easeOutCubic",  &easeOutPow<3>},
234     {"easeOutQuart",  &easeOutPow<4>},
235     {"easeOutQuint",  &easeOutPow<5>},
236     {"easeInOutQuad", &easeInOutPow<2>},
237     {"easeInOutCubic",&easeInOutPow<3>},
238     {"easeInOutQuart",&easeInOutPow<4>},
239     {"easeInOutQuint",&easeInOutPow<5>},
240     SG_ADD_EASING_IN_OUT(Expo)
241     SG_ADD_EASING_IN_OUT(Circ)
242     SG_ADD_EASING_IN_OUT(Back)
243     SG_ADD_EASING_IN_OUT(Elastic)
244     SG_ADD_EASING_IN_OUT(Bounce)
245     {0, 0}
246   };
247
248 #undef SG_ADD_EASING
249 #undef SG_STR
250 #undef SG_ADD_EASING_IN_OUT
251
252 } // namespace simgear