5c9f09788172cb62fd21f03ff4fc748b76b7498e
[chaz/yoink] / src / Moof / Interpolator.hh
1
2 /*******************************************************************************
3
4 Copyright (c) 2009, Charles McGarvey
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9
10 * Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 *******************************************************************************/
28
29 #ifndef _MOOF_INTERPOLATOR_HH_
30 #define _MOOF_INTERPOLATOR_HH_
31
32 #include <Moof/Log.hh>
33 #include <Moof/Math.hh>
34
35
36 namespace Mf {
37
38
39 // TODO - cleanup these classes
40
41 class Interpolator
42 {
43 void clamp(Scalar& value)
44 {
45 if (value > 1.0)
46 {
47 switch (mMode)
48 {
49 case STOP:
50 value = 1.0;
51 mDone = true;
52 break;
53 case REPEAT:
54 value -= 1.0;
55 break;
56 case OSCILLATE:
57 value = 2.0 - value;
58 mScale *= -1.0;
59 break;
60 }
61 }
62 else if (value < 0.0)
63 {
64 switch (mMode)
65 {
66 case STOP:
67 value = 0.0;
68 mDone = true;
69 break;
70 case REPEAT:
71 value += 1.0;
72 break;
73 case OSCILLATE:
74 value = -value;
75 mScale *= -1.0;
76 break;
77 }
78 }
79 }
80
81 public:
82
83 virtual ~Interpolator() {}
84
85 typedef enum
86 {
87 STOP = 0,
88 REPEAT = 1,
89 OSCILLATE = 2
90 } Mode;
91
92 void init(Scalar seconds = 1.0, Mode mode = STOP)
93 {
94 mScale = 1.0 / seconds;
95 mAlpha = 0.0;
96 setMode(mode);
97 }
98
99
100 void setMode(Mode mode)
101 {
102 mMode = mode;
103 mDone = false;
104 }
105
106
107 void update(Scalar t, Scalar dt)
108 {
109 if (!mDone)
110 {
111 mAlpha += dt * mScale;
112 clamp(mAlpha);
113 calculate(mAlpha);
114 }
115 }
116
117 bool isDone() const
118 {
119 return mDone;
120 }
121
122 virtual void calculate(Scalar alpha) = 0;
123
124 private:
125
126 Scalar mAlpha;
127 Mode mMode;
128 Scalar mScale;
129 bool mDone;
130 };
131
132 template <class T = Scalar>
133 class InterpolatorBase : public Interpolator
134 {
135 public:
136
137 virtual ~InterpolatorBase() {}
138
139 void init(Scalar seconds = 1.0, Mode mode = STOP)
140 {
141 Interpolator::init(seconds, mode);
142
143 calculate(0.0); // set value
144 mPrevious = mValue;
145 }
146
147 void calculate(Scalar alpha)
148 {
149 mPrevious = mValue;
150 calculate(mValue, alpha);
151 }
152
153 virtual void calculate(T& value, Scalar alpha) = 0;
154
155 const T& getValue() const
156 {
157 return mValue;
158 }
159
160 const T getState(Scalar alpha) const
161 {
162 return cml::lerp(mPrevious, mValue, alpha);
163 }
164
165 private:
166
167 T mValue;
168 T mPrevious;
169 };
170
171
172 template <int D, class T = Scalar>
173 class PolynomialInterpolator : public InterpolatorBase<T>
174 {
175 public:
176
177 PolynomialInterpolator() {}
178
179 PolynomialInterpolator(const T coefficients[D+1],
180 Scalar seconds = 1.0, Interpolator::Mode mode = Interpolator::STOP)
181 {
182 init(coefficients, seconds, mode);
183 }
184
185 void init(const T coefficients[D+1], Scalar seconds = 1.0,
186 Interpolator::Mode mode = Interpolator::STOP)
187 {
188 Scalar fac[D+1];
189
190 fac[0] = 1.0;
191 fac[1] = 1.0;
192
193 // build an array of the computed factorials we will need
194 for (int i = 2; i <= D; ++i)
195 {
196 fac[i] = i * fac[i - 1];
197 }
198
199 // combine the coefficients for fast updating
200 for (int i = 0; i <= D; ++i)
201 {
202 // n! / (k! * (n - k)!)
203 mCoefficients[i] = coefficients[i] * fac[D] / (fac[i] * fac[D - i]);
204 }
205
206 InterpolatorBase<T>::init(seconds, mode);
207 }
208
209
210 void calculate(T& value, Scalar alpha)
211 {
212 Scalar beta = 1.0 - alpha;
213
214 value = mCoefficients[0] * std::pow(beta, D);
215
216 for (int i = 1; i <= D; ++i)
217 {
218 value += mCoefficients[i] * std::pow(beta, D - i) *
219 std::pow(alpha, i);
220 }
221 }
222
223 private:
224
225 T mCoefficients[D+1];
226 };
227
228
229 // specialized linear interpolator
230
231 template <class T>
232 class PolynomialInterpolator<1,T> : public InterpolatorBase<T>
233 {
234 public:
235
236 PolynomialInterpolator() {}
237
238 PolynomialInterpolator(const T coefficients[2], Scalar seconds = 1.0,
239 Interpolator::Mode mode = Interpolator::STOP)
240 //InterpolatorBase<T>(seconds, mode)
241 {
242 init(coefficients, seconds, mode);
243 }
244
245 void init(const T coefficients[2], Scalar seconds = 1.0,
246 Interpolator::Mode mode = Interpolator::STOP)
247 {
248 mA = coefficients[0];
249 mB = coefficients[1];
250
251 InterpolatorBase<T>::init(seconds, mode);
252 }
253
254
255 void calculate(T& value, Scalar alpha)
256 {
257 value = cml::lerp(mA, mB, alpha);
258 }
259
260 private:
261
262 T mA;
263 T mB;
264 };
265
266
267 // Here are some aliases for more common interpolators. Also see the
268 // interpolation functions in cml for other types of interpolation such as
269 // slerp and some multi-alpha interpolators.
270
271 typedef PolynomialInterpolator<1> Lerp; // linear
272 typedef PolynomialInterpolator<1,Vector2> Lerp2;
273 typedef PolynomialInterpolator<1,Vector3> Lerp3;
274 typedef PolynomialInterpolator<1,Vector4> Lerp4;
275
276 typedef PolynomialInterpolator<2> Qerp; // quadratic
277 typedef PolynomialInterpolator<2,Vector2> Qerp2;
278 typedef PolynomialInterpolator<2,Vector3> Qerp3;
279 typedef PolynomialInterpolator<2,Vector4> Qerp4;
280
281 typedef PolynomialInterpolator<3> Cerp; // cubic
282 typedef PolynomialInterpolator<3,Vector2> Cerp2;
283 typedef PolynomialInterpolator<3,Vector3> Cerp3;
284 typedef PolynomialInterpolator<3,Vector4> Cerp4;
285
286
287 } // namespace Mf
288
289 #endif // _MOOF_INTERPOLATOR_HH_
290
291 /** vim: set ts=4 sw=4 tw=80: *************************************************/
292
This page took 0.040414 seconds and 3 git commands to generate.