Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

LWChannelEnvelope.cpp

Go to the documentation of this file.
00001 
00002 /*
00003     TEDDY - General graphics application library
00004     Copyright (C) 1999-2002  Timo Suoranta
00005     tksuoran@cc.helsinki.fi
00006 
00007         Adapted from
00008 
00009         interp.c and envelope.h from lwsdk7.zip
00010         Interpolation (and extrapolation) of LightWave envelopes.
00011         Ernie Wright  16 Nov 00
00012 
00013     This library is free software; you can redistribute it and/or
00014     modify it under the terms of the GNU Lesser General Public
00015     License as published by the Free Software Foundation; either
00016     version 2.1 of the License, or (at your option) any later version.
00017 
00018     This library is distributed in the hope that it will be useful,
00019     but WITHOUT ANY WARRANTY; without even the implied warranty of
00020     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021     Lesser General Public License for more details.
00022 
00023     You should have received a copy of the GNU Lesser General Public
00024     License along with this library; if not, write to the Free Software
00025     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026 
00027     $Id: LWChannelEnvelope.cpp,v 1.1 2002/02/16 12:41:39 tksuoran Exp $
00028 */
00029 
00030 
00031 #include "Teddy/TeddyConfig.h"
00032 #if defined( TEDDY_INCLUDE_LW_SCENE )
00033 
00034 
00035 #include "Teddy/SysSupport/StdMaths.h"
00036 #include "Teddy/Imports/LWChannelEnvelope.h"
00037 #include "Teddy/Imports/LWChannelKey.h"
00038 #include "Teddy/SysSupport/Messages.h"
00039 using namespace Teddy::SysSupport;
00040 
00041 
00042 namespace Teddy   {
00043 namespace Imports {
00044 
00045 
00046 LWChannelEnvelope::LWChannelEnvelope( int channel_id )
00047 :
00048     channel_id     ( channel_id ),
00049     steps          ( 0 ),
00050     pre_behavior   ( 0 ),
00051     post_behavior  ( 0 ),
00052     last_time      ( -666 ),
00053     last_value     ( 0 )
00054 {
00055 }
00056 
00057 
00058 int LWChannelEnvelope::getChannelId(){
00059     return this->channel_id;
00060 }
00061 
00062 
00063 void LWChannelEnvelope::insert( LWChannelKey *channel_key ){
00064     keys.push_back( channel_key );
00065 }
00066 
00067 
00068 void LWChannelEnvelope::setBehaviors( int pre, int post ){
00069     this->pre_behavior  = pre;
00070     this->post_behavior = post;
00071 }
00072 
00073 
00074 #include <cstdlib>
00075 #include "Teddy/SysSupport/StdMaths.h"
00076 
00077 
00078 #define SHAPE_TCB      0
00079 #define SHAPE_HERM     1
00080 #define SHAPE_BEZI     2
00081 #define SHAPE_LINE     3
00082 #define SHAPE_STEP     4
00083 #define SHAPE_BEZ2     5
00084 
00085 #define BEH_RESET      0
00086 #define BEH_CONSTANT   1
00087 #define BEH_REPEAT     2
00088 #define BEH_OSCILLATE  3
00089 #define BEH_OFFSET     4
00090 #define BEH_LINEAR     5
00091 
00092 
00093 
00105 float range( float v, float lo, float hi, int *i ){
00106     float v2;
00107     float r = hi - lo;
00108     
00109     if( r == 0.0 ){
00110         if ( i ) *i = 0;
00111         return lo;
00112     }
00113     
00114     v2 = v - r * ( float ) floor(( v - lo ) / r );
00115     if ( i ){
00116         *i = -( int )(( v2 - v ) / r + ( v2 > v ? 0.5 : -0.5 ));
00117     }
00118     
00119     return v2;
00120 }
00121 
00122 
00128 static void hermite( float t, float *h1, float *h2, float *h3, float *h4 ){
00129     float t2;
00130     float t3;
00131     
00132     t2 = t * t;
00133     t3 = t * t2;
00134     
00135     *h2 = 3.0f * t2 - t3 - t3;
00136     *h1 = 1.0f - *h2;
00137     *h4 =  t3 - t2;
00138     *h3 = *h4 - t2 + t;
00139 }
00140 
00141 
00147 static float bezier( float x0, float x1, float x2, float x3, float t ){
00148     float a;
00149     float b;
00150     float c;
00151     float t2;
00152     float t3;
00153     
00154     t2 = t  * t;
00155     t3 = t2 * t;
00156     
00157     c  = 3.0f * ( x1 - x0 );
00158     b  = 3.0f * ( x2 - x1 ) - c;
00159     a  = x3 - x0 - c - b;
00160     
00161     return a * t3 + b * t2 + c * t + x0;
00162 }
00163 
00164 
00173 float bez2_time( float x0, float x1, float x2, float x3, float time, float *t0, float *t1 ){
00174     float v, t;
00175     
00176     t = *t0 + ( *t1 - *t0 ) * 0.5f;
00177     v = bezier( x0, x1, x2, x3, t );
00178     if( fabs( time - v ) > .0001f ){
00179         if( v > time ){
00180            *t1 = t;
00181         }else{
00182            *t0 = t;
00183         }
00184         return bez2_time( x0, x1, x2, x3, time, t0, t1 );
00185     }else{
00186         return t;
00187     }
00188 }
00189 
00190 
00196 float bez2( LWChannelKey *key0, LWChannelKey *key1, float time ){
00197     float x;
00198     float y;
00199     float t;
00200     float t0 = 0.0f;
00201     float t1 = 1.0f;
00202 
00203     x = key0->time  + ( key0->shape == SHAPE_BEZ2 ) ? key0->p3 : ( key1->time - key0->time ) / 3.0f;
00204     t = bez2_time     ( key0->time, x, key1->time + key1->p1, key1->time, key0->time, &t0, &t1 );
00205     y = key0->value + ( key0->shape == SHAPE_BEZ2 ) ? key0->p4 : key0->p2 / 3.0f;
00206     
00207     return bezier( key0->value, y, key1->p2 + key1->value, key1->value, t );
00208 }
00209 
00210 
00211 /*
00212     outgoing()
00213 
00214     Return the outgoing tangent to the curve at key0.  The value returned
00215     for the BEZ2 case is used when extrapolating a linear pre behavior and
00216     when interpolating a non-BEZ2 span.
00217 */
00218 float outgoing( LWChannelKey *prev, LWChannelKey *key0, LWChannelKey *key1 ){
00219     float a;
00220     float b;
00221     float d;
00222     float t;
00223     float out;
00224 
00225     switch( key0->shape ){
00226         case SHAPE_TCB:
00227             a = ( 1.0f - key0->tension() ) * ( 1.0f + key0->continuity() ) * ( 1.0f + key0->bias() );
00228             b = ( 1.0f - key0->tension() ) * ( 1.0f - key0->continuity() ) * ( 1.0f - key0->bias() );
00229             d = key1->value - key0->value;
00230             
00231             if( prev ){
00232                 t   = ( key1->time - key0->time ) / ( key1->time - prev->time );
00233                 out = t * ( a * ( key0->value - prev->value ) + b * d );
00234             }else{
00235                 out = b * d;
00236             }
00237             break;
00238         
00239         case SHAPE_LINE:
00240             d = key1->value - key0->value;
00241             if( prev ){
00242                 t   = ( key1->time - key0->time ) / ( key1->time - prev->time );
00243                 out = t * ( key0->value - prev->value + d );
00244             }else{
00245                 out = d;
00246             }
00247             break;
00248         
00249         case SHAPE_BEZI:
00250         case SHAPE_HERM:
00251             out = key0->p5;
00252             if( prev ){
00253                 out *= ( key1->time - key0->time ) / ( key1->time - prev->time );
00254             }
00255             break;
00256         
00257         case SHAPE_BEZ2:
00258             out = key0->p4 * ( key1->time - key0->time );
00259             if( fabs( key0->p3 ) > 1e-5f ){
00260                 out /= key0->p3;
00261             }else{
00262                 out *= 1e5f;
00263             }
00264             break;
00265         
00266         case SHAPE_STEP:
00267         default:
00268             out = 0.0f;
00269             break;
00270     }
00271     
00272     return out;
00273 }
00274 
00275 
00276 /*
00277     incoming()
00278 
00279     Return the incoming tangent to the curve at key1.  The value returned
00280     for the BEZ2 case is used when extrapolating a linear post behavior.
00281 */
00282 float incoming( LWChannelKey *key0, LWChannelKey *key1, LWChannelKey *next ){
00283     float a;
00284     float b;
00285     float d;
00286     float t;
00287     float in;
00288     
00289     switch ( key1->shape ){
00290         case SHAPE_LINE:
00291             d = key1->value - key0->value;
00292             if( next ){
00293                 t = ( key1->time - key0->time ) / ( next->time - key0->time );
00294                 in = t * ( next->value - key1->value + d );
00295             }else{
00296                 in = d;
00297             }
00298             break;
00299         
00300         case SHAPE_TCB:
00301             a = ( 1.0f - key1->tension() ) * ( 1.0f - key1->continuity() ) * ( 1.0f + key1->bias() );
00302             b = ( 1.0f - key1->tension() ) * ( 1.0f + key1->continuity() ) * ( 1.0f - key1->bias() );
00303             d = key1->value - key0->value;
00304             
00305             if( next ){
00306                 t  = ( key1->time - key0->time ) / ( next->time - key0->time );
00307                 in = t * ( b * ( next->value - key1->value ) + a * d );
00308             }else{
00309                 in = a * d;
00310             }
00311             break;
00312         
00313         case SHAPE_BEZI:
00314         case SHAPE_HERM:
00315             in = key1->p4;
00316             if( next ){
00317                 in *= ( key1->time - key0->time ) / ( next->time - key0->time );
00318             }
00319             break;
00320             return in;
00321         
00322         case SHAPE_BEZ2:
00323             in = key1->p2 * ( key1->time - key0->time );
00324             if( fabs( key1->p1 ) > 1e-5f ){
00325                 in /= key1->p1;
00326             }else{
00327                 in *= 1e5f;
00328             }
00329             break;
00330         
00331         case SHAPE_STEP:
00332         default:
00333             in = 0.0f;
00334             break;
00335     }
00336     
00337     return in;
00338 }
00339 
00340 
00347 float LWChannelEnvelope::eval( float time ){
00348     if( time==last_time ){
00349         return last_value;
00350     }else{
00351         last_time = time;
00352     }
00353 
00354     LWChannelKey *prev = NULL;
00355     LWChannelKey *key0 = NULL;
00356     LWChannelKey *key1 = NULL;
00357     LWChannelKey *next = NULL;
00358     LWChannelKey *skey = NULL;
00359     LWChannelKey *ekey = NULL;
00360     float  t;
00361     float  in;
00362     float  out;
00363     float  offset = 0.0f;
00364     int    noff;
00365 
00366     if( keys.size() == 0 ){
00367         last_value = 0;
00368         return last_value;
00369     }
00370 
00371     //  Get the first key
00372     list<LWChannelKey*>::iterator k_it = keys.begin();
00373 
00374     //  If there's no key, the value is 0
00375     if( k_it == keys.end() ){
00376         last_value = 0;
00377         return last_value;
00378     }
00379 
00380 
00381     //  Get the endpoints of the interval being evaluated
00382     ekey = skey = key0 = *k_it; k_it++;
00383 
00384     if( keys.size() == 1 ){
00385         last_value = key0->value;
00386         return last_value;
00387     }
00388 
00389     //  If there's only one key, the value is constant
00390     if( k_it == keys.end() ){
00391         last_value = key0->value;
00392         return last_value;
00393     }
00394 
00395     if( k_it != keys.end() ){
00396         prev = ekey;
00397         ekey = next = *k_it; k_it++;
00398     }
00399     while( k_it != keys.end() ){
00400         prev = ekey;
00401         ekey = *k_it;
00402         k_it++;
00403     }
00404 
00405 
00406     //  Use pre-behavior if time is before first key time
00407     if( time < skey->time ){
00408         switch( this->pre_behavior ){
00409         case BEH_RESET:
00410             last_value = 0;
00411             return last_value;
00412         
00413         case BEH_CONSTANT:
00414             last_value = skey->value;
00415             return last_value;
00416         
00417         case BEH_REPEAT:
00418             last_time = time = range( time, skey->time, ekey->time, NULL );
00419             break;
00420         
00421         case BEH_OSCILLATE:
00422             last_time = time = range( time, skey->time, ekey->time, &noff );
00423             if( noff % 2 ){
00424                 last_time = time = ekey->time - skey->time - time;
00425             }
00426             break;
00427         
00428         case BEH_OFFSET:
00429             last_time = time = range( time, skey->time, ekey->time, &noff );
00430             offset    = noff * ( ekey->value - skey->value );
00431             break;
00432         
00433         case BEH_LINEAR:
00434             out        = outgoing( NULL, skey, next ) / ( next->time - skey->time );
00435             last_value = out * ( time - skey->time ) + skey->value;;
00436             return last_value;
00437 
00438         default:
00439             last_value = 0;
00440             return last_value;
00441         }
00442     }
00443 
00444     //  Use post-behavior if time is after last key time
00445     else if( time > ekey->time ){
00446         switch( post_behavior ){
00447         case BEH_RESET:
00448             last_value = 0;
00449             return last_value;
00450         
00451         case BEH_CONSTANT:
00452             last_value = ekey->value;
00453             return last_value;
00454         
00455         case BEH_REPEAT:
00456             time = range( time, skey->time, ekey->time, NULL );
00457             break;
00458         
00459         case BEH_OSCILLATE:
00460             last_time = time = range( time, skey->time, ekey->time, &noff );
00461             if( noff % 2 ){
00462                last_time = time = ekey->time - skey->time - time;
00463             }
00464             break;
00465         
00466         case BEH_OFFSET:
00467             last_time = time = range( time, skey->time, ekey->time, &noff );
00468             offset    = noff * ( ekey->value - skey->value );
00469             break;
00470         
00471         case BEH_LINEAR:
00472             in = incoming( prev, ekey, NULL ) / ( ekey->time - prev->time );
00473             last_value = in * ( time - ekey->time ) + ekey->value;
00474             return last_value;
00475 
00476         default:
00477             last_value = 0;
00478             return last_value;
00479         }
00480     }
00481 
00482 
00483     //  Get the endpoints of the interval being evaluated
00484     k_it = keys.begin();
00485     prev = NULL;
00486     key0 = NULL;
00487     key1 = NULL;
00488     next = NULL;
00489     while( k_it != keys.end() ){
00490         prev =  key0;
00491         key0 =  key1;
00492         key1 = *k_it;
00493         k_it++;
00494         if( time <= key1->time ){
00495             if( key0 == NULL ){
00496                 key0 = key1;
00497                 if( k_it != keys.end() ){
00498                     key1 = *k_it;
00499                 }
00500             }
00501             break;
00502         }
00503     }
00504     if( k_it != keys.end() ){
00505         next = *k_it;
00506     }
00507 
00508 /*  debug_msg(
00509         "%9.4f <= %9.4f <= %9.4f",
00510         key0 != NULL ? key0->time : 0,
00511         time,
00512         key1 != NULL ? key1->time : 0
00513     );*/
00514 
00515     //  Check for singularities first
00516     if( time == key0->time ){
00517         last_value = key0->value + offset;
00518         return last_value;
00519     }else if( time == key1->time ){
00520         last_value = key1->value + offset;
00521         return last_value;
00522     }
00523 
00524     if( (key0 == NULL) || (key1 == NULL) ){
00525         emsg( M_LWO, "Channel Interpolation error" );
00526         return 0;
00527     }
00528     
00529     //  Get interval length, time in [0, 1]
00530     t = ( time - key0->time ) / ( key1->time - key0->time );
00531     
00532     //  Interpolate
00533     switch( key1->shape ){
00534     case SHAPE_TCB:
00535     case SHAPE_BEZI:
00536     case SHAPE_HERM:
00537         out = outgoing( prev, key0, key1 );
00538         in  = incoming( key0, key1, next );
00539         float h1;
00540         float h2;
00541         float h3;
00542         float h4;
00543         hermite( t, &h1, &h2, &h3, &h4 );
00544         last_value = h1 * key0->value + h2 * key1->value + h3 * out + h4 * in + offset;
00545         return last_value;
00546     
00547     case SHAPE_BEZ2:
00548         last_value = bez2( key0, key1, time ) + offset;
00549         return last_value;
00550     
00551     case SHAPE_LINE:
00552         last_value = key0->value + t * ( key1->value - key0->value ) + offset;
00553         return last_value;
00554     
00555     case SHAPE_STEP:
00556         last_value = key0->value + offset;
00557         return last_value;
00558     
00559     default:
00560         last_value = offset;
00561         return last_value;
00562     }
00563 }
00564 
00565 
00566 };  //  namespace Imports
00567 };  //  namespace Teddy
00568 
00569 
00570 #endif  //  TEDDY_INCLUDE_LW_SCENE
00571 
00572 
00573 /*
00574 Envelopes
00575 
00576 An envelope defines a function of time. For any animation time,
00577 an envelope's parameters can be combined to generate a value at
00578 that time. Envelopes are used to store position coordinates,
00579 rotation angles, scale factors, camera zoom, light intensity,
00580 texture parameters, and anything else that can vary over time.
00581 
00582 The envelope function is a piecewise polynomial curve. The
00583 function is tabulated at specific points, called keys. The
00584 curve segment between two adjacent keys is called a span, and
00585 values on the span are calculated by interpolating between the
00586 keys. The interpolation can be linear, cubic, or stepped, and
00587 it can be different for each span. The value of the function
00588 before the first key and after the last key is calculated by
00589 extrapolation.
00590 
00591 In scene files, an envelope is stored in a block named Envelope
00592 that contains one or more nested Key blocks and one Behaviors block.
00593 
00594    { Envelope
00595      nkeys
00596      Key value time spantype p1 p2 p3 p4 p5 p6
00597      Key ...
00598      Behaviors pre post
00599    }
00600 
00601 The nkeys value is an integer, the number of Key blocks in
00602 the envelope. Envelopes must contain at least one Key block.
00603 The contents of a Key block are as follows. 
00604 
00605 value 
00606 
00607 The key value, a floating-point number. The units and limits
00608 of the value depend on what parameter the envelope represents. 
00609 
00610 time 
00611 
00612 The time in seconds, a float. This can be negative, zero or
00613 positive. Keys are listed in the envelope in increasing time
00614 order. 
00615 
00616 spantype 
00617 
00618 The curve type, an integer. This determines the kind of
00619 interpolation that will be performed on the span between
00620 this key and the previous key, and also indicates what
00621 interpolation parameters are stored for the key. 
00622 
00623 0 - TCB (Kochanek-Bartels) 
00624 1 - Hermite 
00625 2 - 1D Bezier (obsolete, equivalent to Hermite) 
00626 3 - Linear 
00627 4 - Stepped 
00628 5 - 2D Bezier 
00629 
00630 p1...p6 Curve parameters. The data depends on the span type. 
00631 
00632 TCB, Hermite, 1D Bezier 
00633 
00634 The first three parameters are tension(), continuity() and bias().
00635 The fourth and fifth parameters are the incoming and outgoing
00636 tangents. The sixth parameter is ignored and should be 0. Use
00637 the first three to evaluate TCB spans, and the other two to
00638 evaluate Hermite spans. 
00639 
00640 2D Bezier 
00641 
00642 The first two parameters are the incoming time and value,
00643 and the second two are the outgoing time and value. 
00644 
00645 The Behaviors block contains two integers.
00646 
00647 pre, post 
00648 
00649 Pre- and post-behaviors. These determine how the envelope
00650 is extrapolated at times before the first key and after
00651 the last one. 
00652 
00653 0 - Reset          Sets the value to 0.0. 
00654 1 - Constant       Sets the value to the value at the nearest key. 
00655 2 - Repeat         Repeats the interval between the first and last keys (the primary interval). 
00656 3 - Oscillate      Like Repeat, but alternating copies of the primary interval are time-reversed. 
00657 4 - Offset Repeat  Like Repeat, but offset by the difference between the values of the first and last keys. 
00658 5 - Linear         Linearly extrapolates the value based on the tangent at the nearest key. 
00659 
00660 The source code in the sample/envelope directory of the LightWave plug-in SDK demonstrates
00661 how envelopes are evaluated.
00662 */
00663