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