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( &currentValue, 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