1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code 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
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #ifndef __MATH_INTERPOLATE_H__
30 #define __MATH_INTERPOLATE_H__
31
32 #include "idlib/math/Extrapolate.h"
33
34 /*
35 ==============================================================================================
36
37 Linear interpolation.
38
39 ==============================================================================================
40 */
41
42 template< class type >
43 class idInterpolate {
44 public:
45 idInterpolate();
46
47 void Init( const float startTime, const float duration, const type &startValue, const type &endValue );
SetStartTime(float time)48 void SetStartTime( float time ) { this->startTime = time; }
SetDuration(float duration)49 void SetDuration( float duration ) { this->duration = duration; }
SetStartValue(const type & startValue)50 void SetStartValue( const type &startValue ) { this->startValue = startValue; }
SetEndValue(const type & endValue)51 void SetEndValue( const type &endValue ) { this->endValue = endValue; }
52
53 type GetCurrentValue( float time ) const;
IsDone(float time)54 bool IsDone( float time ) const { return ( time >= startTime + duration ); }
55
GetStartTime(void)56 float GetStartTime( void ) const { return startTime; }
GetEndTime(void)57 float GetEndTime( void ) const { return startTime + duration; }
GetDuration(void)58 float GetDuration( void ) const { return duration; }
GetStartValue(void)59 const type & GetStartValue( void ) const { return startValue; }
GetEndValue(void)60 const type & GetEndValue( void ) const { return endValue; }
61
62 private:
63 float startTime;
64 float duration;
65 type startValue;
66 type endValue;
67 mutable float currentTime;
68 mutable type currentValue;
69 };
70
71 /*
72 ====================
73 idInterpolate::idInterpolate
74 ====================
75 */
76 template< class type >
idInterpolate()77 ID_INLINE idInterpolate<type>::idInterpolate() {
78 currentTime = startTime = duration = 0;
79 memset( ¤tValue, 0, sizeof( currentValue ) );
80 startValue = endValue = currentValue;
81 }
82
83 /*
84 ====================
85 idInterpolate::Init
86 ====================
87 */
88 template< class type >
Init(const float startTime,const float duration,const type & startValue,const type & endValue)89 ID_INLINE void idInterpolate<type>::Init( const float startTime, const float duration, const type &startValue, const type &endValue ) {
90 this->startTime = startTime;
91 this->duration = duration;
92 this->startValue = startValue;
93 this->endValue = endValue;
94 this->currentTime = startTime - 1;
95 this->currentValue = startValue;
96 }
97
98 /*
99 ====================
100 idInterpolate::GetCurrentValue
101 ====================
102 */
103 template< class type >
GetCurrentValue(float time)104 ID_INLINE type idInterpolate<type>::GetCurrentValue( float time ) const {
105 float deltaTime;
106
107 deltaTime = time - startTime;
108 if ( time != currentTime ) {
109 currentTime = time;
110 if ( deltaTime <= 0 ) {
111 currentValue = startValue;
112 } else if ( deltaTime >= duration ) {
113 currentValue = endValue;
114 } else {
115 currentValue = startValue + ( endValue - startValue ) * ( (float) deltaTime / duration );
116 }
117 }
118 return currentValue;
119 }
120
121
122 /*
123 ==============================================================================================
124
125 Continuous interpolation with linear acceleration and deceleration phase.
126 The velocity is continuous but the acceleration is not.
127
128 ==============================================================================================
129 */
130
131 template< class type >
132 class idInterpolateAccelDecelLinear {
133 public:
134 idInterpolateAccelDecelLinear();
135
136 void Init( const float startTime, const float accelTime, const float decelTime, const float duration, const type &startValue, const type &endValue );
SetStartTime(float time)137 void SetStartTime( float time ) { startTime = time; Invalidate(); }
SetStartValue(const type & startValue)138 void SetStartValue( const type &startValue ) { this->startValue = startValue; Invalidate(); }
SetEndValue(const type & endValue)139 void SetEndValue( const type &endValue ) { this->endValue = endValue; Invalidate(); }
140
141 type GetCurrentValue( float time ) const;
142 type GetCurrentSpeed( float time ) const;
IsDone(float time)143 bool IsDone( float time ) const { return ( time >= startTime + accelTime + linearTime + decelTime ); }
144
GetStartTime(void)145 float GetStartTime( void ) const { return startTime; }
GetEndTime(void)146 float GetEndTime( void ) const { return startTime + accelTime + linearTime + decelTime; }
GetDuration(void)147 float GetDuration( void ) const { return accelTime + linearTime + decelTime; }
GetAcceleration(void)148 float GetAcceleration( void ) const { return accelTime; }
GetDeceleration(void)149 float GetDeceleration( void ) const { return decelTime; }
GetStartValue(void)150 const type & GetStartValue( void ) const { return startValue; }
GetEndValue(void)151 const type & GetEndValue( void ) const { return endValue; }
152
153 private:
154 float startTime;
155 float accelTime;
156 float linearTime;
157 float decelTime;
158 type startValue;
159 type endValue;
160 mutable idExtrapolate<type> extrapolate;
161
162 void Invalidate( void );
163 void SetPhase( float time ) const;
164 };
165
166 /*
167 ====================
168 idInterpolateAccelDecelLinear::idInterpolateAccelDecelLinear
169 ====================
170 */
171 template< class type >
idInterpolateAccelDecelLinear()172 ID_INLINE idInterpolateAccelDecelLinear<type>::idInterpolateAccelDecelLinear() {
173 startTime = accelTime = linearTime = decelTime = 0;
174 memset( &startValue, 0, sizeof( startValue ) );
175 endValue = startValue;
176 }
177
178 /*
179 ====================
180 idInterpolateAccelDecelLinear::Init
181 ====================
182 */
183 template< class type >
Init(const float startTime,const float accelTime,const float decelTime,const float duration,const type & startValue,const type & endValue)184 ID_INLINE void idInterpolateAccelDecelLinear<type>::Init( const float startTime, const float accelTime, const float decelTime, const float duration, const type &startValue, const type &endValue ) {
185 type speed;
186
187 this->startTime = startTime;
188 this->accelTime = accelTime;
189 this->decelTime = decelTime;
190 this->startValue = startValue;
191 this->endValue = endValue;
192
193 if ( duration <= 0.0f ) {
194 return;
195 }
196
197 if ( this->accelTime + this->decelTime > duration ) {
198 this->accelTime = this->accelTime * duration / ( this->accelTime + this->decelTime );
199 this->decelTime = duration - this->accelTime;
200 }
201 this->linearTime = duration - this->accelTime - this->decelTime;
202 speed = ( endValue - startValue ) * ( 1000.0f / ( (float) this->linearTime + ( this->accelTime + this->decelTime ) * 0.5f ) );
203
204 if ( this->accelTime ) {
205 extrapolate.Init( startTime, this->accelTime, startValue, ( startValue - startValue ), speed, EXTRAPOLATION_ACCELLINEAR );
206 } else if ( this->linearTime ) {
207 extrapolate.Init( startTime, this->linearTime, startValue, ( startValue - startValue ), speed, EXTRAPOLATION_LINEAR );
208 } else {
209 extrapolate.Init( startTime, this->decelTime, startValue, ( startValue - startValue ), speed, EXTRAPOLATION_DECELLINEAR );
210 }
211 }
212
213 /*
214 ====================
215 idInterpolateAccelDecelLinear::Invalidate
216 ====================
217 */
218 template< class type >
Invalidate(void)219 ID_INLINE void idInterpolateAccelDecelLinear<type>::Invalidate( void ) {
220 extrapolate.Init( 0, 0, extrapolate.GetStartValue(), extrapolate.GetBaseSpeed(), extrapolate.GetSpeed(), EXTRAPOLATION_NONE );
221 }
222
223 /*
224 ====================
225 idInterpolateAccelDecelLinear::SetPhase
226 ====================
227 */
228 template< class type >
SetPhase(float time)229 ID_INLINE void idInterpolateAccelDecelLinear<type>::SetPhase( float time ) const {
230 float deltaTime;
231
232 deltaTime = time - startTime;
233 if ( deltaTime < accelTime ) {
234 if ( extrapolate.GetExtrapolationType() != EXTRAPOLATION_ACCELLINEAR ) {
235 extrapolate.Init( startTime, accelTime, startValue, extrapolate.GetBaseSpeed(), extrapolate.GetSpeed(), EXTRAPOLATION_ACCELLINEAR );
236 }
237 } else if ( deltaTime < accelTime + linearTime ) {
238 if ( extrapolate.GetExtrapolationType() != EXTRAPOLATION_LINEAR ) {
239 extrapolate.Init( startTime + accelTime, linearTime, startValue + extrapolate.GetSpeed() * ( accelTime * 0.001f * 0.5f ), extrapolate.GetBaseSpeed(), extrapolate.GetSpeed(), EXTRAPOLATION_LINEAR );
240 }
241 } else {
242 if ( extrapolate.GetExtrapolationType() != EXTRAPOLATION_DECELLINEAR ) {
243 extrapolate.Init( startTime + accelTime + linearTime, decelTime, endValue - ( extrapolate.GetSpeed() * ( decelTime * 0.001f * 0.5f ) ), extrapolate.GetBaseSpeed(), extrapolate.GetSpeed(), EXTRAPOLATION_DECELLINEAR );
244 }
245 }
246 }
247
248 /*
249 ====================
250 idInterpolateAccelDecelLinear::GetCurrentValue
251 ====================
252 */
253 template< class type >
GetCurrentValue(float time)254 ID_INLINE type idInterpolateAccelDecelLinear<type>::GetCurrentValue( float time ) const {
255 SetPhase( time );
256 return extrapolate.GetCurrentValue( time );
257 }
258
259 /*
260 ====================
261 idInterpolateAccelDecelLinear::GetCurrentSpeed
262 ====================
263 */
264 template< class type >
GetCurrentSpeed(float time)265 ID_INLINE type idInterpolateAccelDecelLinear<type>::GetCurrentSpeed( float time ) const {
266 SetPhase( time );
267 return extrapolate.GetCurrentSpeed( time );
268 }
269
270
271 /*
272 ==============================================================================================
273
274 Continuous interpolation with sinusoidal acceleration and deceleration phase.
275 Both the velocity and acceleration are continuous.
276
277 ==============================================================================================
278 */
279
280 template< class type >
281 class idInterpolateAccelDecelSine {
282 public:
283 idInterpolateAccelDecelSine();
284
285 void Init( const float startTime, const float accelTime, const float decelTime, const float duration, const type &startValue, const type &endValue );
SetStartTime(float time)286 void SetStartTime( float time ) { startTime = time; Invalidate(); }
SetStartValue(const type & startValue)287 void SetStartValue( const type &startValue ) { this->startValue = startValue; Invalidate(); }
SetEndValue(const type & endValue)288 void SetEndValue( const type &endValue ) { this->endValue = endValue; Invalidate(); }
289
290 type GetCurrentValue( float time ) const;
291 type GetCurrentSpeed( float time ) const;
IsDone(float time)292 bool IsDone( float time ) const { return ( time >= startTime + accelTime + linearTime + decelTime ); }
293
GetStartTime(void)294 float GetStartTime( void ) const { return startTime; }
GetEndTime(void)295 float GetEndTime( void ) const { return startTime + accelTime + linearTime + decelTime; }
GetDuration(void)296 float GetDuration( void ) const { return accelTime + linearTime + decelTime; }
GetAcceleration(void)297 float GetAcceleration( void ) const { return accelTime; }
GetDeceleration(void)298 float GetDeceleration( void ) const { return decelTime; }
GetStartValue(void)299 const type & GetStartValue( void ) const { return startValue; }
GetEndValue(void)300 const type & GetEndValue( void ) const { return endValue; }
301
302 private:
303 float startTime;
304 float accelTime;
305 float linearTime;
306 float decelTime;
307 type startValue;
308 type endValue;
309 mutable idExtrapolate<type> extrapolate;
310
311 void Invalidate( void );
312 void SetPhase( float time ) const;
313 };
314
315 /*
316 ====================
317 idInterpolateAccelDecelSine::idInterpolateAccelDecelSine
318 ====================
319 */
320 template< class type >
idInterpolateAccelDecelSine()321 ID_INLINE idInterpolateAccelDecelSine<type>::idInterpolateAccelDecelSine() {
322 startTime = accelTime = linearTime = decelTime = 0;
323 memset( &startValue, 0, sizeof( startValue ) );
324 endValue = startValue;
325 }
326
327 /*
328 ====================
329 idInterpolateAccelDecelSine::Init
330 ====================
331 */
332 template< class type >
Init(const float startTime,const float accelTime,const float decelTime,const float duration,const type & startValue,const type & endValue)333 ID_INLINE void idInterpolateAccelDecelSine<type>::Init( const float startTime, const float accelTime, const float decelTime, const float duration, const type &startValue, const type &endValue ) {
334 type speed;
335
336 this->startTime = startTime;
337 this->accelTime = accelTime;
338 this->decelTime = decelTime;
339 this->startValue = startValue;
340 this->endValue = endValue;
341
342 if ( duration <= 0.0f ) {
343 return;
344 }
345
346 if ( this->accelTime + this->decelTime > duration ) {
347 this->accelTime = this->accelTime * duration / ( this->accelTime + this->decelTime );
348 this->decelTime = duration - this->accelTime;
349 }
350 this->linearTime = duration - this->accelTime - this->decelTime;
351 speed = ( endValue - startValue ) * ( 1000.0f / ( (float) this->linearTime + ( this->accelTime + this->decelTime ) * idMath::SQRT_1OVER2 ) );
352
353 if ( this->accelTime ) {
354 extrapolate.Init( startTime, this->accelTime, startValue, ( startValue - startValue ), speed, EXTRAPOLATION_ACCELSINE );
355 } else if ( this->linearTime ) {
356 extrapolate.Init( startTime, this->linearTime, startValue, ( startValue - startValue ), speed, EXTRAPOLATION_LINEAR );
357 } else {
358 extrapolate.Init( startTime, this->decelTime, startValue, ( startValue - startValue ), speed, EXTRAPOLATION_DECELSINE );
359 }
360 }
361
362 /*
363 ====================
364 idInterpolateAccelDecelSine::Invalidate
365 ====================
366 */
367 template< class type >
Invalidate(void)368 ID_INLINE void idInterpolateAccelDecelSine<type>::Invalidate( void ) {
369 extrapolate.Init( 0, 0, extrapolate.GetStartValue(), extrapolate.GetBaseSpeed(), extrapolate.GetSpeed(), EXTRAPOLATION_NONE );
370 }
371
372 /*
373 ====================
374 idInterpolateAccelDecelSine::SetPhase
375 ====================
376 */
377 template< class type >
SetPhase(float time)378 ID_INLINE void idInterpolateAccelDecelSine<type>::SetPhase( float time ) const {
379 float deltaTime;
380
381 deltaTime = time - startTime;
382 if ( deltaTime < accelTime ) {
383 if ( extrapolate.GetExtrapolationType() != EXTRAPOLATION_ACCELSINE ) {
384 extrapolate.Init( startTime, accelTime, startValue, extrapolate.GetBaseSpeed(), extrapolate.GetSpeed(), EXTRAPOLATION_ACCELSINE );
385 }
386 } else if ( deltaTime < accelTime + linearTime ) {
387 if ( extrapolate.GetExtrapolationType() != EXTRAPOLATION_LINEAR ) {
388 extrapolate.Init( startTime + accelTime, linearTime, startValue + extrapolate.GetSpeed() * ( accelTime * 0.001f * idMath::SQRT_1OVER2 ), extrapolate.GetBaseSpeed(), extrapolate.GetSpeed(), EXTRAPOLATION_LINEAR );
389 }
390 } else {
391 if ( extrapolate.GetExtrapolationType() != EXTRAPOLATION_DECELSINE ) {
392 extrapolate.Init( startTime + accelTime + linearTime, decelTime, endValue - ( extrapolate.GetSpeed() * ( decelTime * 0.001f * idMath::SQRT_1OVER2 ) ), extrapolate.GetBaseSpeed(), extrapolate.GetSpeed(), EXTRAPOLATION_DECELSINE );
393 }
394 }
395 }
396
397 /*
398 ====================
399 idInterpolateAccelDecelSine::GetCurrentValue
400 ====================
401 */
402 template< class type >
GetCurrentValue(float time)403 ID_INLINE type idInterpolateAccelDecelSine<type>::GetCurrentValue( float time ) const {
404 SetPhase( time );
405 return extrapolate.GetCurrentValue( time );
406 }
407
408 /*
409 ====================
410 idInterpolateAccelDecelSine::GetCurrentSpeed
411 ====================
412 */
413 template< class type >
GetCurrentSpeed(float time)414 ID_INLINE type idInterpolateAccelDecelSine<type>::GetCurrentSpeed( float time ) const {
415 SetPhase( time );
416 return extrapolate.GetCurrentSpeed( time );
417 }
418
419 #endif /* !__MATH_INTERPOLATE_H__ */
420