animation.cxx

00001 // animation.cxx - classes to manage model animation.
00002 // Written by David Megginson, started 2002.
00003 //
00004 // This file is in the Public Domain, and comes with no warranty.
00005 
00006 #ifdef HAVE_CONFIG_H
00007 #  include <simgear_config.h>
00008 #endif
00009 
00010 #include <string.h>             // for strcmp()
00011 #include <math.h>
00012 
00013 #include <plib/sg.h>
00014 #include <plib/ssg.h>
00015 #include <plib/ul.h>
00016 
00017 #include <simgear/math/interpolater.hxx>
00018 #include <simgear/props/condition.hxx>
00019 #include <simgear/props/props.hxx>
00020 #include <simgear/math/sg_random.h>
00021 
00022 #include "animation.hxx"
00023 #include "custtrans.hxx"
00024 #include "personality.hxx"
00025 
00026 
00028 // Static utility functions.
00030 
00034 static void
00035 set_rotation (sgMat4 &matrix, double position_deg,
00036               sgVec3 &center, sgVec3 &axis)
00037 {
00038  float temp_angle = -position_deg * SG_DEGREES_TO_RADIANS ;
00039  
00040  float s = (float) sin ( temp_angle ) ;
00041  float c = (float) cos ( temp_angle ) ;
00042  float t = SG_ONE - c ;
00043 
00044  // axis was normalized at load time 
00045  // hint to the compiler to put these into FP registers
00046  float x = axis[0];
00047  float y = axis[1];
00048  float z = axis[2];
00049 
00050  matrix[0][0] = t * x * x + c ;
00051  matrix[0][1] = t * y * x - s * z ;
00052  matrix[0][2] = t * z * x + s * y ;
00053  matrix[0][3] = SG_ZERO;
00054  
00055  matrix[1][0] = t * x * y + s * z ;
00056  matrix[1][1] = t * y * y + c ;
00057  matrix[1][2] = t * z * y - s * x ;
00058  matrix[1][3] = SG_ZERO;
00059  
00060  matrix[2][0] = t * x * z - s * y ;
00061  matrix[2][1] = t * y * z + s * x ;
00062  matrix[2][2] = t * z * z + c ;
00063  matrix[2][3] = SG_ZERO;
00064 
00065   // hint to the compiler to put these into FP registers
00066  x = center[0];
00067  y = center[1];
00068  z = center[2];
00069  
00070  matrix[3][0] = x - x*matrix[0][0] - y*matrix[1][0] - z*matrix[2][0];
00071  matrix[3][1] = y - x*matrix[0][1] - y*matrix[1][1] - z*matrix[2][1];
00072  matrix[3][2] = z - x*matrix[0][2] - y*matrix[1][2] - z*matrix[2][2];
00073  matrix[3][3] = SG_ONE;
00074 }
00075 
00079 static void
00080 set_translation (sgMat4 &matrix, double position_m, sgVec3 &axis)
00081 {
00082   sgVec3 xyz;
00083   sgScaleVec3(xyz, axis, position_m);
00084   sgMakeTransMat4(matrix, xyz);
00085 }
00086 
00090 static void
00091 set_scale (sgMat4 &matrix, double x, double y, double z)
00092 {
00093   sgMakeIdentMat4( matrix );
00094   matrix[0][0] = x;
00095   matrix[1][1] = y;
00096   matrix[2][2] = z;
00097 }
00098 
00102 static void
00103 change_alpha( ssgBase *_branch, float _blend )
00104 {
00105   int i;
00106 
00107   for (i = 0; i < ((ssgBranch *)_branch)->getNumKids(); i++)
00108     change_alpha( ((ssgBranch *)_branch)->getKid(i), _blend );
00109 
00110   if ( !_branch->isAKindOf(ssgTypeLeaf())
00111        && !_branch->isAKindOf(ssgTypeVtxTable())
00112        && !_branch->isAKindOf(ssgTypeVTable()) )
00113     return;
00114 
00115   int num_colors = ((ssgLeaf *)_branch)->getNumColours();
00116 // unsigned int select_ = (_blend == 1.0) ? false : true;
00117 
00118   for (i = 0; i < num_colors; i++)
00119   {
00120 //    ((ssgSelector *)_branch)->select( select_ );
00121     float *color =  ((ssgLeaf *)_branch)->getColour(i);
00122     color[3] = _blend;
00123   }
00124 }
00125 
00129 static double
00130 apply_mods(double property, double step, double scroll)
00131 {
00132 
00133   double modprop;
00134   if(step > 0) {
00135     double scrollval = 0.0;
00136     if(scroll > 0) {
00137       // calculate scroll amount (for odometer like movement)
00138       double remainder  =  step - fmod(fabs(property), step);
00139       if (remainder < scroll) {
00140         scrollval = (scroll - remainder) / scroll * step;
00141       }
00142     }
00143   // apply stepping of input value
00144   if(property > 0) 
00145      modprop = ((floor(property/step) * step) + scrollval);
00146   else
00147      modprop = ((ceil(property/step) * step) + scrollval);
00148   } else {
00149      modprop = property;
00150   }
00151   return modprop;
00152 
00153 }
00154 
00158 static SGInterpTable *
00159 read_interpolation_table (SGPropertyNode_ptr props)
00160 {
00161   SGPropertyNode_ptr table_node = props->getNode("interpolation");
00162   if (table_node != 0) {
00163     SGInterpTable * table = new SGInterpTable();
00164     vector<SGPropertyNode_ptr> entries = table_node->getChildren("entry");
00165     for (unsigned int i = 0; i < entries.size(); i++)
00166       table->addEntry(entries[i]->getDoubleValue("ind", 0.0),
00167                       entries[i]->getDoubleValue("dep", 0.0));
00168     return table;
00169   } else {
00170     return 0;
00171   }
00172 }
00173 
00174 
00175 
00177 // Implementation of SGAnimation
00179 
00180 // Initialize the static data member
00181 double SGAnimation::sim_time_sec = 0.0;
00182 SGPersonalityBranch *SGAnimation::current_object = 0;
00183 
00184 SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch)
00185     : _branch(branch),
00186     animation_type(0)
00187 {
00188     _branch->setName(props->getStringValue("name", 0));
00189     if ( props->getBoolValue( "enable-hot", true ) ) {
00190         _branch->setTraversalMaskBits( SSGTRAV_HOT );
00191     } else {
00192         _branch->clrTraversalMaskBits( SSGTRAV_HOT );
00193     }
00194 }
00195 
00196 SGAnimation::~SGAnimation ()
00197 {
00198 }
00199 
00200 void
00201 SGAnimation::init ()
00202 {
00203 }
00204 
00205 int
00206 SGAnimation::update()
00207 {
00208     return 1;
00209 }
00210 
00211 void
00212 SGAnimation::restore()
00213 {
00214 }
00215 
00216 
00217 
00219 // Implementation of SGNullAnimation
00221 
00222 SGNullAnimation::SGNullAnimation (SGPropertyNode_ptr props)
00223   : SGAnimation(props, new ssgBranch)
00224 {
00225 }
00226 
00227 SGNullAnimation::~SGNullAnimation ()
00228 {
00229 }
00230 
00231 
00232 
00234 // Implementation of SGRangeAnimation
00236 
00237 SGRangeAnimation::SGRangeAnimation (SGPropertyNode *prop_root,
00238                                     SGPropertyNode_ptr props)
00239   : SGAnimation(props, new ssgRangeSelector),
00240     _min(0.0), _max(0.0), _min_factor(1.0), _max_factor(1.0),
00241     _condition(0)
00242 {
00243     SGPropertyNode_ptr node = props->getChild("condition");
00244     if (node != 0)
00245        _condition = sgReadCondition(prop_root, node);
00246 
00247     float ranges[2];
00248 
00249     node = props->getChild( "min-factor" );
00250     if (node != 0) {
00251        _min_factor = props->getFloatValue("min-factor", 1.0);
00252     }
00253     node = props->getChild( "max-factor" );
00254     if (node != 0) {
00255        _max_factor = props->getFloatValue("max-factor", 1.0);
00256     }
00257     node = props->getChild( "min-property" );
00258     if (node != 0) {
00259        _min_prop = (SGPropertyNode *)prop_root->getNode(node->getStringValue(), true);
00260        ranges[0] = _min_prop->getFloatValue() * _min_factor;
00261     } else {
00262        _min = props->getFloatValue("min-m", 0);
00263        ranges[0] = _min * _min_factor;
00264     }
00265     node = props->getChild( "max-property" );
00266     if (node != 0) {
00267        _max_prop = (SGPropertyNode *)prop_root->getNode(node->getStringValue(), true);
00268        ranges[1] = _max_prop->getFloatValue() * _max_factor;
00269     } else {
00270        _max = props->getFloatValue("max-m", 0);
00271        ranges[1] = _max * _max_factor;
00272     }
00273     ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
00274 }
00275 
00276 SGRangeAnimation::~SGRangeAnimation ()
00277 {
00278    delete _condition;
00279 }
00280 
00281 int
00282 SGRangeAnimation::update()
00283 {
00284   float ranges[2];
00285   if ( _condition == 0 || _condition->test() ) {
00286     if (_min_prop != 0) {
00287       ranges[0] = _min_prop->getFloatValue() * _min_factor;
00288     } else {
00289       ranges[0] = _min * _min_factor;
00290     }
00291     if (_max_prop != 0) {
00292       ranges[1] = _max_prop->getFloatValue() * _max_factor;
00293     } else {
00294       ranges[1] = _max * _max_factor;
00295     }
00296   } else {
00297     ranges[0] = 0.f;
00298     ranges[1] = 1000000000.f;
00299   }
00300   ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
00301   return 2;
00302 }
00303 
00304 
00305 
00307 // Implementation of SGBillboardAnimation
00309 
00310 SGBillboardAnimation::SGBillboardAnimation (SGPropertyNode_ptr props)
00311     : SGAnimation(props, new ssgCutout(props->getBoolValue("spherical", true)))
00312 {
00313 }
00314 
00315 SGBillboardAnimation::~SGBillboardAnimation ()
00316 {
00317 }
00318 
00319 
00320 
00322 // Implementation of SGSelectAnimation
00324 
00325 SGSelectAnimation::SGSelectAnimation( SGPropertyNode *prop_root,
00326                                   SGPropertyNode_ptr props )
00327   : SGAnimation(props, new ssgSelector),
00328     _condition(0)
00329 {
00330   SGPropertyNode_ptr node = props->getChild("condition");
00331   if (node != 0)
00332     _condition = sgReadCondition(prop_root, node);
00333 }
00334 
00335 SGSelectAnimation::~SGSelectAnimation ()
00336 {
00337   delete _condition;
00338 }
00339 
00340 int
00341 SGSelectAnimation::update()
00342 {
00343   if (_condition != 0 && _condition->test()) 
00344       ((ssgSelector *)_branch)->select(0xffff);
00345   else
00346       ((ssgSelector *)_branch)->select(0x0000);
00347   return 2;
00348 }
00349 
00350 
00351 
00353 // Implementation of SGSpinAnimation
00355 
00356 SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
00357                               SGPropertyNode_ptr props,
00358                               double sim_time_sec )
00359   : SGAnimation(props, new ssgTransform),
00360     _use_personality( props->getBoolValue("use-personality",false) ),
00361     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
00362     _last_time_sec( sim_time_sec ),
00363     _condition(0),
00364     _factor( props, "factor", 1.0 ),
00365     _position_deg( props, "starting-position-deg", 0.0 )
00366 {
00367     SGPropertyNode_ptr node = props->getChild("condition");
00368     if (node != 0)
00369         _condition = sgReadCondition(prop_root, node);
00370 
00371     _center[0] = 0;
00372     _center[1] = 0;
00373     _center[2] = 0;
00374     if (props->hasValue("axis/x1-m")) {
00375         double x1,y1,z1,x2,y2,z2;
00376         x1 = props->getFloatValue("axis/x1-m");
00377         y1 = props->getFloatValue("axis/y1-m");
00378         z1 = props->getFloatValue("axis/z1-m");
00379         x2 = props->getFloatValue("axis/x2-m");
00380         y2 = props->getFloatValue("axis/y2-m");
00381         z2 = props->getFloatValue("axis/z2-m");
00382         _center[0] = (x1+x2)/2;
00383         _center[1]= (y1+y2)/2;
00384         _center[2] = (z1+z2)/2;
00385         float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
00386         _axis[0] = (x2-x1)/vector_length;
00387         _axis[1] = (y2-y1)/vector_length;
00388         _axis[2] = (z2-z1)/vector_length;
00389     } else {
00390        _axis[0] = props->getFloatValue("axis/x", 0);
00391        _axis[1] = props->getFloatValue("axis/y", 0);
00392        _axis[2] = props->getFloatValue("axis/z", 0);
00393     }
00394     if (props->hasValue("center/x-m")) {
00395        _center[0] = props->getFloatValue("center/x-m", 0);
00396        _center[1] = props->getFloatValue("center/y-m", 0);
00397        _center[2] = props->getFloatValue("center/z-m", 0);
00398     }
00399     sgNormalizeVec3(_axis);
00400 }
00401 
00402 SGSpinAnimation::~SGSpinAnimation ()
00403 {
00404    delete _condition;
00405 }
00406 
00407 int
00408 SGSpinAnimation::update()
00409 {
00410   if ( _condition == 0 || _condition->test() ) {
00411     double dt;
00412     float velocity_rpms;
00413     if ( _use_personality && current_object ) {
00414       SGPersonalityBranch *key = current_object;
00415       if ( !key->getIntValue( this, INIT_SPIN ) ) {
00416         key->setDoubleValue( _factor.shuffle(), this, FACTOR_SPIN );
00417         key->setDoubleValue( _position_deg.shuffle(), this, POSITION_DEG_SPIN );
00418 
00419         key->setDoubleValue( sim_time_sec, this, LAST_TIME_SEC_SPIN );
00420         key->setIntValue( 1, this, INIT_SPIN );
00421       }
00422 
00423       _factor = key->getDoubleValue( this, FACTOR_SPIN );
00424       _position_deg = key->getDoubleValue( this, POSITION_DEG_SPIN );
00425       _last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC_SPIN );
00426       dt = sim_time_sec - _last_time_sec;
00427       _last_time_sec = sim_time_sec;
00428       key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC_SPIN );
00429 
00430       velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
00431       _position_deg += (dt * velocity_rpms * 360);
00432       while (_position_deg < 0)
00433          _position_deg += 360.0;
00434       while (_position_deg >= 360.0)
00435          _position_deg -= 360.0;
00436       key->setDoubleValue( _position_deg, this, POSITION_DEG_SPIN );
00437     } else {
00438       dt = sim_time_sec - _last_time_sec;
00439       _last_time_sec = sim_time_sec;
00440 
00441       velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0);
00442       _position_deg += (dt * velocity_rpms * 360);
00443       while (_position_deg < 0)
00444          _position_deg += 360.0;
00445       while (_position_deg >= 360.0)
00446          _position_deg -= 360.0;
00447     }
00448 
00449     set_rotation(_matrix, _position_deg, _center, _axis);
00450     ((ssgTransform *)_branch)->setTransform(_matrix);
00451   }
00452   return 1;
00453 }
00454 
00455 
00456 
00458 // Implementation of SGTimedAnimation
00460 
00461 SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
00462   : SGAnimation(props, new ssgSelector),
00463     _use_personality( props->getBoolValue("use-personality",false) ),
00464     _duration_sec(props->getDoubleValue("duration-sec", 1.0)),
00465     _last_time_sec( sim_time_sec ),
00466     _total_duration_sec( 0 ),
00467     _step( 0 )
00468     
00469 {
00470     vector<SGPropertyNode_ptr> nodes = props->getChildren( "branch-duration-sec" );
00471     size_t nb = nodes.size();
00472     for ( size_t i = 0; i < nb; i++ ) {
00473         size_t ind = nodes[ i ]->getIndex();
00474         while ( ind >= _branch_duration_specs.size() ) {
00475             _branch_duration_specs.push_back( DurationSpec( _duration_sec ) );
00476         }
00477         SGPropertyNode_ptr rNode = nodes[ i ]->getChild("random");
00478         if ( rNode == 0 ) {
00479             _branch_duration_specs[ ind ] = DurationSpec( nodes[ i ]->getDoubleValue() );
00480         } else {
00481             _branch_duration_specs[ ind ] = DurationSpec( rNode->getDoubleValue( "min", 0.0 ),
00482                                                           rNode->getDoubleValue( "max", 1.0 ) );
00483         }
00484     }
00485 }
00486 
00487 SGTimedAnimation::~SGTimedAnimation ()
00488 {
00489 }
00490 
00491 void
00492 SGTimedAnimation::init()
00493 {
00494     if ( !_use_personality ) {
00495         for ( int i = 0; i < getBranch()->getNumKids(); i++ ) {
00496             double v;
00497             if ( i < (int)_branch_duration_specs.size() ) {
00498                 DurationSpec &sp = _branch_duration_specs[ i ];
00499                 v = sp._min + sg_random() * ( sp._max - sp._min );
00500             } else {
00501                 v = _duration_sec;
00502             }
00503             _branch_duration_sec.push_back( v );
00504             _total_duration_sec += v;
00505         }
00506         // Sanity check : total duration shouldn't equal zero
00507         if ( _total_duration_sec < 0.01 ) {
00508             _total_duration_sec = 0.01;
00509         }
00510     }
00511     ((ssgSelector *)getBranch())->selectStep(_step);
00512 }
00513 
00514 int
00515 SGTimedAnimation::update()
00516 {
00517     if ( _use_personality && current_object ) {
00518         SGPersonalityBranch *key = current_object;
00519         if ( !key->getIntValue( this, INIT_TIMED ) ) {
00520             double total = 0;
00521             double offset = 1.0;
00522             for ( size_t i = 0; i < _branch_duration_specs.size(); i++ ) {
00523                 DurationSpec &sp = _branch_duration_specs[ i ];
00524                 double v = sp._min + sg_random() * ( sp._max - sp._min );
00525                 key->setDoubleValue( v, this, BRANCH_DURATION_SEC_TIMED, i );
00526                 if ( i == 0 )
00527                     offset = v;
00528                 total += v;
00529             }
00530             // Sanity check : total duration shouldn't equal zero
00531             if ( total < 0.01 ) {
00532                 total = 0.01;
00533             }
00534             offset *= sg_random();
00535             key->setDoubleValue( sim_time_sec - offset, this, LAST_TIME_SEC_TIMED );
00536             key->setDoubleValue( total, this, TOTAL_DURATION_SEC_TIMED );
00537             key->setIntValue( 0, this, STEP_TIMED );
00538             key->setIntValue( 1, this, INIT_TIMED );
00539         }
00540 
00541         _step = key->getIntValue( this, STEP_TIMED );
00542         _last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC_TIMED );
00543         _total_duration_sec = key->getDoubleValue( this, TOTAL_DURATION_SEC_TIMED );
00544         while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
00545             _last_time_sec += _total_duration_sec;
00546         }
00547         double duration = _duration_sec;
00548         if ( _step < (int)_branch_duration_specs.size() ) {
00549             duration = key->getDoubleValue( this, BRANCH_DURATION_SEC_TIMED, _step );
00550         }
00551         if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
00552             _last_time_sec += duration;
00553             _step += 1;
00554             if ( _step >= getBranch()->getNumKids() )
00555                 _step = 0;
00556         }
00557         ((ssgSelector *)getBranch())->selectStep( _step );
00558         key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC_TIMED );
00559         key->setIntValue( _step, this, STEP_TIMED );
00560     } else {
00561         while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
00562             _last_time_sec += _total_duration_sec;
00563         }
00564         double duration = _duration_sec;
00565         if ( _step < (int)_branch_duration_sec.size() ) {
00566             duration = _branch_duration_sec[ _step ];
00567         }
00568         if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
00569             _last_time_sec += duration;
00570             _step += 1;
00571             if ( _step >= getBranch()->getNumKids() )
00572                 _step = 0;
00573             ((ssgSelector *)getBranch())->selectStep( _step );
00574         }
00575     }
00576     return 1;
00577 }
00578 
00579 
00580 
00582 // Implementation of SGRotateAnimation
00584 
00585 SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
00586                                   SGPropertyNode_ptr props )
00587     : SGAnimation(props, new ssgTransform),
00588       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
00589       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
00590       _factor(props->getDoubleValue("factor", 1.0)),
00591       _table(read_interpolation_table(props)),
00592       _has_min(props->hasValue("min-deg")),
00593       _min_deg(props->getDoubleValue("min-deg")),
00594       _has_max(props->hasValue("max-deg")),
00595       _max_deg(props->getDoubleValue("max-deg")),
00596       _position_deg(props->getDoubleValue("starting-position-deg", 0)),
00597       _condition(0)
00598 {
00599     SGPropertyNode_ptr node = props->getChild("condition");
00600     if (node != 0)
00601       _condition = sgReadCondition(prop_root, node);
00602 
00603     _center[0] = 0;
00604     _center[1] = 0;
00605     _center[2] = 0;
00606     if (props->hasValue("axis/x") || props->hasValue("axis/y") || props->hasValue("axis/z")) {
00607        _axis[0] = props->getFloatValue("axis/x", 0);
00608        _axis[1] = props->getFloatValue("axis/y", 0);
00609        _axis[2] = props->getFloatValue("axis/z", 0);
00610     } else {
00611         double x1,y1,z1,x2,y2,z2;
00612         x1 = props->getFloatValue("axis/x1-m", 0);
00613         y1 = props->getFloatValue("axis/y1-m", 0);
00614         z1 = props->getFloatValue("axis/z1-m", 0);
00615         x2 = props->getFloatValue("axis/x2-m", 0);
00616         y2 = props->getFloatValue("axis/y2-m", 0);
00617         z2 = props->getFloatValue("axis/z2-m", 0);
00618         _center[0] = (x1+x2)/2;
00619         _center[1]= (y1+y2)/2;
00620         _center[2] = (z1+z2)/2;
00621         float vector_length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1));
00622         _axis[0] = (x2-x1)/vector_length;
00623         _axis[1] = (y2-y1)/vector_length;
00624         _axis[2] = (z2-z1)/vector_length;
00625     }
00626     if (props->hasValue("center/x-m") || props->hasValue("center/y-m")
00627             || props->hasValue("center/z-m")) {
00628         _center[0] = props->getFloatValue("center/x-m", 0);
00629         _center[1] = props->getFloatValue("center/y-m", 0);
00630         _center[2] = props->getFloatValue("center/z-m", 0);
00631     }
00632     sgNormalizeVec3(_axis);
00633 }
00634 
00635 SGRotateAnimation::~SGRotateAnimation ()
00636 {
00637   delete _table;
00638   delete _condition;
00639 }
00640 
00641 int
00642 SGRotateAnimation::update()
00643 {
00644   if (_condition == 0 || _condition->test()) {
00645     if (_table == 0) {
00646       _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
00647       if (_has_min && _position_deg < _min_deg)
00648         _position_deg = _min_deg;
00649       if (_has_max && _position_deg > _max_deg)
00650         _position_deg = _max_deg;
00651     } else {
00652       _position_deg = _table->interpolate(_prop->getDoubleValue());
00653     }
00654     set_rotation(_matrix, _position_deg, _center, _axis);
00655     ((ssgTransform *)_branch)->setTransform(_matrix);
00656   }
00657   return 2;
00658 }
00659 
00660 
00662 // Implementation of SGBlendAnimation
00664 
00665 SGBlendAnimation::SGBlendAnimation( SGPropertyNode *prop_root,
00666                                         SGPropertyNode_ptr props )
00667   : SGAnimation(props, new ssgTransform),
00668     _use_personality( props->getBoolValue("use-personality",false) ),
00669     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
00670     _table(read_interpolation_table(props)),
00671     _prev_value(1.0),
00672     _offset(props,"offset",0.0),
00673     _factor(props,"factor",1.0),
00674     _has_min(props->hasValue("min")),
00675     _min(props->getDoubleValue("min", 0.0)),
00676     _has_max(props->hasValue("max")),
00677     _max(props->getDoubleValue("max", 1.0))
00678 {
00679 }
00680 
00681 SGBlendAnimation::~SGBlendAnimation ()
00682 {
00683     delete _table;
00684 }
00685 
00686 int
00687 SGBlendAnimation::update()
00688 {
00689   double _blend;
00690 
00691   if ( _use_personality && current_object ) {
00692     SGPersonalityBranch *key = current_object;
00693     if ( !key->getIntValue( this, INIT_BLEND ) ) {
00694       key->setDoubleValue( _factor.shuffle(), this, FACTOR_BLEND );
00695       key->setDoubleValue( _offset.shuffle(), this, OFFSET_BLEND );
00696 
00697       key->setIntValue( 1, this, INIT_BLEND );
00698     }
00699 
00700     _factor = key->getDoubleValue( this, FACTOR_BLEND );
00701     _offset = key->getDoubleValue( this, OFFSET_BLEND );
00702   }
00703 
00704   if (_table == 0) {
00705     _blend = 1.0 - (_prop->getDoubleValue() * _factor + _offset);
00706 
00707     if (_has_min && (_blend < _min))
00708       _blend = _min;
00709     if (_has_max && (_blend > _max))
00710       _blend = _max;
00711   } else {
00712     _blend = _table->interpolate(_prop->getDoubleValue());
00713   }
00714 
00715   if (_blend != _prev_value) {
00716     _prev_value = _blend;
00717     change_alpha( _branch, _blend );
00718   }
00719   return 1;
00720 }
00721 
00722 
00723 
00725 // Implementation of SGTranslateAnimation
00727 
00728 SGTranslateAnimation::SGTranslateAnimation( SGPropertyNode *prop_root,
00729                                         SGPropertyNode_ptr props )
00730   : SGAnimation(props, new ssgTransform),
00731     _use_personality( props->getBoolValue("use-personality",false) ),
00732     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
00733     _table(read_interpolation_table(props)),
00734     _has_min(props->hasValue("min-m")),
00735     _min_m(props->getDoubleValue("min-m")),
00736     _has_max(props->hasValue("max-m")),
00737     _max_m(props->getDoubleValue("max-m")),
00738     _position_m(props->getDoubleValue("starting-position-m", 0)),
00739     _condition(0),
00740     _factor( props, "factor", 1.0 ),
00741     _offset_m( props, "offset-m", 0.0 )
00742 {
00743   SGPropertyNode_ptr node = props->getChild("condition");
00744   if (node != 0)
00745     _condition = sgReadCondition(prop_root, node);
00746 
00747   _axis[0] = props->getFloatValue("axis/x", 0);
00748   _axis[1] = props->getFloatValue("axis/y", 0);
00749   _axis[2] = props->getFloatValue("axis/z", 0);
00750   sgNormalizeVec3(_axis);
00751 }
00752 
00753 SGTranslateAnimation::~SGTranslateAnimation ()
00754 {
00755   delete _table;
00756   delete _condition;
00757 }
00758 
00759 int
00760 SGTranslateAnimation::update()
00761 {
00762   if (_condition == 0 || _condition->test()) {
00763     if ( _use_personality && current_object ) {
00764       SGPersonalityBranch *key = current_object;
00765       if ( !key->getIntValue( this, INIT_TRANSLATE ) ) {
00766         key->setDoubleValue( _factor.shuffle(), this, FACTOR_TRANSLATE );
00767         key->setDoubleValue( _offset_m.shuffle(), this, OFFSET_TRANSLATE );
00768       }
00769 
00770       _factor = key->getDoubleValue( this, FACTOR_TRANSLATE );
00771       _offset_m = key->getDoubleValue( this, OFFSET_TRANSLATE );
00772 
00773       key->setIntValue( 1, this, INIT_TRANSLATE );
00774     }
00775 
00776     if (_table == 0) {
00777       _position_m = (_prop->getDoubleValue() * _factor) + _offset_m;
00778       if (_has_min && _position_m < _min_m)
00779         _position_m = _min_m;
00780       if (_has_max && _position_m > _max_m)
00781         _position_m = _max_m;
00782     } else {
00783       _position_m = _table->interpolate(_prop->getDoubleValue());
00784     }
00785 
00786     set_translation(_matrix, _position_m, _axis);
00787     ((ssgTransform *)_branch)->setTransform(_matrix);
00788   }
00789   return 2;
00790 }
00791 
00792 
00793 
00795 // Implementation of SGScaleAnimation
00797 
00798 SGScaleAnimation::SGScaleAnimation( SGPropertyNode *prop_root,
00799                                         SGPropertyNode_ptr props )
00800   : SGAnimation(props, new ssgTransform),
00801     _use_personality( props->getBoolValue("use-personality",false) ),
00802     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
00803     _x_factor(props,"x-factor",1.0),
00804     _y_factor(props,"y-factor",1.0),
00805     _z_factor(props,"z-factor",1.0),
00806     _x_offset(props,"x-offset",0.0),
00807     _y_offset(props,"y-offset",0.0),
00808     _z_offset(props,"z-offset",0.0),
00809     _table(read_interpolation_table(props)),
00810     _has_min_x(props->hasValue("x-min")),
00811     _has_min_y(props->hasValue("y-min")),
00812     _has_min_z(props->hasValue("z-min")),
00813     _min_x(props->getDoubleValue("x-min")),
00814     _min_y(props->getDoubleValue("y-min")),
00815     _min_z(props->getDoubleValue("z-min")),
00816     _has_max_x(props->hasValue("x-max")),
00817     _has_max_y(props->hasValue("y-max")),
00818     _has_max_z(props->hasValue("z-max")),
00819     _max_x(props->getDoubleValue("x-max")),
00820     _max_y(props->getDoubleValue("y-max")),
00821     _max_z(props->getDoubleValue("z-max"))
00822 {
00823 }
00824 
00825 SGScaleAnimation::~SGScaleAnimation ()
00826 {
00827   delete _table;
00828 }
00829 
00830 int
00831 SGScaleAnimation::update()
00832 {
00833   if ( _use_personality && current_object ) {
00834     SGPersonalityBranch *key = current_object;
00835     if ( !key->getIntValue( this, INIT_SCALE ) ) {
00836       key->setDoubleValue( _x_factor.shuffle(), this, X_FACTOR_SCALE );
00837       key->setDoubleValue( _x_offset.shuffle(), this, X_OFFSET_SCALE );
00838       key->setDoubleValue( _y_factor.shuffle(), this, Y_FACTOR_SCALE );
00839       key->setDoubleValue( _y_offset.shuffle(), this, Y_OFFSET_SCALE );
00840       key->setDoubleValue( _z_factor.shuffle(), this, Z_FACTOR_SCALE );
00841       key->setDoubleValue( _z_offset.shuffle(), this, Z_OFFSET_SCALE );
00842 
00843       key->setIntValue( 1, this, INIT_SCALE );
00844     }
00845 
00846     _x_factor = key->getDoubleValue( this, X_FACTOR_SCALE );
00847     _x_offset = key->getDoubleValue( this, X_OFFSET_SCALE );
00848     _y_factor = key->getDoubleValue( this, Y_FACTOR_SCALE );
00849     _y_offset = key->getDoubleValue( this, Y_OFFSET_SCALE );
00850     _z_factor = key->getDoubleValue( this, Z_FACTOR_SCALE );
00851     _z_offset = key->getDoubleValue( this, Z_OFFSET_SCALE );
00852   }
00853 
00854   if (_table == 0) {
00855       _x_scale = _prop->getDoubleValue() * _x_factor + _x_offset;
00856     if (_has_min_x && _x_scale < _min_x)
00857       _x_scale = _min_x;
00858     if (_has_max_x && _x_scale > _max_x)
00859       _x_scale = _max_x;
00860   } else {
00861     _x_scale = _table->interpolate(_prop->getDoubleValue());
00862   }
00863 
00864   if (_table == 0) {
00865     _y_scale = _prop->getDoubleValue() * _y_factor + _y_offset;
00866     if (_has_min_y && _y_scale < _min_y)
00867       _y_scale = _min_y;
00868     if (_has_max_y && _y_scale > _max_y)
00869       _y_scale = _max_y;
00870   } else {
00871     _y_scale = _table->interpolate(_prop->getDoubleValue());
00872   }
00873 
00874   if (_table == 0) {
00875     _z_scale = _prop->getDoubleValue() * _z_factor + _z_offset;
00876     if (_has_min_z && _z_scale < _min_z)
00877       _z_scale = _min_z;
00878     if (_has_max_z && _z_scale > _max_z)
00879       _z_scale = _max_z;
00880   } else {
00881     _z_scale = _table->interpolate(_prop->getDoubleValue());
00882   }
00883 
00884   set_scale(_matrix, _x_scale, _y_scale, _z_scale );
00885   ((ssgTransform *)_branch)->setTransform(_matrix);
00886   return 2;
00887 }
00888 
00889 
00891 // Implementation of SGTexRotateAnimation
00893 
00894 SGTexRotateAnimation::SGTexRotateAnimation( SGPropertyNode *prop_root,
00895                                   SGPropertyNode_ptr props )
00896     : SGAnimation(props, new ssgTexTrans),
00897       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
00898       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
00899       _factor(props->getDoubleValue("factor", 1.0)),
00900       _table(read_interpolation_table(props)),
00901       _has_min(props->hasValue("min-deg")),
00902       _min_deg(props->getDoubleValue("min-deg")),
00903       _has_max(props->hasValue("max-deg")),
00904       _max_deg(props->getDoubleValue("max-deg")),
00905       _position_deg(props->getDoubleValue("starting-position-deg", 0)),
00906       _condition(0)
00907 {
00908   SGPropertyNode *node = props->getChild("condition");
00909   if (node != 0)
00910     _condition = sgReadCondition(prop_root, node);
00911 
00912   _center[0] = props->getFloatValue("center/x", 0);
00913   _center[1] = props->getFloatValue("center/y", 0);
00914   _center[2] = props->getFloatValue("center/z", 0);
00915   _axis[0] = props->getFloatValue("axis/x", 0);
00916   _axis[1] = props->getFloatValue("axis/y", 0);
00917   _axis[2] = props->getFloatValue("axis/z", 0);
00918   sgNormalizeVec3(_axis);
00919 }
00920 
00921 SGTexRotateAnimation::~SGTexRotateAnimation ()
00922 {
00923   delete _table;
00924   delete _condition;
00925 }
00926 
00927 int
00928 SGTexRotateAnimation::update()
00929 {
00930   if (_condition && !_condition->test())
00931     return 1;
00932 
00933   if (_table == 0) {
00934    _position_deg = _prop->getDoubleValue() * _factor + _offset_deg;
00935    if (_has_min && _position_deg < _min_deg)
00936      _position_deg = _min_deg;
00937    if (_has_max && _position_deg > _max_deg)
00938      _position_deg = _max_deg;
00939   } else {
00940     _position_deg = _table->interpolate(_prop->getDoubleValue());
00941   }
00942   set_rotation(_matrix, _position_deg, _center, _axis);
00943   ((ssgTexTrans *)_branch)->setTransform(_matrix);
00944   return 2;
00945 }
00946 
00947 
00949 // Implementation of SGTexTranslateAnimation
00951 
00952 SGTexTranslateAnimation::SGTexTranslateAnimation( SGPropertyNode *prop_root,
00953                                         SGPropertyNode_ptr props )
00954   : SGAnimation(props, new ssgTexTrans),
00955       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
00956     _offset(props->getDoubleValue("offset", 0.0)),
00957     _factor(props->getDoubleValue("factor", 1.0)),
00958     _step(props->getDoubleValue("step",0.0)),
00959     _scroll(props->getDoubleValue("scroll",0.0)),
00960     _table(read_interpolation_table(props)),
00961     _has_min(props->hasValue("min")),
00962     _min(props->getDoubleValue("min")),
00963     _has_max(props->hasValue("max")),
00964     _max(props->getDoubleValue("max")),
00965     _position(props->getDoubleValue("starting-position", 0)),
00966     _condition(0)
00967 {
00968   SGPropertyNode *node = props->getChild("condition");
00969   if (node != 0)
00970     _condition = sgReadCondition(prop_root, node);
00971 
00972   _axis[0] = props->getFloatValue("axis/x", 0);
00973   _axis[1] = props->getFloatValue("axis/y", 0);
00974   _axis[2] = props->getFloatValue("axis/z", 0);
00975   sgNormalizeVec3(_axis);
00976 }
00977 
00978 SGTexTranslateAnimation::~SGTexTranslateAnimation ()
00979 {
00980   delete _table;
00981   delete _condition;
00982 }
00983 
00984 int
00985 SGTexTranslateAnimation::update()
00986 {
00987   if (_condition && !_condition->test())
00988     return 1;
00989 
00990   if (_table == 0) {
00991     _position = (apply_mods(_prop->getDoubleValue(), _step, _scroll) + _offset) * _factor;
00992     if (_has_min && _position < _min)
00993       _position = _min;
00994     if (_has_max && _position > _max)
00995       _position = _max;
00996   } else {
00997     _position = _table->interpolate(apply_mods(_prop->getDoubleValue(), _step, _scroll));
00998   }
00999   set_translation(_matrix, _position, _axis);
01000   ((ssgTexTrans *)_branch)->setTransform(_matrix);
01001   return 2;
01002 }
01003 
01004 
01006 // Implementation of SGTexMultipleAnimation
01008 
01009 SGTexMultipleAnimation::SGTexMultipleAnimation( SGPropertyNode *prop_root,
01010                                         SGPropertyNode_ptr props )
01011   : SGAnimation(props, new ssgTexTrans),
01012       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true))
01013 {
01014   unsigned int i;
01015   // Load animations
01016   vector<SGPropertyNode_ptr> transform_nodes = props->getChildren("transform");
01017   _transform = new TexTransform [transform_nodes.size()];
01018   _num_transforms = 0;
01019   for (i = 0; i < transform_nodes.size(); i++) {
01020     SGPropertyNode_ptr transform_props = transform_nodes[i];
01021 
01022     if (!strcmp("textranslate",transform_props->getStringValue("subtype", 0))) {
01023 
01024       // transform is a translation
01025       _transform[i].subtype = 0;
01026 
01027       _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
01028 
01029       _transform[i].offset = transform_props->getDoubleValue("offset", 0.0);
01030       _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
01031       _transform[i].step = transform_props->getDoubleValue("step",0.0);
01032       _transform[i].scroll = transform_props->getDoubleValue("scroll",0.0);
01033       _transform[i].table = read_interpolation_table(transform_props);
01034       _transform[i].has_min = transform_props->hasValue("min");
01035       _transform[i].min = transform_props->getDoubleValue("min");
01036       _transform[i].has_max = transform_props->hasValue("max");
01037       _transform[i].max = transform_props->getDoubleValue("max");
01038       _transform[i].position = transform_props->getDoubleValue("starting-position", 0);
01039 
01040       _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
01041       _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
01042       _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
01043       sgNormalizeVec3(_transform[i].axis);
01044       _num_transforms++;
01045     } else if (!strcmp("texrotate",transform_nodes[i]->getStringValue("subtype", 0))) {
01046 
01047       // transform is a rotation
01048       _transform[i].subtype = 1;
01049 
01050       _transform[i].prop = (SGPropertyNode *)prop_root->getNode(transform_props->getStringValue("property", "/null"), true);
01051       _transform[i].offset = transform_props->getDoubleValue("offset-deg", 0.0);
01052       _transform[i].factor = transform_props->getDoubleValue("factor", 1.0);
01053       _transform[i].table = read_interpolation_table(transform_props);
01054       _transform[i].has_min = transform_props->hasValue("min-deg");
01055       _transform[i].min = transform_props->getDoubleValue("min-deg");
01056       _transform[i].has_max = transform_props->hasValue("max-deg");
01057       _transform[i].max = transform_props->getDoubleValue("max-deg");
01058       _transform[i].position = transform_props->getDoubleValue("starting-position-deg", 0);
01059 
01060       _transform[i].center[0] = transform_props->getFloatValue("center/x", 0);
01061       _transform[i].center[1] = transform_props->getFloatValue("center/y", 0);
01062       _transform[i].center[2] = transform_props->getFloatValue("center/z", 0);
01063       _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
01064       _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
01065       _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
01066       sgNormalizeVec3(_transform[i].axis);
01067       _num_transforms++;
01068     }
01069   }
01070 }
01071 
01072 SGTexMultipleAnimation::~SGTexMultipleAnimation ()
01073 {
01074    delete [] _transform;
01075 }
01076 
01077 int
01078 SGTexMultipleAnimation::update()
01079 {
01080   int i;
01081   sgMat4 tmatrix;
01082   sgMakeIdentMat4(tmatrix);
01083   for (i = 0; i < _num_transforms; i++) {
01084 
01085     if(_transform[i].subtype == 0) {
01086 
01087       // subtype 0 is translation
01088       if (_transform[i].table == 0) {
01089         _transform[i].position = (apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll) + _transform[i].offset) * _transform[i].factor;
01090         if (_transform[i].has_min && _transform[i].position < _transform[i].min)
01091           _transform[i].position = _transform[i].min;
01092         if (_transform[i].has_max && _transform[i].position > _transform[i].max)
01093           _transform[i].position = _transform[i].max;
01094       } else {
01095          _transform[i].position = _transform[i].table->interpolate(apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll));
01096       }
01097       set_translation(_transform[i].matrix, _transform[i].position, _transform[i].axis);
01098       sgPreMultMat4(tmatrix, _transform[i].matrix);
01099 
01100     } else if (_transform[i].subtype == 1) {
01101 
01102       // subtype 1 is rotation
01103 
01104       if (_transform[i].table == 0) {
01105         _transform[i].position = _transform[i].prop->getDoubleValue() * _transform[i].factor + _transform[i].offset;
01106         if (_transform[i].has_min && _transform[i].position < _transform[i].min)
01107          _transform[i].position = _transform[i].min;
01108        if (_transform[i].has_max && _transform[i].position > _transform[i].max)
01109          _transform[i].position = _transform[i].max;
01110      } else {
01111         _transform[i].position = _transform[i].table->interpolate(_transform[i].prop->getDoubleValue());
01112       }
01113       set_rotation(_transform[i].matrix, _transform[i].position, _transform[i].center, _transform[i].axis);
01114       sgPreMultMat4(tmatrix, _transform[i].matrix);
01115     }
01116   }
01117   ((ssgTexTrans *)_branch)->setTransform(tmatrix);
01118   return 2;
01119 }
01120 
01121 
01122 
01124 // Implementation of SGAlphaTestAnimation
01126 
01127 SGAlphaTestAnimation::SGAlphaTestAnimation(SGPropertyNode_ptr props)
01128   : SGAnimation(props, new ssgBranch)
01129 {
01130   _alpha_clamp = props->getFloatValue("alpha-factor", 0.0);
01131 }
01132 
01133 SGAlphaTestAnimation::~SGAlphaTestAnimation ()
01134 {
01135 }
01136 
01137 void SGAlphaTestAnimation::init()
01138 {
01139   setAlphaClampToBranch(_branch,_alpha_clamp);
01140 }
01141 
01142 void SGAlphaTestAnimation::setAlphaClampToBranch(ssgBranch *b, float clamp)
01143 {
01144   int nb = b->getNumKids();
01145   for (int i = 0; i<nb; i++) {
01146     ssgEntity *e = b->getKid(i);
01147     if (e->isAKindOf(ssgTypeLeaf())) {
01148       ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
01149       s->enable( GL_ALPHA_TEST );
01150       s->setAlphaClamp( clamp );
01151     } else if (e->isAKindOf(ssgTypeBranch())) {
01152       setAlphaClampToBranch( (ssgBranch*)e, clamp );
01153     }
01154   }
01155 }
01156 
01157 
01158 
01160 // Implementation of SGMaterialAnimation
01162 
01163 SGMaterialAnimation::SGMaterialAnimation( SGPropertyNode *prop_root,
01164         SGPropertyNode_ptr props, const SGPath &texture_path)
01165     : SGAnimation(props, new ssgBranch),
01166     _last_condition(false),
01167     _prop_root(prop_root),
01168     _prop_base(""),
01169     _texture_base(texture_path),
01170     _cached_material(0),
01171     _cloned_material(0),
01172     _read(0),
01173     _update(0),
01174     _global(props->getBoolValue("global", false))
01175 {
01176     SGPropertyNode_ptr n;
01177     n = props->getChild("condition");
01178     _condition = n ? sgReadCondition(_prop_root, n) : 0;
01179     n = props->getChild("property-base");
01180     if (n) {
01181         _prop_base = n->getStringValue();
01182         if (!_prop_base.empty() && _prop_base.end()[-1] != '/')
01183             _prop_base += '/';
01184     }
01185 
01186     initColorGroup(props->getChild("diffuse"), &_diff, DIFFUSE);
01187     initColorGroup(props->getChild("ambient"), &_amb, AMBIENT);
01188     initColorGroup(props->getChild("emission"), &_emis, EMISSION);
01189     initColorGroup(props->getChild("specular"), &_spec, SPECULAR);
01190 
01191     _shi = props->getFloatValue("shininess", -1.0);
01192     if (_shi >= 0.0)
01193         _update |= SHININESS;
01194 
01195     SGPropertyNode_ptr group = props->getChild("transparency");
01196     if (group) {
01197         _trans.value = group->getFloatValue("alpha", -1.0);
01198         _trans.factor = group->getFloatValue("factor", 1.0);
01199         _trans.offset = group->getFloatValue("offset", 0.0);
01200         _trans.min = group->getFloatValue("min", 0.0);
01201         if (_trans.min < 0.0)
01202             _trans.min = 0.0;
01203         _trans.max = group->getFloatValue("max", 1.0);
01204         if (_trans.max > 1.0)
01205             _trans.max = 1.0;
01206         if (_trans.dirty())
01207             _update |= TRANSPARENCY;
01208 
01209         n = group->getChild("alpha-prop");
01210         _trans.value_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
01211         n = group->getChild("factor-prop");
01212         _trans.factor_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
01213         n = group->getChild("offset-prop");
01214         _trans.offset_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
01215         if (_trans.live())
01216             _read |= TRANSPARENCY;
01217     }
01218 
01219     _thresh = props->getFloatValue("threshold", -1.0);
01220     if (_thresh >= 0.0)
01221         _update |= THRESHOLD;
01222 
01223     string _texture_str = props->getStringValue("texture", "");
01224     if (!_texture_str.empty()) {
01225         _texture = _texture_base;
01226         _texture.append(_texture_str);
01227         _update |= TEXTURE;
01228     }
01229 
01230     n = props->getChild("shininess-prop");
01231     _shi_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
01232     n = props->getChild("threshold-prop");
01233     _thresh_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
01234     n = props->getChild("texture-prop");
01235     _tex_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
01236 
01237     _static_update = _update;
01238 }
01239 
01240 SGMaterialAnimation::~SGMaterialAnimation()
01241 {
01242    delete _condition;
01243 }
01244 
01245 
01246 void SGMaterialAnimation::initColorGroup(SGPropertyNode_ptr group, ColorSpec *col, int flag)
01247 {
01248     if (!group)
01249         return;
01250 
01251     col->red = group->getFloatValue("red", -1.0);
01252     col->green = group->getFloatValue("green", -1.0);
01253     col->blue = group->getFloatValue("blue", -1.0);
01254     col->factor = group->getFloatValue("factor", 1.0);
01255     col->offset = group->getFloatValue("offset", 0.0);
01256     if (col->dirty())
01257         _update |= flag;
01258 
01259     SGPropertyNode *n;
01260     n = group->getChild("red-prop");
01261     col->red_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
01262     n = group->getChild("green-prop");
01263     col->green_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
01264     n = group->getChild("blue-prop");
01265     col->blue_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
01266     n = group->getChild("factor-prop");
01267     col->factor_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
01268     n = group->getChild("offset-prop");
01269     col->offset_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
01270     if (col->live())
01271         _read |= flag;
01272 }
01273 
01274 void SGMaterialAnimation::init()
01275 {
01276     if (!_global)
01277         cloneMaterials(_branch);
01278 }
01279 
01280 int SGMaterialAnimation::update()
01281 {
01282     if (_condition) {
01283         bool cond = _condition->test();
01284         if (cond && !_last_condition)
01285             _update |= _static_update;
01286 
01287         _last_condition = cond;
01288         if (!cond)
01289             return 2;
01290     }
01291 
01292     if (_read & DIFFUSE)
01293         updateColorGroup(&_diff, DIFFUSE);
01294     if (_read & AMBIENT)
01295         updateColorGroup(&_amb, AMBIENT);
01296     if (_read & EMISSION)
01297         updateColorGroup(&_emis, EMISSION);
01298     if (_read & SPECULAR)
01299         updateColorGroup(&_spec, SPECULAR);
01300 
01301     float f;
01302     if (_shi_prop) {
01303         f = _shi;
01304         _shi = _shi_prop->getFloatValue();
01305         if (_shi != f)
01306             _update |= SHININESS;
01307     }
01308     if (_read & TRANSPARENCY) {
01309         PropSpec tmp = _trans;
01310         if (_trans.value_prop)
01311             _trans.value = _trans.value_prop->getFloatValue();
01312         if (_trans.factor_prop)
01313             _trans.factor = _trans.factor_prop->getFloatValue();
01314         if (_trans.offset_prop)
01315             _trans.offset = _trans.offset_prop->getFloatValue();
01316         if (_trans != tmp)
01317             _update |= TRANSPARENCY;
01318     }
01319     if (_thresh_prop) {
01320         f = _thresh;
01321         _thresh = _thresh_prop->getFloatValue();
01322         if (_thresh != f)
01323             _update |= THRESHOLD;
01324     }
01325     if (_tex_prop) {
01326         string t = _tex_prop->getStringValue();
01327         if (!t.empty() && t != _texture_str) {
01328             _texture_str = t;
01329             _texture = _texture_base;
01330             _texture.append(t);
01331             _update |= TEXTURE;
01332         }
01333     }
01334     if (_update) {
01335         setMaterialBranch(_branch);
01336         _update = 0;
01337     }
01338     return 2;
01339 }
01340 
01341 void SGMaterialAnimation::updateColorGroup(ColorSpec *col, int flag)
01342 {
01343     ColorSpec tmp = *col;
01344     if (col->red_prop)
01345         col->red = col->red_prop->getFloatValue();
01346     if (col->green_prop)
01347         col->green = col->green_prop->getFloatValue();
01348     if (col->blue_prop)
01349         col->blue = col->blue_prop->getFloatValue();
01350     if (col->factor_prop)
01351         col->factor = col->factor_prop->getFloatValue();
01352     if (col->offset_prop)
01353         col->offset = col->offset_prop->getFloatValue();
01354     if (*col != tmp)
01355         _update |= flag;
01356 }
01357 
01358 void SGMaterialAnimation::cloneMaterials(ssgBranch *b)
01359 {
01360     for (int i = 0; i < b->getNumKids(); i++)
01361         cloneMaterials((ssgBranch *)b->getKid(i));
01362 
01363     if (!b->isAKindOf(ssgTypeLeaf()) || !((ssgLeaf *)b)->hasState())
01364         return;
01365 
01366     ssgSimpleState *s = (ssgSimpleState *)((ssgLeaf *)b)->getState();
01367     if (!_cached_material || _cached_material != s) {
01368         _cached_material = s;
01369         _cloned_material = (ssgSimpleState *)s->clone(SSG_CLONE_STATE);
01370     }
01371     ((ssgLeaf *)b)->setState(_cloned_material)