2 ======================================================================
\r
5 Envelope functions for an LWO2 reader.
\r
7 Ernie Wright 16 Nov 00
\r
8 ====================================================================== */
\r
10 #include "../picointernal.h"
\r
14 ======================================================================
\r
17 Free the memory used by an lwEnvelope.
\r
18 ====================================================================== */
\r
20 void lwFreeEnvelope( lwEnvelope *env )
\r
23 if ( env->name ) _pico_free( env->name );
\r
24 lwListFree( env->key, _pico_free );
\r
25 lwListFree( env->cfilter, lwFreePlugin );
\r
31 static int compare_keys( lwKey *k1, lwKey *k2 )
\r
33 return k1->time > k2->time ? 1 : k1->time < k2->time ? -1 : 0;
\r
38 ======================================================================
\r
41 Read an ENVL chunk from an LWO2 file.
\r
42 ====================================================================== */
\r
44 lwEnvelope *lwGetEnvelope( picoMemStream_t *fp, int cksize )
\r
52 int i, nparams, pos, rlen;
\r
55 /* allocate the Envelope structure */
\r
57 env = _pico_calloc( 1, sizeof( lwEnvelope ));
\r
58 if ( !env ) goto Fail;
\r
60 /* remember where we started */
\r
63 pos = _pico_memstream_tell( fp );
\r
67 env->index = getVX( fp );
\r
69 /* first subchunk header */
\r
73 if ( 0 > get_flen() ) goto Fail;
\r
75 /* process subchunks as they're encountered */
\r
83 env->type = getU2( fp );
\r
87 env->name = getS0( fp );
\r
91 env->behavior[ 0 ] = getU2( fp );
\r
95 env->behavior[ 1 ] = getU2( fp );
\r
99 key = _pico_calloc( 1, sizeof( lwKey ));
\r
100 if ( !key ) goto Fail;
\r
101 key->time = getF4( fp );
\r
102 key->value = getF4( fp );
\r
103 lwListInsert( &env->key, key, compare_keys );
\r
108 if ( !key ) goto Fail;
\r
109 key->shape = getU4( fp );
\r
111 nparams = ( sz - 4 ) / 4;
\r
112 if ( nparams > 4 ) nparams = 4;
\r
113 for ( i = 0; i < nparams; i++ )
\r
114 f[ i ] = getF4( fp );
\r
116 switch ( key->shape ) {
\r
118 key->tension = f[ 0 ];
\r
119 key->continuity = f[ 1 ];
\r
120 key->bias = f[ 2 ];
\r
126 for ( i = 0; i < nparams; i++ )
\r
127 key->param[ i ] = f[ i ];
\r
133 plug = _pico_calloc( 1, sizeof( lwPlugin ));
\r
134 if ( !plug ) goto Fail;
\r
136 plug->name = getS0( fp );
\r
137 plug->flags = getU2( fp );
\r
138 plug->data = getbytes( fp, sz - get_flen() );
\r
140 lwListAdd( &env->cfilter, plug );
\r
148 /* error while reading current subchunk? */
\r
151 if ( rlen < 0 || rlen > sz ) goto Fail;
\r
153 /* skip unread parts of the current subchunk */
\r
156 _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
\r
158 /* end of the ENVL chunk? */
\r
160 rlen = _pico_memstream_tell( fp ) - pos;
\r
161 if ( cksize < rlen ) goto Fail;
\r
162 if ( cksize == rlen ) break;
\r
164 /* get the next subchunk header */
\r
169 if ( 6 != get_flen() ) goto Fail;
\r
175 lwFreeEnvelope( env );
\r
181 ======================================================================
\r
184 Returns an lwEnvelope pointer, given an envelope index.
\r
185 ====================================================================== */
\r
187 lwEnvelope *lwFindEnvelope( lwEnvelope *list, int index )
\r
193 if ( env->index == index ) break;
\r
201 ======================================================================
\r
204 Given the value v of a periodic function, returns the equivalent value
\r
205 v2 in the principal interval [lo, hi]. If i isn't NULL, it receives
\r
206 the number of wavelengths between v and v2.
\r
208 v2 = v - i * (hi - lo)
\r
210 For example, range( 3 pi, 0, 2 pi, i ) returns pi, with i = 1.
\r
211 ====================================================================== */
\r
213 static float range( float v, float lo, float hi, int *i )
\r
215 float v2, r = hi - lo;
\r
222 v2 = lo + v - r * ( float ) floor(( double ) v / r );
\r
223 if ( i ) *i = -( int )(( v2 - v ) / r + ( v2 > v ? 0.5 : -0.5 ));
\r
230 ======================================================================
\r
233 Calculate the Hermite coefficients.
\r
234 ====================================================================== */
\r
236 static void hermite( float t, float *h1, float *h2, float *h3, float *h4 )
\r
243 *h2 = 3.0f * t2 - t3 - t3;
\r
246 *h3 = *h4 - t2 + t;
\r
251 ======================================================================
\r
254 Interpolate the value of a 1D Bezier curve.
\r
255 ====================================================================== */
\r
257 static float bezier( float x0, float x1, float x2, float x3, float t )
\r
259 float a, b, c, t2, t3;
\r
264 c = 3.0f * ( x1 - x0 );
\r
265 b = 3.0f * ( x2 - x1 ) - c;
\r
266 a = x3 - x0 - c - b;
\r
268 return a * t3 + b * t2 + c * t + x0;
\r
273 ======================================================================
\r
276 Find the t for which bezier() returns the input time. The handle
\r
277 endpoints of a BEZ2 curve represent the control points, and these have
\r
278 (time, value) coordinates, so time is used as both a coordinate and a
\r
279 parameter for this curve type.
\r
280 ====================================================================== */
\r
282 static float bez2_time( float x0, float x1, float x2, float x3, float time,
\r
283 float *t0, float *t1 )
\r
287 t = *t0 + ( *t1 - *t0 ) * 0.5f;
\r
288 v = bezier( x0, x1, x2, x3, t );
\r
289 if ( fabs( time - v ) > .0001f ) {
\r
294 return bez2_time( x0, x1, x2, x3, time, t0, t1 );
\r
302 ======================================================================
\r
305 Interpolate the value of a BEZ2 curve.
\r
306 ====================================================================== */
\r
308 static float bez2( lwKey *key0, lwKey *key1, float time )
\r
310 float x, y, t, t0 = 0.0f, t1 = 1.0f;
\r
312 if ( key0->shape == ID_BEZ2 )
\r
313 x = key0->time + key0->param[ 2 ];
\r
315 x = key0->time + ( key1->time - key0->time ) / 3.0f;
\r
317 t = bez2_time( key0->time, x, key1->time + key1->param[ 0 ], key1->time,
\r
320 if ( key0->shape == ID_BEZ2 )
\r
321 y = key0->value + key0->param[ 3 ];
\r
323 y = key0->value + key0->param[ 1 ] / 3.0f;
\r
325 return bezier( key0->value, y, key1->param[ 1 ] + key1->value, key1->value, t );
\r
330 ======================================================================
\r
333 Return the outgoing tangent to the curve at key0. The value returned
\r
334 for the BEZ2 case is used when extrapolating a linear pre behavior and
\r
335 when interpolating a non-BEZ2 span.
\r
336 ====================================================================== */
\r
338 static float outgoing( lwKey *key0, lwKey *key1 )
\r
340 float a, b, d, t, out;
\r
342 switch ( key0->shape )
\r
345 a = ( 1.0f - key0->tension )
\r
346 * ( 1.0f + key0->continuity )
\r
347 * ( 1.0f + key0->bias );
\r
348 b = ( 1.0f - key0->tension )
\r
349 * ( 1.0f - key0->continuity )
\r
350 * ( 1.0f - key0->bias );
\r
351 d = key1->value - key0->value;
\r
353 if ( key0->prev ) {
\r
354 t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
\r
355 out = t * ( a * ( key0->value - key0->prev->value ) + b * d );
\r
362 d = key1->value - key0->value;
\r
363 if ( key0->prev ) {
\r
364 t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
\r
365 out = t * ( key0->value - key0->prev->value + d );
\r
373 out = key0->param[ 1 ];
\r
375 out *= ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
\r
379 out = key0->param[ 3 ] * ( key1->time - key0->time );
\r
380 if ( fabs( key0->param[ 2 ] ) > 1e-5f )
\r
381 out /= key0->param[ 2 ];
\r
397 ======================================================================
\r
400 Return the incoming tangent to the curve at key1. The value returned
\r
401 for the BEZ2 case is used when extrapolating a linear post behavior.
\r
402 ====================================================================== */
\r
404 static float incoming( lwKey *key0, lwKey *key1 )
\r
406 float a, b, d, t, in;
\r
408 switch ( key1->shape )
\r
411 d = key1->value - key0->value;
\r
412 if ( key1->next ) {
\r
413 t = ( key1->time - key0->time ) / ( key1->next->time - key0->time );
\r
414 in = t * ( key1->next->value - key1->value + d );
\r
421 a = ( 1.0f - key1->tension )
\r
422 * ( 1.0f - key1->continuity )
\r
423 * ( 1.0f + key1->bias );
\r
424 b = ( 1.0f - key1->tension )
\r
425 * ( 1.0f + key1->continuity )
\r
426 * ( 1.0f - key1->bias );
\r
427 d = key1->value - key0->value;
\r
429 if ( key1->next ) {
\r
430 t = ( key1->time - key0->time ) / ( key1->next->time - key0->time );
\r
431 in = t * ( b * ( key1->next->value - key1->value ) + a * d );
\r
439 in = key1->param[ 0 ];
\r
441 in *= ( key1->time - key0->time ) / ( key1->next->time - key0->time );
\r
446 in = key1->param[ 1 ] * ( key1->time - key0->time );
\r
447 if ( fabs( key1->param[ 0 ] ) > 1e-5f )
\r
448 in /= key1->param[ 0 ];
\r
464 ======================================================================
\r
467 Given a list of keys and a time, returns the interpolated value of the
\r
468 envelope at that time.
\r
469 ====================================================================== */
\r
471 float evalEnvelope( lwEnvelope *env, float time )
\r
473 lwKey *key0, *key1, *skey, *ekey;
\r
474 float t, h1, h2, h3, h4, in, out, offset = 0.0f;
\r
478 /* if there's no key, the value is 0 */
\r
480 if ( env->nkeys == 0 ) return 0.0f;
\r
482 /* if there's only one key, the value is constant */
\r
484 if ( env->nkeys == 1 )
\r
485 return env->key->value;
\r
487 /* find the first and last keys */
\r
489 skey = ekey = env->key;
\r
490 while ( ekey->next ) ekey = ekey->next;
\r
492 /* use pre-behavior if time is before first key time */
\r
494 if ( time < skey->time ) {
\r
495 switch ( env->behavior[ 0 ] )
\r
501 return skey->value;
\r
504 time = range( time, skey->time, ekey->time, NULL );
\r
507 case BEH_OSCILLATE:
\r
508 time = range( time, skey->time, ekey->time, &noff );
\r
510 time = ekey->time - skey->time - time;
\r
514 time = range( time, skey->time, ekey->time, &noff );
\r
515 offset = noff * ( ekey->value - skey->value );
\r
519 out = outgoing( skey, skey->next )
\r
520 / ( skey->next->time - skey->time );
\r
521 return out * ( time - skey->time ) + skey->value;
\r
525 /* use post-behavior if time is after last key time */
\r
527 else if ( time > ekey->time ) {
\r
528 switch ( env->behavior[ 1 ] )
\r
534 return ekey->value;
\r
537 time = range( time, skey->time, ekey->time, NULL );
\r
540 case BEH_OSCILLATE:
\r
541 time = range( time, skey->time, ekey->time, &noff );
\r
543 time = ekey->time - skey->time - time;
\r
547 time = range( time, skey->time, ekey->time, &noff );
\r
548 offset = noff * ( ekey->value - skey->value );
\r
552 in = incoming( ekey->prev, ekey )
\r
553 / ( ekey->time - ekey->prev->time );
\r
554 return in * ( time - ekey->time ) + ekey->value;
\r
558 /* get the endpoints of the interval being evaluated */
\r
561 while ( time > key0->next->time )
\r
565 /* check for singularities first */
\r
567 if ( time == key0->time )
\r
568 return key0->value + offset;
\r
569 else if ( time == key1->time )
\r
570 return key1->value + offset;
\r
572 /* get interval length, time in [0, 1] */
\r
574 t = ( time - key0->time ) / ( key1->time - key0->time );
\r
578 switch ( key1->shape )
\r
583 out = outgoing( key0, key1 );
\r
584 in = incoming( key0, key1 );
\r
585 hermite( t, &h1, &h2, &h3, &h4 );
\r
586 return h1 * key0->value + h2 * key1->value + h3 * out + h4 * in + offset;
\r
589 return bez2( key0, key1, time ) + offset;
\r
592 return key0->value + t * ( key1->value - key0->value ) + offset;
\r
595 return key0->value + offset;
\r