Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/Tools/LightwaveConverter/src/lwEnvelope.cpp @ 7

Last change on this file since 7 was 6, checked in by anonymous, 17 years ago

=…

File size: 10.2 KB
Line 
1#include "lwEnvelope.h"
2
3lwKey *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/*======================================================================
11range()
12 
13Given the value v of a periodic function, returns the equivalent value
14v2 in the principal interval [lo, hi].  If i isn't NULL, it receives
15the number of wavelengths between v and v2.
16       
17v2 = v - i * (hi - lo)
18       
19For example, range( 3 pi, 0, 2 pi, i ) returns pi, with i = 1.
20====================================================================== */
21
22float 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/*======================================================================
38hermite()
39
40Calculate the Hermite coefficients.
41====================================================================== */
42
43void 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/*======================================================================
57bezier()
58
59Interpolate the value of a 1D Bezier curve.
60====================================================================== */
61
62float 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/*======================================================================
78bez2_time()
79
80Find the t for which bezier() returns the input time.  The handle
81endpoints 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
83parameter for this curve type.
84====================================================================== */
85 
86float 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 
111float 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 
141float 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/*======================================================================
205incoming()
206 
207Return the incoming tangent to the curve at key1.  The value returned
208for the BEZ2 case is used when extrapolating a linear post behavior.
209====================================================================== */
210 
211float 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/*======================================================================
272evalEnvelope()
273
274Given a list of keys and a time, returns the interpolated value of the
275envelope at that time.
276====================================================================== */
277 
278float 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}
Note: See TracBrowser for help on using the repository browser.