diff --git a/simgear/scene/model/animation.cxx b/simgear/scene/model/animation.cxx index 6ced0858..317df8e1 100644 --- a/simgear/scene/model/animation.cxx +++ b/simgear/scene/model/animation.cxx @@ -14,6 +14,7 @@ #include #include #include +#include #include "animation.hxx" #include "flash.hxx" @@ -174,6 +175,7 @@ read_interpolation_table (SGPropertyNode_ptr props) // Initialize the static data member double SGAnimation::sim_time_sec = 0.0; +ssgBranch *SGAnimation::current_object = 0; SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch) : _branch(branch) @@ -225,12 +227,16 @@ SGNullAnimation::~SGNullAnimation () SGRangeAnimation::SGRangeAnimation (SGPropertyNode *prop_root, SGPropertyNode_ptr props) : SGAnimation(props, new ssgRangeSelector), - _min(0.0), _max(0.0), _min_factor(1.0), _max_factor(1.0) - + _min(0.0), _max(0.0), _min_factor(1.0), _max_factor(1.0), + _condition(0) { + SGPropertyNode_ptr node = props->getChild("condition"); + if (node != 0) + _condition = sgReadCondition(prop_root, node); + float ranges[2]; - SGPropertyNode_ptr node = props->getChild( "min-factor" ); + node = props->getChild( "min-factor" ); if (node != 0) { _min_factor = props->getFloatValue("min-factor", 1.0); } @@ -264,23 +270,23 @@ SGRangeAnimation::~SGRangeAnimation () int SGRangeAnimation::update() { - float ranges[2]; - bool upd = false; + float ranges[2]; + if ( _condition == 0 || _condition->test() ) { if (_min_prop != 0) { - ranges[0] = _min_prop->getFloatValue() * _min_factor; - upd = true; + ranges[0] = _min_prop->getFloatValue() * _min_factor; } else { - ranges[0] = _min * _min_factor; + ranges[0] = _min * _min_factor; } if (_max_prop != 0) { - ranges[1] = _max_prop->getFloatValue() * _max_factor; - upd = true; + ranges[1] = _max_prop->getFloatValue() * _max_factor; } else { - ranges[1] = _max * _max_factor; - } - if (upd) { - ((ssgRangeSelector *)_branch)->setRanges(ranges, 2); + ranges[1] = _max * _max_factor; } + } else { + ranges[0] = 0.f; + ranges[1] = 1000000000.f; + } + ((ssgRangeSelector *)_branch)->setRanges(ranges, 2); return 1; } @@ -343,8 +349,13 @@ SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root, _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)), _factor(props->getDoubleValue("factor", 1.0)), _position_deg(props->getDoubleValue("starting-position-deg", 0)), - _last_time_sec( sim_time_sec ) + _last_time_sec( sim_time_sec ), + _condition(0) { + SGPropertyNode_ptr node = props->getChild("condition"); + if (node != 0) + _condition = sgReadCondition(prop_root, node); + _center[0] = 0; _center[1] = 0; _center[2] = 0; @@ -383,17 +394,19 @@ SGSpinAnimation::~SGSpinAnimation () int SGSpinAnimation::update() { - double dt = sim_time_sec - _last_time_sec; - _last_time_sec = sim_time_sec; + if ( _condition == 0 || _condition->test() ) { + double dt = sim_time_sec - _last_time_sec; + _last_time_sec = sim_time_sec; - float velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0); - _position_deg += (dt * velocity_rpms * 360); - while (_position_deg < 0) - _position_deg += 360.0; - while (_position_deg >= 360.0) - _position_deg -= 360.0; - set_rotation(_matrix, _position_deg, _center, _axis); - ((ssgTransform *)_branch)->setTransform(_matrix); + float velocity_rpms = (_prop->getDoubleValue() * _factor / 60.0); + _position_deg += (dt * velocity_rpms * 360); + while (_position_deg < 0) + _position_deg += 360.0; + while (_position_deg >= 360.0) + _position_deg -= 360.0; + set_rotation(_matrix, _position_deg, _center, _axis); + ((ssgTransform *)_branch)->setTransform(_matrix); + } return 1; } @@ -406,9 +419,25 @@ SGSpinAnimation::update() SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props) : SGAnimation(props, new ssgSelector), _duration_sec(props->getDoubleValue("duration-sec", 1.0)), - _last_time_sec(0), - _step(-1) + _step( 0 ), + _use_personality( props->getBoolValue("use-personality",false) ) { + vector nodes = props->getChildren( "branch-duration-sec" ); + size_t nb = nodes.size(); + for ( size_t i = 0; i < nb; i++ ) { + size_t ind = nodes[ i ]->getIndex(); + while ( ind >= _branch_duration_specs.size() ) { + _branch_duration_specs.push_back( DurationSpec( _duration_sec ) ); + } + SGPropertyNode_ptr rNode = nodes[ i ]->getChild("random"); + if ( rNode == 0 ) { + _branch_duration_specs[ ind ] = DurationSpec( nodes[ i ]->getDoubleValue() ); + } else { + _branch_duration_specs[ ind ] = DurationSpec( rNode->getDoubleValue( "min", 0.0 ), + rNode->getDoubleValue( "max", 1.0 ) ); + } + } + ((ssgSelector *)getBranch())->selectStep(_step); } SGTimedAnimation::~SGTimedAnimation () @@ -418,14 +447,37 @@ SGTimedAnimation::~SGTimedAnimation () int SGTimedAnimation::update() { - if ((sim_time_sec - _last_time_sec) >= _duration_sec) { - _last_time_sec = sim_time_sec; - _step++; - if (_step >= getBranch()->getNumKids()) - _step = 0; - ((ssgSelector *)getBranch())->selectStep(_step); + ssgBranch *key = ( _use_personality ? current_object : 0 ); + PersonalityMap::iterator it = _branch_duration_sec.find( key ); + if ( it == _branch_duration_sec.end() ) { + vector durations; + double total = 0; + for ( size_t i = 0; i < _branch_duration_specs.size(); i++ ) { + DurationSpec &sp = _branch_duration_specs[ i ]; + double v = sp._min + sg_random() * ( sp._max - sp._min ); + durations.push_back( v ); + total += v; + } + it = _branch_duration_sec.insert( PersonalityMap::value_type( key, durations ) ).first; + _last_time_sec[ key ] = sim_time_sec; + _total_duration_sec[ key ] = total; } - return 1; + + while ( ( sim_time_sec - _last_time_sec[ key ] ) >= _total_duration_sec[ key ] ) { + _last_time_sec[ key ] += _total_duration_sec[ key ]; + } + double duration = _duration_sec; + if ( _step < (int)it->second.size() ) { + duration = it->second[ _step ]; + } + if ( ( sim_time_sec - _last_time_sec[ key ] ) >= duration ) { + _last_time_sec[ key ] += duration; + _step += 1; + if ( _step >= getBranch()->getNumKids() ) + _step = 0; + ((ssgSelector *)getBranch())->selectStep( _step ); + } + return 1; } @@ -445,8 +497,13 @@ SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root, _min_deg(props->getDoubleValue("min-deg")), _has_max(props->hasValue("max-deg")), _max_deg(props->getDoubleValue("max-deg")), - _position_deg(props->getDoubleValue("starting-position-deg", 0)) + _position_deg(props->getDoubleValue("starting-position-deg", 0)), + _condition(0) { + SGPropertyNode_ptr node = props->getChild("condition"); + if (node != 0) + _condition = sgReadCondition(prop_root, node); + _center[0] = 0; _center[1] = 0; _center[2] = 0; @@ -486,17 +543,19 @@ SGRotateAnimation::~SGRotateAnimation () int SGRotateAnimation::update() { - if (_table == 0) { - _position_deg = _prop->getDoubleValue() * _factor + _offset_deg; - if (_has_min && _position_deg < _min_deg) - _position_deg = _min_deg; - if (_has_max && _position_deg > _max_deg) - _position_deg = _max_deg; - } else { - _position_deg = _table->interpolate(_prop->getDoubleValue()); + if (_condition == 0 || _condition->test()) { + if (_table == 0) { + _position_deg = _prop->getDoubleValue() * _factor + _offset_deg; + if (_has_min && _position_deg < _min_deg) + _position_deg = _min_deg; + if (_has_max && _position_deg > _max_deg) + _position_deg = _max_deg; + } else { + _position_deg = _table->interpolate(_prop->getDoubleValue()); + } + set_rotation(_matrix, _position_deg, _center, _axis); + ((ssgTransform *)_branch)->setTransform(_matrix); } - set_rotation(_matrix, _position_deg, _center, _axis); - ((ssgTransform *)_branch)->setTransform(_matrix); return 1; } @@ -565,8 +624,13 @@ SGTranslateAnimation::SGTranslateAnimation( SGPropertyNode *prop_root, _min_m(props->getDoubleValue("min-m")), _has_max(props->hasValue("max-m")), _max_m(props->getDoubleValue("max-m")), - _position_m(props->getDoubleValue("starting-position-m", 0)) + _position_m(props->getDoubleValue("starting-position-m", 0)), + _condition(0) { + SGPropertyNode_ptr node = props->getChild("condition"); + if (node != 0) + _condition = sgReadCondition(prop_root, node); + _axis[0] = props->getFloatValue("axis/x", 0); _axis[1] = props->getFloatValue("axis/y", 0); _axis[2] = props->getFloatValue("axis/z", 0); @@ -581,17 +645,19 @@ SGTranslateAnimation::~SGTranslateAnimation () int SGTranslateAnimation::update() { - if (_table == 0) { - _position_m = (_prop->getDoubleValue() + _offset_m) * _factor; - if (_has_min && _position_m < _min_m) - _position_m = _min_m; - if (_has_max && _position_m > _max_m) - _position_m = _max_m; - } else { - _position_m = _table->interpolate(_prop->getDoubleValue()); + if (_condition == 0 || _condition->test()) { + if (_table == 0) { + _position_m = (_prop->getDoubleValue() + _offset_m) * _factor; + if (_has_min && _position_m < _min_m) + _position_m = _min_m; + if (_has_max && _position_m > _max_m) + _position_m = _max_m; + } else { + _position_m = _table->interpolate(_prop->getDoubleValue()); + } + set_translation(_matrix, _position_m, _axis); + ((ssgTransform *)_branch)->setTransform(_matrix); } - set_translation(_matrix, _position_m, _axis); - ((ssgTransform *)_branch)->setTransform(_matrix); return 1; } diff --git a/simgear/scene/model/animation.hxx b/simgear/scene/model/animation.hxx index 76259c98..cac47686 100644 --- a/simgear/scene/model/animation.hxx +++ b/simgear/scene/model/animation.hxx @@ -12,8 +12,10 @@ #endif #include +#include SG_USING_STD(vector); +SG_USING_STD(map); #include #include @@ -78,6 +80,12 @@ public: */ static void set_sim_time_sec( double val ) { sim_time_sec = val; } + /** + * Current personality branch : enable animation to behave differently + * for similar objects + */ + static ssgBranch *current_object; + protected: static double sim_time_sec; @@ -115,6 +123,7 @@ private: float _max; float _min_factor; float _max_factor; + SGCondition * _condition; }; @@ -165,6 +174,7 @@ private: sgMat4 _matrix; sgVec3 _center; sgVec3 _axis; + SGCondition * _condition; }; @@ -179,8 +189,18 @@ public: virtual int update(); private: double _duration_sec; - double _last_time_sec; + map _last_time_sec; + map _total_duration_sec; int _step; + struct DurationSpec { + DurationSpec( double m = 0.0 ) : _min(m), _max(m) {} + DurationSpec( double m1, double m2 ) : _min(m1), _max(m2) {} + double _min, _max; + }; + vector _branch_duration_specs; + bool _use_personality; + typedef map > PersonalityMap; + PersonalityMap _branch_duration_sec; }; @@ -208,6 +228,7 @@ private: sgMat4 _matrix; sgVec3 _center; sgVec3 _axis; + SGCondition * _condition; }; @@ -233,6 +254,7 @@ private: double _position_m; sgMat4 _matrix; sgVec3 _axis; + SGCondition * _condition; }; /** diff --git a/simgear/scene/model/flash.cxx b/simgear/scene/model/flash.cxx index 9e75421d..67a2ec52 100755 --- a/simgear/scene/model/flash.cxx +++ b/simgear/scene/model/flash.cxx @@ -74,7 +74,11 @@ void SGFlash::cull( sgFrustum *f, sgMat4 m, int test_needed ) sgXformVec3( transformed_axis, _axis, m ); sgNormalizeVec3( transformed_axis ); - float cos_angle = transformed_axis[ 2 ]; // z component, through the screen + sgVec3 view; + sgFullXformPnt3( view, _center, m ); + sgNormalizeVec3( view ); + + float cos_angle = -sgScalarProductVec3( transformed_axis, view ); float scale_factor = 0.f; if ( _two_sides && cos_angle < 0 ) scale_factor = _factor * (float)pow( -cos_angle, _power ) + _offset; diff --git a/simgear/scene/model/flash.hxx b/simgear/scene/model/flash.hxx index f94fef03..3ca3b6fe 100755 --- a/simgear/scene/model/flash.hxx +++ b/simgear/scene/model/flash.hxx @@ -1,3 +1,6 @@ +/** + * $Id$ + */ class SGFlash : public ssgBranch { diff --git a/simgear/scene/model/modellib.cxx b/simgear/scene/model/modellib.cxx index 3d3edd1b..8733f448 100644 --- a/simgear/scene/model/modellib.cxx +++ b/simgear/scene/model/modellib.cxx @@ -4,6 +4,7 @@ #include #include "model.hxx" +#include "animation.hxx" #include "modellib.hxx" @@ -60,6 +61,25 @@ SGModelLib::flush1() } } +struct SGPersonalityBranch : public ssgBranch { + ssgBranch *_old_current; +}; + +static int +personality_pretrav_callback(ssgEntity * entity, int mask) +{ + ((SGPersonalityBranch *)entity)->_old_current = SGAnimation::current_object; + SGAnimation::current_object = (ssgBranch *)entity; + return 1; +} + +static int +personality_posttrav_callback(ssgEntity * entity, int mask) +{ + SGAnimation::current_object = ((SGPersonalityBranch *)entity)->_old_current; + ((SGPersonalityBranch *)entity)->_old_current = 0; + return 1; +} ssgEntity * SGModelLib::load_model( const string &fg_root, @@ -67,6 +87,10 @@ SGModelLib::load_model( const string &fg_root, SGPropertyNode *prop_root, double sim_time_sec ) { + ssgBranch *personality_branch = new SGPersonalityBranch; + personality_branch->setTravCallback(SSG_CALLBACK_PRETRAV, personality_pretrav_callback); + personality_branch->setTravCallback(SSG_CALLBACK_POSTTRAV, personality_posttrav_callback); + // FIXME: normalize path to // avoid duplicates. map::iterator it = _table.find(path); @@ -75,10 +99,11 @@ SGModelLib::load_model( const string &fg_root, sim_time_sec ); model->ref(); _table[path] = model; // add one reference to keep it around - return model; + personality_branch->addKid( model ); } else { - return (ssgEntity *)it->second; + personality_branch->addKid( (ssgEntity *)it->second ); } + return personality_branch; }