]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/picomodel/lwo/envelope.c
eol style
[xonotic/netradiant.git] / libs / picomodel / lwo / envelope.c
1 /*
2 ======================================================================
3 envelope.c
4
5 Envelope functions for an LWO2 reader.
6
7 Ernie Wright  16 Nov 00
8 ====================================================================== */
9
10 #include "../picointernal.h"
11 #include "lwo2.h"
12
13 /*
14 ======================================================================
15 lwFreeEnvelope()
16
17 Free the memory used by an lwEnvelope.
18 ====================================================================== */
19
20 void lwFreeEnvelope( lwEnvelope *env )
21 {
22    if ( env ) {
23       if ( env->name ) _pico_free( env->name );
24       lwListFree( env->key, _pico_free );
25       lwListFree( env->cfilter, lwFreePlugin );
26       _pico_free( env );
27    }
28 }
29
30
31 static int compare_keys( lwKey *k1, lwKey *k2 )
32 {
33    return k1->time > k2->time ? 1 : k1->time < k2->time ? -1 : 0;
34 }
35
36
37 /*
38 ======================================================================
39 lwGetEnvelope()
40
41 Read an ENVL chunk from an LWO2 file.
42 ====================================================================== */
43
44 lwEnvelope *lwGetEnvelope( picoMemStream_t *fp, int cksize )
45 {
46    lwEnvelope *env;
47    lwKey *key;
48    lwPlugin *plug;
49    unsigned int id;
50    unsigned short sz;
51    float f[ 4 ];
52    int i, nparams, pos, rlen;
53
54
55    /* allocate the Envelope structure */
56
57    env = _pico_calloc( 1, sizeof( lwEnvelope ));
58    if ( !env ) goto Fail;
59
60    /* remember where we started */
61
62    set_flen( 0 );
63    pos = _pico_memstream_tell( fp );
64
65    /* index */
66
67    env->index = getVX( fp );
68
69    /* first subchunk header */
70
71    id = getU4( fp );
72    sz = getU2( fp );
73    if ( 0 > get_flen() ) goto Fail;
74
75    /* process subchunks as they're encountered */
76
77    while ( 1 ) {
78       sz += sz & 1;
79       set_flen( 0 );
80
81       switch ( id ) {
82          case ID_TYPE:
83             env->type = getU2( fp );
84             break;
85
86          case ID_NAME:
87             env->name = getS0( fp );
88             break;
89
90          case ID_PRE:
91             env->behavior[ 0 ] = getU2( fp );
92             break;
93
94          case ID_POST:
95             env->behavior[ 1 ] = getU2( fp );
96             break;
97
98          case ID_KEY:
99             key = _pico_calloc( 1, sizeof( lwKey ));
100             if ( !key ) goto Fail;
101             key->time = getF4( fp );
102             key->value = getF4( fp );
103             lwListInsert( &env->key, key, compare_keys );
104             env->nkeys++;
105             break;
106
107          case ID_SPAN:
108             if ( !key ) goto Fail;
109             key->shape = getU4( fp );
110
111             nparams = ( sz - 4 ) / 4;
112             if ( nparams > 4 ) nparams = 4;
113             for ( i = 0; i < nparams; i++ )
114                f[ i ] = getF4( fp );
115
116             switch ( key->shape ) {
117                case ID_TCB:
118                   key->tension = f[ 0 ];
119                   key->continuity = f[ 1 ];
120                   key->bias = f[ 2 ];
121                   break;
122
123                case ID_BEZI:
124                case ID_HERM:
125                case ID_BEZ2:
126                   for ( i = 0; i < nparams; i++ )
127                      key->param[ i ] = f[ i ];
128                   break;
129             }
130             break;
131
132          case ID_CHAN:
133             plug = _pico_calloc( 1, sizeof( lwPlugin ));
134             if ( !plug ) goto Fail;
135
136             plug->name = getS0( fp );
137             plug->flags = getU2( fp );
138             plug->data = getbytes( fp, sz - get_flen() );
139
140             lwListAdd( &env->cfilter, plug );
141             env->ncfilters++;
142             break;
143
144          default:
145             break;
146       }
147
148       /* error while reading current subchunk? */
149
150       rlen = get_flen();
151       if ( rlen < 0 || rlen > sz ) goto Fail;
152
153       /* skip unread parts of the current subchunk */
154
155       if ( rlen < sz )
156          _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR );
157
158       /* end of the ENVL chunk? */
159
160       rlen = _pico_memstream_tell( fp ) - pos;
161       if ( cksize < rlen ) goto Fail;
162       if ( cksize == rlen ) break;
163
164       /* get the next subchunk header */
165
166       set_flen( 0 );
167       id = getU4( fp );
168       sz = getU2( fp );
169       if ( 6 != get_flen() ) goto Fail;
170    }
171
172    return env;
173
174 Fail:
175    lwFreeEnvelope( env );
176    return NULL;
177 }
178
179
180 /*
181 ======================================================================
182 lwFindEnvelope()
183
184 Returns an lwEnvelope pointer, given an envelope index.
185 ====================================================================== */
186
187 lwEnvelope *lwFindEnvelope( lwEnvelope *list, int index )
188 {
189    lwEnvelope *env;
190
191    env = list;
192    while ( env ) {
193       if ( env->index == index ) break;
194       env = env->next;
195    }
196    return env;
197 }
198
199
200 /*
201 ======================================================================
202 range()
203
204 Given the value v of a periodic function, returns the equivalent value
205 v2 in the principal interval [lo, hi].  If i isn't NULL, it receives
206 the number of wavelengths between v and v2.
207
208    v2 = v - i * (hi - lo)
209
210 For example, range( 3 pi, 0, 2 pi, i ) returns pi, with i = 1.
211 ====================================================================== */
212
213 static float range( float v, float lo, float hi, int *i )
214 {
215    float v2, r = hi - lo;
216
217    if ( r == 0.0 ) {
218       if ( i ) *i = 0;
219       return lo;
220    }
221
222    v2 = lo + v - r * ( float ) floor(( double ) v / r );
223    if ( i ) *i = -( int )(( v2 - v ) / r + ( v2 > v ? 0.5 : -0.5 ));
224
225    return v2;
226 }
227
228
229 /*
230 ======================================================================
231 hermite()
232
233 Calculate the Hermite coefficients.
234 ====================================================================== */
235
236 static void hermite( float t, float *h1, float *h2, float *h3, float *h4 )
237 {
238    float t2, t3;
239
240    t2 = t * t;
241    t3 = t * t2;
242
243    *h2 = 3.0f * t2 - t3 - t3;
244    *h1 = 1.0f - *h2;
245    *h4 = t3 - t2;
246    *h3 = *h4 - t2 + t;
247 }
248
249
250 /*
251 ======================================================================
252 bezier()
253
254 Interpolate the value of a 1D Bezier curve.
255 ====================================================================== */
256
257 static float bezier( float x0, float x1, float x2, float x3, float t )
258 {
259    float a, b, c, t2, t3;
260
261    t2 = t * t;
262    t3 = t2 * t;
263
264    c = 3.0f * ( x1 - x0 );
265    b = 3.0f * ( x2 - x1 ) - c;
266    a = x3 - x0 - c - b;
267
268    return a * t3 + b * t2 + c * t + x0;
269 }
270
271
272 /*
273 ======================================================================
274 bez2_time()
275
276 Find the t for which bezier() returns the input time.  The handle
277 endpoints of a BEZ2 curve represent the control points, and these have
278 (time, value) coordinates, so time is used as both a coordinate and a
279 parameter for this curve type.
280 ====================================================================== */
281
282 static float bez2_time( float x0, float x1, float x2, float x3, float time,
283    float *t0, float *t1 )
284 {
285    float v, t;
286
287    t = *t0 + ( *t1 - *t0 ) * 0.5f;
288    v = bezier( x0, x1, x2, x3, t );
289    if ( fabs( time - v ) > .0001f ) {
290       if ( v > time )
291          *t1 = t;
292       else
293          *t0 = t;
294       return bez2_time( x0, x1, x2, x3, time, t0, t1 );
295    }
296    else
297       return t;
298 }
299
300
301 /*
302 ======================================================================
303 bez2()
304
305 Interpolate the value of a BEZ2 curve.
306 ====================================================================== */
307
308 static float bez2( lwKey *key0, lwKey *key1, float time )
309 {
310    float x, y, t, t0 = 0.0f, t1 = 1.0f;
311
312    if ( key0->shape == ID_BEZ2 )
313       x = key0->time + key0->param[ 2 ];
314    else
315       x = key0->time + ( key1->time - key0->time ) / 3.0f;
316
317    t = bez2_time( key0->time, x, key1->time + key1->param[ 0 ], key1->time,
318       time, &t0, &t1 );
319
320    if ( key0->shape == ID_BEZ2 )
321       y = key0->value + key0->param[ 3 ];
322    else
323       y = key0->value + key0->param[ 1 ] / 3.0f;
324
325    return bezier( key0->value, y, key1->param[ 1 ] + key1->value, key1->value, t );
326 }
327
328
329 /*
330 ======================================================================
331 outgoing()
332
333 Return the outgoing tangent to the curve at key0.  The value returned
334 for the BEZ2 case is used when extrapolating a linear pre behavior and
335 when interpolating a non-BEZ2 span.
336 ====================================================================== */
337
338 static float outgoing( lwKey *key0, lwKey *key1 )
339 {
340    float a, b, d, t, out;
341
342    switch ( key0->shape )
343    {
344       case ID_TCB:
345          a = ( 1.0f - key0->tension )
346            * ( 1.0f + key0->continuity )
347            * ( 1.0f + key0->bias );
348          b = ( 1.0f - key0->tension )
349            * ( 1.0f - key0->continuity )
350            * ( 1.0f - key0->bias );
351          d = key1->value - key0->value;
352
353          if ( key0->prev ) {
354             t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
355             out = t * ( a * ( key0->value - key0->prev->value ) + b * d );
356          }
357          else
358             out = b * d;
359          break;
360
361       case ID_LINE:
362          d = key1->value - key0->value;
363          if ( key0->prev ) {
364             t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
365             out = t * ( key0->value - key0->prev->value + d );
366          }
367          else
368             out = d;
369          break;
370
371       case ID_BEZI:
372       case ID_HERM:
373          out = key0->param[ 1 ];
374          if ( key0->prev )
375             out *= ( key1->time - key0->time ) / ( key1->time - key0->prev->time );
376          break;
377
378       case ID_BEZ2:
379          out = key0->param[ 3 ] * ( key1->time - key0->time );
380          if ( fabs( key0->param[ 2 ] ) > 1e-5f )
381             out /= key0->param[ 2 ];
382          else
383             out *= 1e5f;
384          break;
385
386       case ID_STEP:
387       default:
388          out = 0.0f;
389          break;
390    }
391
392    return out;
393 }
394
395
396 /*
397 ======================================================================
398 incoming()
399
400 Return the incoming tangent to the curve at key1.  The value returned
401 for the BEZ2 case is used when extrapolating a linear post behavior.
402 ====================================================================== */
403
404 static float incoming( lwKey *key0, lwKey *key1 )
405 {
406    float a, b, d, t, in;
407
408    switch ( key1->shape )
409    {
410       case ID_LINE:
411          d = key1->value - key0->value;
412          if ( key1->next ) {
413             t = ( key1->time - key0->time ) / ( key1->next->time - key0->time );
414             in = t * ( key1->next->value - key1->value + d );
415          }
416          else
417             in = d;
418          break;
419
420       case ID_TCB:
421          a = ( 1.0f - key1->tension )
422            * ( 1.0f - key1->continuity )
423            * ( 1.0f + key1->bias );
424          b = ( 1.0f - key1->tension )
425            * ( 1.0f + key1->continuity )
426            * ( 1.0f - key1->bias );
427          d = key1->value - key0->value;
428
429          if ( key1->next ) {
430             t = ( key1->time - key0->time ) / ( key1->next->time - key0->time );
431             in = t * ( b * ( key1->next->value - key1->value ) + a * d );
432          }
433          else
434             in = a * d;
435          break;
436
437       case ID_BEZI:
438       case ID_HERM:
439          in = key1->param[ 0 ];
440          if ( key1->next )
441             in *= ( key1->time - key0->time ) / ( key1->next->time - key0->time );
442          break;
443          return in;
444
445       case ID_BEZ2:
446          in = key1->param[ 1 ] * ( key1->time - key0->time );
447          if ( fabs( key1->param[ 0 ] ) > 1e-5f )
448             in /= key1->param[ 0 ];
449          else
450             in *= 1e5f;
451          break;
452
453       case ID_STEP:
454       default:
455          in = 0.0f;
456          break;
457    }
458
459    return in;
460 }
461
462
463 /*
464 ======================================================================
465 evalEnvelope()
466
467 Given a list of keys and a time, returns the interpolated value of the
468 envelope at that time.
469 ====================================================================== */
470
471 float evalEnvelope( lwEnvelope *env, float time )
472 {
473    lwKey *key0, *key1, *skey, *ekey;
474    float t, h1, h2, h3, h4, in, out, offset = 0.0f;
475    int noff;
476
477
478    /* if there's no key, the value is 0 */
479
480    if ( env->nkeys == 0 ) return 0.0f;
481
482    /* if there's only one key, the value is constant */
483
484    if ( env->nkeys == 1 )
485       return env->key->value;
486
487    /* find the first and last keys */
488
489    skey = ekey = env->key;
490    while ( ekey->next ) ekey = ekey->next;
491
492    /* use pre-behavior if time is before first key time */
493
494    if ( time < skey->time ) {
495       switch ( env->behavior[ 0 ] )
496       {
497          case BEH_RESET:
498             return 0.0f;
499
500          case BEH_CONSTANT:
501             return skey->value;
502
503          case BEH_REPEAT:
504             time = range( time, skey->time, ekey->time, NULL );
505             break;
506
507          case BEH_OSCILLATE:
508             time = range( time, skey->time, ekey->time, &noff );
509             if ( noff % 2 )
510                time = ekey->time - skey->time - time;
511             break;
512
513          case BEH_OFFSET:
514             time = range( time, skey->time, ekey->time, &noff );
515             offset = noff * ( ekey->value - skey->value );
516             break;
517
518          case BEH_LINEAR:
519             out = outgoing( skey, skey->next )
520                 / ( skey->next->time - skey->time );
521             return out * ( time - skey->time ) + skey->value;
522       }
523    }
524
525    /* use post-behavior if time is after last key time */
526
527    else if ( time > ekey->time ) {
528       switch ( env->behavior[ 1 ] )
529       {
530          case BEH_RESET:
531             return 0.0f;
532
533          case BEH_CONSTANT:
534             return ekey->value;
535
536          case BEH_REPEAT:
537             time = range( time, skey->time, ekey->time, NULL );
538             break;
539
540          case BEH_OSCILLATE:
541             time = range( time, skey->time, ekey->time, &noff );
542             if ( noff % 2 )
543                time = ekey->time - skey->time - time;
544             break;
545
546          case BEH_OFFSET:
547             time = range( time, skey->time, ekey->time, &noff );
548             offset = noff * ( ekey->value - skey->value );
549             break;
550
551          case BEH_LINEAR:
552             in = incoming( ekey->prev, ekey )
553                / ( ekey->time - ekey->prev->time );
554             return in * ( time - ekey->time ) + ekey->value;
555       }
556    }
557
558    /* get the endpoints of the interval being evaluated */
559
560    key0 = env->key;
561    while ( time > key0->next->time )
562       key0 = key0->next;
563    key1 = key0->next;
564
565    /* check for singularities first */
566
567    if ( time == key0->time )
568       return key0->value + offset;
569    else if ( time == key1->time )
570       return key1->value + offset;
571
572    /* get interval length, time in [0, 1] */
573
574    t = ( time - key0->time ) / ( key1->time - key0->time );
575
576    /* interpolate */
577
578    switch ( key1->shape )
579    {
580       case ID_TCB:
581       case ID_BEZI:
582       case ID_HERM:
583          out = outgoing( key0, key1 );
584          in = incoming( key0, key1 );
585          hermite( t, &h1, &h2, &h3, &h4 );
586          return h1 * key0->value + h2 * key1->value + h3 * out + h4 * in + offset;
587
588       case ID_BEZ2:
589          return bez2( key0, key1, time ) + offset;
590
591       case ID_LINE:
592          return key0->value + t * ( key1->value - key0->value ) + offset;
593
594       case ID_STEP:
595          return key0->value + offset;
596
597       default:
598          return offset;
599    }
600 }