1 #include "lwEnvelope.h"
2 
addKey(float time,float value)3 lwKey *lwEnvelope::addKey( float time, float value )
4 {
5 	lwKey *key = new lwKey(time, value);
6 	keys.insert(lower_bound(keys.begin(), keys.end(), key), key);
7 	return key;
8 }
9 
10 /*======================================================================
11 range()
12 
13 Given the value v of a periodic function, returns the equivalent value
14 v2 in the principal interval [lo, hi].  If i isn't NULL, it receives
15 the number of wavelengths between v and v2.
16 
17 v2 = v - i * (hi - lo)
18 
19 For example, range( 3 pi, 0, 2 pi, i ) returns pi, with i = 1.
20 ====================================================================== */
21 
range(float v,float lo,float hi,int * i)22 float lwEnvelope::range( float v, float lo, float hi, int *i )
23 {
24 	float v2, r = hi - lo;
25 
26 	if ( r == 0.0 ) {
27 		if ( i ) *i = 0;
28 		return lo;
29 	}
30 
31 	v2 = lo + v - r * ( float ) floor(( double ) v / r );
32 	if ( i ) *i = -( int )(( v2 - v ) / r + ( v2 > v ? 0.5 : -0.5 ));
33 
34 	return v2;
35 }
36 
37 /*======================================================================
38 hermite()
39 
40 Calculate the Hermite coefficients.
41 ====================================================================== */
42 
hermite(float t,float * h1,float * h2,float * h3,float * h4)43 void lwEnvelope::hermite( float t, float *h1, float *h2, float *h3, float *h4 )
44 {
45 	float t2, t3;
46 
47 	t2 = t * t;
48 	t3 = t * t2;
49 
50 	*h2 = 3.0f * t2 - t3 - t3;
51 	*h1 = 1.0f - *h2;
52 	*h4 = t3 - t2;
53 	*h3 = *h4 - t2 + t;
54 }
55 
56 /*======================================================================
57 bezier()
58 
59 Interpolate the value of a 1D Bezier curve.
60 ====================================================================== */
61 
bezier(float x0,float x1,float x2,float x3,float t)62 float lwEnvelope::bezier( float x0, float x1, float x2, float x3, float t )
63 {
64 	float a, b, c, t2, t3;
65 
66 	t2 = t * t;
67 	t3 = t2 * t;
68 
69 	c = 3.0f * ( x1 - x0 );
70 	b = 3.0f * ( x2 - x1 ) - c;
71 	a = x3 - x0 - c - b;
72 
73 	return a * t3 + b * t2 + c * t + x0;
74 }
75 
76 
77 /*======================================================================
78 bez2_time()
79 
80 Find the t for which bezier() returns the input time.  The handle
81 endpoints of a BEZ2 curve represent the control points, and these have
82 (time, value) coordinates, so time is used as both a coordinate and a
83 parameter for this curve type.
84 ====================================================================== */
85 
bez2_time(float x0,float x1,float x2,float x3,float time,float * t0,float * t1)86 float lwEnvelope::bez2_time( float x0, float x1, float x2, float x3, float time,	float *t0, float *t1 )
87 {
88 	float v, t;
89 
90 	t = *t0 + ( *t1 - *t0 ) * 0.5f;
91 	v = bezier( x0, x1, x2, x3, t );
92 	if ( fabs( time - v ) > .0001f ) {
93 		if ( v > time )
94 			*t1 = t;
95 		else
96 			*t0 = t;
97 		return bez2_time( x0, x1, x2, x3, time, t0, t1 );
98 	}
99 	else
100 		return t;
101 }
102 
103 
104   /*
105   ======================================================================
106   bez2()
107 
108 	Interpolate the value of a BEZ2 curve.
109   ====================================================================== */
110 
bez2(lwKey * key0,lwKey * key1,float time)111 float lwEnvelope::bez2( lwKey *key0, lwKey *key1, float time )
112 {
113 	float x, y, t, t0 = 0.0f, t1 = 1.0f;
114 
115 	if ( key0->shape == ID_BEZ2 )
116 		x = key0->time + key0->param[ 2 ];
117 	else
118 		x = key0->time + ( key1->time - key0->time ) / 3.0f;
119 
120 	t = bez2_time( key0->time, x, key1->time + key1->param[ 0 ], key1->time,
121 		time, &t0, &t1 );
122 
123 	if ( key0->shape == ID_BEZ2 )
124 		y = key0->value + key0->param[ 3 ];
125 	else
126 		y = key0->value + key0->param[ 1 ] / 3.0f;
127 
128 	return bezier( key0->value, y, key1->param[ 1 ] + key1->value, key1->value, t );
129 }
130 
131 
132   /*
133   ======================================================================
134   outgoing()
135 
136 	Return the outgoing tangent to the curve at key0.  The value returned
137 	for the BEZ2 case is used when extrapolating a linear pre behavior and
138 	when interpolating a non-BEZ2 span.
139   ====================================================================== */
140 
outgoing(unsigned int key0,unsigned int key1)141 float lwEnvelope::outgoing( unsigned int key0, unsigned int key1 )
142 {
143 	float a, b, d, t, tout;
144 
145 	switch ( keys[key0]->shape )
146 	{
147 	case ID_TCB:
148 		a = ( 1.0f - keys[key0]->tension )
149 			* ( 1.0f + keys[key0]->continuity )
150 			* ( 1.0f + keys[key0]->bias );
151 		b = ( 1.0f - keys[key0]->tension )
152 			* ( 1.0f - keys[key0]->continuity )
153 			* ( 1.0f - keys[key0]->bias );
154 		d = keys[key1]->value - keys[key0]->value;
155 
156 
157 		if ( key0 > 0 )
158 		{
159 			t = ( keys[key1]->time - keys[key0]->time ) / ( keys[key1]->time - keys[ key0-1 ]->time );
160 			tout = t * ( a * ( keys[key0]->value - keys[ key0-1 ]->value ) + b * d );
161 		}
162 		else
163 			tout = b * d;
164 		break;
165 
166 	case ID_LINE:
167 		d = keys[key1]->value - keys[key0]->value;
168 		if ( key0 > 0 )
169 		{
170 			t = ( keys[key1]->time - keys[key0]->time ) / ( keys[key1]->time - keys[ key0-1 ]->time );
171 			tout = t * ( keys[key0]->value - keys[ key0-1 ]->value + d );
172 		}
173 		else
174 			tout = d;
175 		break;
176 
177 	case ID_BEZI:
178 	case ID_HERM:
179 		tout = keys[key0]->param[ 1 ];
180 
181 		if ( key0 > 0 )
182 			tout *= ( keys[key1]->time - keys[key0]->time ) / ( keys[key1]->time - keys[ key0-1 ]->time );
183 
184 		break;
185 
186 	case ID_BEZ2:
187 		tout = keys[key0]->param[ 3 ] * ( keys[key1]->time - keys[key0]->time );
188 		if ( fabs( keys[key0]->param[ 2 ] ) > 1e-5f )
189 			tout /= keys[key0]->param[ 2 ];
190 		else
191 			tout *= 1e5f;
192 		break;
193 
194 	case ID_STEP:
195 	default:
196 		tout = 0.0f;
197 		break;
198 	}
199 
200 	return tout;
201 }
202 
203 
204 /*======================================================================
205 incoming()
206 
207 Return the incoming tangent to the curve at key1.  The value returned
208 for the BEZ2 case is used when extrapolating a linear post behavior.
209 ====================================================================== */
210 
incoming(unsigned int key0,unsigned int key1)211 float lwEnvelope::incoming( unsigned int key0, unsigned int key1 )
212 {
213 	float a, b, d, t, tin;
214 
215 	switch ( keys[key1]->shape )
216 	{
217 	case ID_LINE:
218 		d = keys[key1]->value - keys[key0]->value;
219 
220 		if ( key1 < keys.size()-1 )
221 		{
222 			t = ( keys[key1]->time - keys[key0]->time ) / ( keys[ key1+1 ]->time - keys[key0]->time );
223 			tin = t * ( keys[ key1+1 ]->value - keys[key1]->value + d );
224 		}
225 		else
226 			tin = d;
227 
228 		break;
229 
230 	case ID_TCB:
231 		a = ( 1.0f - keys[key1]->tension )
232 			* ( 1.0f - keys[key1]->continuity )
233 			* ( 1.0f + keys[key1]->bias );
234 		b = ( 1.0f - keys[key1]->tension )
235 			* ( 1.0f + keys[key1]->continuity )
236 			* ( 1.0f - keys[key1]->bias );
237 		d = keys[key1]->value - keys[key0]->value;
238 		if ( key1 < keys.size()-1 ) {
239 			t = ( keys[key1]->time - keys[key0]->time ) / ( keys[ key1+1 ]->time - keys[key0]->time );
240 			tin = t * ( b * ( keys[ key1+1 ]->value - keys[key1]->value ) + a * d );
241 		}
242 		else
243 			tin = a * d;
244 		break;
245 
246 	case ID_BEZI:
247 	case ID_HERM:
248 		tin = keys[key1]->param[ 0 ];
249 		if ( key1 < keys.size()-1 )
250 			tin *= ( keys[key1]->time - keys[key0]->time ) / ( keys[ key1+1 ]->time - keys[key0]->time );
251 		break;
252 		return tin;
253 
254 	case ID_BEZ2:
255 		tin = keys[key1]->param[ 1 ] * ( keys[key1]->time - keys[key0]->time );
256 		if ( fabs( keys[key1]->param[ 0 ] ) > 1e-5f )
257 			tin /= keys[key1]->param[ 0 ];
258 		else
259 			tin *= 1e5f;
260 		break;
261 
262 	case ID_STEP:
263 	default:
264 		tin = 0.0f;
265 		break;
266 	}
267 
268 	return tin;
269 }
270 
271 /*======================================================================
272 evalEnvelope()
273 
274 Given a list of keys and a time, returns the interpolated value of the
275 envelope at that time.
276 ====================================================================== */
277 
evaluate(float time)278 float lwEnvelope::evaluate( float time )
279 {
280 	lwKey *key0, *key1, *skey, *ekey;
281 	float t, h1, h2, h3, h4, tin, tout, offset = 0.0f;
282 	int noff;
283 	int key0index, key1index;
284 
285 
286 	/* if there's no key, the value is 0 */
287 
288 	if ( keys.size() == 0 ) return 0.0f;
289 
290 	/* if there's only one key, the value is constant */
291 
292 	if ( keys.size() == 1 )	return keys[0]->value;
293 
294 	/* find the first and last keys */
295 
296 	key0index = 0;
297 	key1index = keys.size()-1;
298 	skey = keys[key0index];
299 	ekey = keys[key1index];
300 
301 	/* use pre-behavior if time is before first key time */
302 
303 	if ( time < skey->time )
304 	{
305 		switch ( behavior[ 0 ] )
306 		{
307 		case BEH_RESET:
308 			return 0.0f;
309 
310 		case BEH_CONSTANT:
311 			return skey->value;
312 
313 		case BEH_REPEAT:
314 			time = range( time, skey->time, ekey->time, NULL );
315 			break;
316 
317 		case BEH_OSCILLATE:
318 			time = range( time, skey->time, ekey->time, &noff );
319 			if ( noff % 2 )
320 				time = ekey->time - skey->time - time;
321 			break;
322 
323 		case BEH_OFFSET:
324 			time = range( time, skey->time, ekey->time, &noff );
325 			offset = noff * ( ekey->value - skey->value );
326 			break;
327 
328 		case BEH_LINEAR:
329 			tout = outgoing( key0index, key0index+1 ) / ( keys[key0index+1]->time - keys[key0index]->time );
330 
331 			return tout * ( time - skey->time ) + skey->value;
332 		}
333 	}
334 
335 	/* use post-behavior if time is after last key time */
336 
337 	else if ( time > ekey->time ) {
338 		switch ( behavior[ 1 ] )
339 		{
340 		case BEH_RESET:
341 			return 0.0f;
342 
343 		case BEH_CONSTANT:
344 			return ekey->value;
345 
346 		case BEH_REPEAT:
347 			time = range( time, skey->time, ekey->time, NULL );
348 			break;
349 
350 		case BEH_OSCILLATE:
351 			time = range( time, skey->time, ekey->time, &noff );
352 			if ( noff % 2 )
353 				time = ekey->time - skey->time - time;
354 			break;
355 
356 		case BEH_OFFSET:
357 			time = range( time, skey->time, ekey->time, &noff );
358 			offset = noff * ( ekey->value - skey->value );
359 			break;
360 
361 		case BEH_LINEAR:
362 			tin = incoming( key1index-1, key1index ) / ( ekey->time - keys[key1index-1]->time );
363 			return tin * ( time - ekey->time ) + ekey->value;
364 		}
365 	}
366 
367 	/* get the endpoints of the interval being evaluated */
368 
369 	key0index = keys.size()-2;
370 	key1index = keys.size()-1;
371 	key0 = keys[key0index];
372 	key1 = keys[key1index];
373 
374 	/* check for singularities first */
375 
376 	if ( time == key0->time )
377 		return key0->value + offset;
378 	else if ( time == key1->time )
379 		return key1->value + offset;
380 
381 	/* get interval length, time in [0, 1] */
382 
383 	t = ( time - key0->time ) / ( key1->time - key0->time );
384 
385 	/* interpolate */
386 
387 	switch ( key1->shape )
388 	{
389 	case ID_TCB:
390 	case ID_BEZI:
391 	case ID_HERM:
392 		tout = outgoing( key0index, key1index );
393 		tin = incoming( key0index, key1index );
394 		hermite( t, &h1, &h2, &h3, &h4 );
395 		return h1 * key0->value + h2 * key1->value + h3 * tout + h4 * tin + offset;
396 
397 	case ID_BEZ2:
398 		return bez2( key0, key1, time ) + offset;
399 
400 	case ID_LINE:
401 		return key0->value + t * ( key1->value - key0->value ) + offset;
402 
403 	case ID_STEP:
404 		return key0->value + offset;
405 
406 	default:
407 		return offset;
408 	}
409 }
410