//
// This file is in the Public Domain, and comes with no warranty.
+#ifdef HAVE_CONFIG_H
+# include <simgear_config.h>
+#endif
#include <string.h> // for strcmp()
#include <math.h>
#include <simgear/math/interpolater.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/props/props.hxx>
+#include <simgear/math/sg_random.h>
#include "animation.hxx"
-
+#include "custtrans.hxx"
+#include "personality.hxx"
\f
////////////////////////////////////////////////////////////////////////
return;
int num_colors = ((ssgLeaf *)_branch)->getNumColours();
+// unsigned int select_ = (_blend == 1.0) ? false : true;
- if ( _blend == 1.0 ) { // fully translucent.
- for (i = 0; i < num_colors; i++)
- ((ssgSelector *)_branch)->select(0x0000); // deselect item.
- } else {
- for (i = 0; i < num_colors; i++)
- {
- ((ssgSelector *)_branch)->select(0xffff);
- float *color = ((ssgLeaf *)_branch)->getColour(i);
- color[3] = _blend;
- }
+ for (i = 0; i < num_colors; i++)
+ {
+// ((ssgSelector *)_branch)->select( select_ );
+ float *color = ((ssgLeaf *)_branch)->getColour(i);
+ color[3] = _blend;
}
}
// Initialize the static data member
double SGAnimation::sim_time_sec = 0.0;
+SGPersonalityBranch *SGAnimation::current_object = 0;
SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch)
- : _branch(branch)
+ : _branch(branch),
+ animation_type(0)
{
_branch->setName(props->getStringValue("name", 0));
+ if ( props->getBoolValue( "enable-hot", true ) ) {
+ _branch->setTraversalMaskBits( SSGTRAV_HOT );
+ } else {
+ _branch->clrTraversalMaskBits( SSGTRAV_HOT );
+ }
}
SGAnimation::~SGAnimation ()
{
}
-void
+int
SGAnimation::update()
+{
+ return 1;
+}
+
+void
+SGAnimation::restore()
{
}
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);
}
{
}
-void
+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 2;
}
delete _condition;
}
-void
+int
SGSelectAnimation::update()
{
if (_condition != 0 && _condition->test())
((ssgSelector *)_branch)->select(0xffff);
else
((ssgSelector *)_branch)->select(0x0000);
+ return 2;
}
SGPropertyNode_ptr props,
double sim_time_sec )
: SGAnimation(props, new ssgTransform),
+ _use_personality( props->getBoolValue("use-personality",false) ),
_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;
_center[2] = props->getFloatValue("center/z-m", 0);
}
sgNormalizeVec3(_axis);
+
+ //_factor(props->getDoubleValue("factor", 1.0)),
+ _factor = 1.0;
+ _factor_min = 1.0;
+ _factor_max = 1.0;
+ SGPropertyNode_ptr factor_n = props->getNode( "factor" );
+ if ( factor_n != 0 ) {
+ SGPropertyNode_ptr rand_n = factor_n->getNode( "random" );
+ if ( rand_n != 0 ) {
+ _factor_min = rand_n->getDoubleValue( "min", 0.0 );
+ _factor_max = rand_n->getDoubleValue( "max", 1.0 );
+ _factor = _factor_min + sg_random() * ( _factor_max - _factor_min );
+ } else {
+ _factor = _factor_min = _factor_max = props->getDoubleValue("factor", 1.0);
+ }
+ }
+ //_position_deg(props->getDoubleValue("starting-position-deg", 0)),
+ _position_deg = 0.0;
+ _position_deg_min = 0.0;
+ _position_deg_max = 0.0;
+ SGPropertyNode_ptr position_deg_n = props->getNode( "starting-position-deg" );
+ if ( position_deg_n != 0 ) {
+ SGPropertyNode_ptr rand_n = position_deg_n->getNode( "random" );
+ if ( rand_n != 0 ) {
+ _position_deg_min = rand_n->getDoubleValue( "min", 0.0 );
+ _position_deg_max = rand_n->getDoubleValue( "max", 1.0 );
+ _position_deg = _position_deg_min + sg_random() * ( _position_deg_max - _position_deg_min );
+ } else {
+ _position_deg = _position_deg_min = _position_deg_max =
+ props->getDoubleValue("starting-position-deg", 1.0);
+ }
+ }
}
SGSpinAnimation::~SGSpinAnimation ()
{
}
-void
+int
SGSpinAnimation::update()
{
- double dt = sim_time_sec - _last_time_sec;
- _last_time_sec = sim_time_sec;
+ if ( _condition == 0 || _condition->test() ) {
+ double dt;
+ float velocity_rpms;
+ if ( _use_personality ) {
+ SGPersonalityBranch *key = current_object;
+ if ( !key->getIntValue( this, INIT_SPIN ) ) {
+ double v = _factor_min + sg_random() * ( _factor_max - _factor_min );
+ key->setDoubleValue( v, this, FACTOR_SPIN );
+
+ key->setDoubleValue( sim_time_sec, this, LAST_TIME_SEC_SPIN );
+ key->setIntValue( 1, this, INIT_SPIN );
+
+ v = _position_deg_min + sg_random() * ( _position_deg_max - _position_deg_min );
+ key->setDoubleValue( v, this, POSITION_DEG_SPIN );
+ }
- 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);
+ _factor = key->getDoubleValue( this, FACTOR_SPIN );
+ _position_deg = key->getDoubleValue( this, POSITION_DEG_SPIN );
+ _last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC_SPIN );
+ dt = sim_time_sec - _last_time_sec;
+ _last_time_sec = sim_time_sec;
+ key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC_SPIN );
+
+ 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;
+ key->setDoubleValue( _position_deg, this, POSITION_DEG_SPIN );
+ } else {
+ dt = sim_time_sec - _last_time_sec;
+ _last_time_sec = sim_time_sec;
+
+ 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;
}
SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
: SGAnimation(props, new ssgSelector),
+ _use_personality( props->getBoolValue("use-personality",false) ),
_duration_sec(props->getDoubleValue("duration-sec", 1.0)),
- _last_time_sec(0),
- _step(-1)
+ _last_time_sec( sim_time_sec ),
+ _total_duration_sec( 0 ),
+ _step( 0 )
+
{
+ vector<SGPropertyNode_ptr> 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 ) );
+ }
+ }
}
SGTimedAnimation::~SGTimedAnimation ()
}
void
+SGTimedAnimation::init()
+{
+ if ( !_use_personality ) {
+ for ( int i = 0; i < getBranch()->getNumKids(); i++ ) {
+ double v;
+ if ( i < (int)_branch_duration_specs.size() ) {
+ DurationSpec &sp = _branch_duration_specs[ i ];
+ v = sp._min + sg_random() * ( sp._max - sp._min );
+ } else {
+ v = _duration_sec;
+ }
+ _branch_duration_sec.push_back( v );
+ _total_duration_sec += v;
+ }
+ // Sanity check : total duration shouldn't equal zero
+ if ( _total_duration_sec < 0.01 ) {
+ _total_duration_sec = 0.01;
+ }
+ }
+ ((ssgSelector *)getBranch())->selectStep(_step);
+}
+
+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);
+ if ( _use_personality ) {
+ SGPersonalityBranch *key = current_object;
+ if ( !key->getIntValue( this, INIT_TIMED ) ) {
+ double total = 0;
+ double offset = 1.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 );
+ key->setDoubleValue( v, this, BRANCH_DURATION_SEC_TIMED, i );
+ if ( i == 0 )
+ offset = v;
+ total += v;
+ }
+ // Sanity check : total duration shouldn't equal zero
+ if ( total < 0.01 ) {
+ total = 0.01;
+ }
+ offset *= sg_random();
+ key->setDoubleValue( sim_time_sec - offset, this, LAST_TIME_SEC_TIMED );
+ key->setDoubleValue( total, this, TOTAL_DURATION_SEC_TIMED );
+ key->setIntValue( 0, this, STEP_TIMED );
+ key->setIntValue( 1, this, INIT_TIMED );
+ }
+
+ _step = key->getIntValue( this, STEP_TIMED );
+ _last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC_TIMED );
+ _total_duration_sec = key->getDoubleValue( this, TOTAL_DURATION_SEC_TIMED );
+ while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
+ _last_time_sec += _total_duration_sec;
+ }
+ double duration = _duration_sec;
+ if ( _step < (int)_branch_duration_specs.size() ) {
+ duration = key->getDoubleValue( this, BRANCH_DURATION_SEC_TIMED, _step );
+ }
+ if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
+ _last_time_sec += duration;
+ _step += 1;
+ if ( _step >= getBranch()->getNumKids() )
+ _step = 0;
+ }
+ ((ssgSelector *)getBranch())->selectStep( _step );
+ key->setDoubleValue( _last_time_sec, this, LAST_TIME_SEC_TIMED );
+ key->setIntValue( _step, this, STEP_TIMED );
+ } else {
+ while ( ( sim_time_sec - _last_time_sec ) >= _total_duration_sec ) {
+ _last_time_sec += _total_duration_sec;
+ }
+ double duration = _duration_sec;
+ if ( _step < (int)_branch_duration_sec.size() ) {
+ duration = _branch_duration_sec[ _step ];
+ }
+ if ( ( sim_time_sec - _last_time_sec ) >= duration ) {
+ _last_time_sec += duration;
+ _step += 1;
+ if ( _step >= getBranch()->getNumKids() )
+ _step = 0;
+ ((ssgSelector *)getBranch())->selectStep( _step );
+ }
}
+ return 1;
}
_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;
- if (props->hasValue("axis/x1-m")) {
+ if (props->hasValue("axis/x") || props->hasValue("axis/y") || props->hasValue("axis/z")) {
+ _axis[0] = props->getFloatValue("axis/x", 0);
+ _axis[1] = props->getFloatValue("axis/y", 0);
+ _axis[2] = props->getFloatValue("axis/z", 0);
+ } else {
double x1,y1,z1,x2,y2,z2;
- x1 = props->getFloatValue("axis/x1-m");
- y1 = props->getFloatValue("axis/y1-m");
- z1 = props->getFloatValue("axis/z1-m");
- x2 = props->getFloatValue("axis/x2-m");
- y2 = props->getFloatValue("axis/y2-m");
- z2 = props->getFloatValue("axis/z2-m");
+ x1 = props->getFloatValue("axis/x1-m", 0);
+ y1 = props->getFloatValue("axis/y1-m", 0);
+ z1 = props->getFloatValue("axis/z1-m", 0);
+ x2 = props->getFloatValue("axis/x2-m", 0);
+ y2 = props->getFloatValue("axis/y2-m", 0);
+ z2 = props->getFloatValue("axis/z2-m", 0);
_center[0] = (x1+x2)/2;
_center[1]= (y1+y2)/2;
_center[2] = (z1+z2)/2;
_axis[0] = (x2-x1)/vector_length;
_axis[1] = (y2-y1)/vector_length;
_axis[2] = (z2-z1)/vector_length;
- } else {
- _axis[0] = props->getFloatValue("axis/x", 0);
- _axis[1] = props->getFloatValue("axis/y", 0);
- _axis[2] = props->getFloatValue("axis/z", 0);
}
- if (props->hasValue("center/x-m")) {
- _center[0] = props->getFloatValue("center/x-m", 0);
- _center[1] = props->getFloatValue("center/y-m", 0);
- _center[2] = props->getFloatValue("center/z-m", 0);
+ if (props->hasValue("center/x-m") || props->hasValue("center/y-m")
+ || props->hasValue("center/z-m")) {
+ _center[0] = props->getFloatValue("center/x-m", 0);
+ _center[1] = props->getFloatValue("center/y-m", 0);
+ _center[2] = props->getFloatValue("center/z-m", 0);
}
sgNormalizeVec3(_axis);
}
delete _table;
}
-void
+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 2;
}
\f
SGPropertyNode_ptr props )
: SGAnimation(props, new ssgTransform),
_prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
+ _table(read_interpolation_table(props)),
+ _prev_value(1.0),
_offset(props->getDoubleValue("offset", 0.0)),
_factor(props->getDoubleValue("factor", 1.0)),
- _table(read_interpolation_table(props)),
_has_min(props->hasValue("min")),
_min(props->getDoubleValue("min", 0.0)),
_has_max(props->hasValue("max")),
- _max(props->getDoubleValue("max", 1.0)),
- _prev_value(1.0)
+ _max(props->getDoubleValue("max", 1.0))
{
}
delete _table;
}
-void
+int
SGBlendAnimation::update()
{
double _blend;
_prev_value = _blend;
change_alpha( _branch, _blend );
}
+ return 1;
}
_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);
delete _table;
}
-void
+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() * _factor) + _offset_m;
+ 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 2;
}
delete _table;
}
-void
+int
SGScaleAnimation::update()
{
if (_table == 0) {
set_scale(_matrix, _x_scale, _y_scale, _z_scale );
((ssgTransform *)_branch)->setTransform(_matrix);
+ return 2;
}
delete _table;
}
-void
+int
SGTexRotateAnimation::update()
{
if (_table == 0) {
}
set_rotation(_matrix, _position_deg, _center, _axis);
((ssgTexTrans *)_branch)->setTransform(_matrix);
+ return 2;
}
delete _table;
}
-void
+int
SGTexTranslateAnimation::update()
{
if (_table == 0) {
}
set_translation(_matrix, _position, _axis);
((ssgTexTrans *)_branch)->setTransform(_matrix);
+ return 2;
}
SGTexMultipleAnimation::~SGTexMultipleAnimation ()
{
- // delete _table;
- delete _transform;
+ delete [] _transform;
}
-void
+int
SGTexMultipleAnimation::update()
{
int i;
}
}
((ssgTexTrans *)_branch)->setTransform(tmatrix);
+ return 2;
}
}
}
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of SGMaterialAnimation
+////////////////////////////////////////////////////////////////////////
+
+SGMaterialAnimation::SGMaterialAnimation( SGPropertyNode *prop_root,
+ SGPropertyNode_ptr props, const SGPath &texture_path)
+ : SGAnimation(props, new ssgBranch),
+ _prop_root(prop_root),
+ _last_condition(false),
+ _prop_base(""),
+ _texture_base(texture_path),
+ _cached_material(0),
+ _cloned_material(0),
+ _read(0),
+ _update(0),
+ _global(props->getBoolValue("global", false))
+{
+ SGPropertyNode_ptr n;
+ n = props->getChild("condition");
+ _condition = n ? sgReadCondition(_prop_root, n) : 0;
+ n = props->getChild("property-base");
+ if (n) {
+ _prop_base = n->getStringValue();
+ if (!_prop_base.empty() && _prop_base.end()[-1] != '/')
+ _prop_base += '/';
+ }
+
+ initColorGroup(props->getChild("diffuse"), &_diff, DIFFUSE);
+ initColorGroup(props->getChild("ambient"), &_amb, AMBIENT);
+ initColorGroup(props->getChild("emission"), &_emis, EMISSION);
+ initColorGroup(props->getChild("specular"), &_spec, SPECULAR);
+
+ _shi = props->getFloatValue("shininess", -1.0);
+ if (_shi >= 0.0)
+ _update |= SHININESS;
+
+ SGPropertyNode_ptr group = props->getChild("transparency");
+ if (group) {
+ _trans.value = group->getFloatValue("alpha", -1.0);
+ _trans.factor = group->getFloatValue("factor", 1.0);
+ _trans.offset = group->getFloatValue("offset", 0.0);
+ _trans.min = group->getFloatValue("min", 0.0);
+ if (_trans.min < 0.0)
+ _trans.min = 0.0;
+ _trans.max = group->getFloatValue("max", 1.0);
+ if (_trans.max > 1.0)
+ _trans.max = 1.0;
+ if (_trans.dirty())
+ _update |= TRANSPARENCY;
+
+ n = group->getChild("alpha-prop");
+ _trans.value_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
+ n = group->getChild("factor-prop");
+ _trans.factor_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
+ n = group->getChild("offset-prop");
+ _trans.offset_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
+ if (_trans.live())
+ _read |= TRANSPARENCY;
+ }
+
+ _thresh = props->getFloatValue("threshold", -1.0);
+ if (_thresh >= 0.0)
+ _update |= THRESHOLD;
+
+ string _texture_str = props->getStringValue("texture", "");
+ if (!_texture_str.empty()) {
+ _texture = _texture_base;
+ _texture.append(_texture_str);
+ _update |= TEXTURE;
+ }
+
+ n = props->getChild("shininess-prop");
+ _shi_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
+ n = props->getChild("threshold-prop");
+ _thresh_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
+ n = props->getChild("texture-prop");
+ _tex_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
+
+ _static_update = _update;
+}
+
+void SGMaterialAnimation::initColorGroup(SGPropertyNode_ptr group, ColorSpec *col, int flag)
+{
+ if (!group)
+ return;
+
+ col->red = group->getFloatValue("red", -1.0);
+ col->green = group->getFloatValue("green", -1.0);
+ col->blue = group->getFloatValue("blue", -1.0);
+ col->factor = group->getFloatValue("factor", 1.0);
+ col->offset = group->getFloatValue("offset", 0.0);
+ if (col->dirty())
+ _update |= flag;
+
+ SGPropertyNode *n;
+ n = group->getChild("red-prop");
+ col->red_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
+ n = group->getChild("green-prop");
+ col->green_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
+ n = group->getChild("blue-prop");
+ col->blue_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
+ n = group->getChild("factor-prop");
+ col->factor_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
+ n = group->getChild("offset-prop");
+ col->offset_prop = n ? _prop_root->getNode(path(n->getStringValue()), true) : 0;
+ if (col->live())
+ _read |= flag;
+}
+
+void SGMaterialAnimation::init()
+{
+ if (!_global)
+ cloneMaterials(_branch);
+}
+
+int SGMaterialAnimation::update()
+{
+ if (_condition) {
+ bool cond = _condition->test();
+ if (cond && !_last_condition)
+ _update |= _static_update;
+
+ _last_condition = cond;
+ if (!cond)
+ return 2;
+ }
+
+ if (_read & DIFFUSE)
+ updateColorGroup(&_diff, DIFFUSE);
+ if (_read & AMBIENT)
+ updateColorGroup(&_amb, AMBIENT);
+ if (_read & EMISSION)
+ updateColorGroup(&_emis, EMISSION);
+ if (_read & SPECULAR)
+ updateColorGroup(&_spec, SPECULAR);
+
+ float f;
+ if (_shi_prop) {
+ f = _shi;
+ _shi = _shi_prop->getFloatValue();
+ if (_shi != f)
+ _update |= SHININESS;
+ }
+ if (_read & TRANSPARENCY) {
+ PropSpec tmp = _trans;
+ if (_trans.value_prop)
+ _trans.value = _trans.value_prop->getFloatValue();
+ if (_trans.factor_prop)
+ _trans.factor = _trans.factor_prop->getFloatValue();
+ if (_trans.offset_prop)
+ _trans.offset = _trans.offset_prop->getFloatValue();
+ if (_trans != tmp)
+ _update |= TRANSPARENCY;
+ }
+ if (_thresh_prop) {
+ f = _thresh;
+ _thresh = _thresh_prop->getFloatValue();
+ if (_thresh != f)
+ _update |= THRESHOLD;
+ }
+ if (_tex_prop) {
+ string t = _tex_prop->getStringValue();
+ if (!t.empty() && t != _texture_str) {
+ _texture_str = t;
+ _texture = _texture_base;
+ _texture.append(t);
+ _update |= TEXTURE;
+ }
+ }
+ if (_update) {
+ setMaterialBranch(_branch);
+ _update = 0;
+ }
+ return 2;
+}
+
+void SGMaterialAnimation::updateColorGroup(ColorSpec *col, int flag)
+{
+ ColorSpec tmp = *col;
+ if (col->red_prop)
+ col->red = col->red_prop->getFloatValue();
+ if (col->green_prop)
+ col->green = col->green_prop->getFloatValue();
+ if (col->blue_prop)
+ col->blue = col->blue_prop->getFloatValue();
+ if (col->factor_prop)
+ col->factor = col->factor_prop->getFloatValue();
+ if (col->offset_prop)
+ col->offset = col->offset_prop->getFloatValue();
+ if (*col != tmp)
+ _update |= flag;
+}
+
+void SGMaterialAnimation::cloneMaterials(ssgBranch *b)
+{
+ for (int i = 0; i < b->getNumKids(); i++)
+ cloneMaterials((ssgBranch *)b->getKid(i));
+
+ if (!b->isAKindOf(ssgTypeLeaf()) || !((ssgLeaf *)b)->hasState())
+ return;
+
+ ssgSimpleState *s = (ssgSimpleState *)((ssgLeaf *)b)->getState();
+ if (!_cached_material || _cached_material != s) {
+ _cached_material = s;
+ _cloned_material = (ssgSimpleState *)s->clone(SSG_CLONE_STATE);
+ }
+ ((ssgLeaf *)b)->setState(_cloned_material);
+}
+
+void SGMaterialAnimation::setMaterialBranch(ssgBranch *b)
+{
+ for (int i = 0; i < b->getNumKids(); i++)
+ setMaterialBranch((ssgBranch *)b->getKid(i));
+
+ if (!b->isAKindOf(ssgTypeLeaf()) || !((ssgLeaf *)b)->hasState())
+ return;
+
+ ssgSimpleState *s = (ssgSimpleState *)((ssgLeaf *)b)->getState();
+
+ if (_update & DIFFUSE) {
+ float *v = _diff.rgba();
+ SGfloat alpha = s->getMaterial(GL_DIFFUSE)[3];
+ s->setColourMaterial(GL_DIFFUSE);
+ s->enable(GL_COLOR_MATERIAL);
+ s->setMaterial(GL_DIFFUSE, v[0], v[1], v[2], alpha);
+ s->disable(GL_COLOR_MATERIAL);
+ }
+ if (_update & AMBIENT) {
+ s->setColourMaterial(GL_AMBIENT);
+ s->enable(GL_COLOR_MATERIAL);
+ s->setMaterial(GL_AMBIENT, _amb.rgba());
+ s->disable(GL_COLOR_MATERIAL);
+ }
+ if (_update & EMISSION)
+ s->setMaterial(GL_EMISSION, _emis.rgba());
+ if (_update & SPECULAR)
+ s->setMaterial(GL_SPECULAR, _spec.rgba());
+ if (_update & SHININESS)
+ s->setShininess(clamp(_shi, 0.0, 128.0));
+ if (_update & TRANSPARENCY) {
+ SGfloat *v = s->getMaterial(GL_DIFFUSE);
+ float trans = _trans.value * _trans.factor + _trans.offset;
+ trans = trans < _trans.min ? _trans.min : trans > _trans.max ? _trans.max : trans;
+ s->setMaterial(GL_DIFFUSE, v[0], v[1], v[2], trans);
+ }
+ if (_update & THRESHOLD)
+ s->setAlphaClamp(clamp(_thresh));
+ if (_update & TEXTURE)
+ s->setTexture(_texture.c_str());
+ if (_update & (TEXTURE|TRANSPARENCY)) {
+ SGfloat alpha = s->getMaterial(GL_DIFFUSE)[3];
+ ssgTexture *tex = s->getTexture();
+ if ((tex && tex->hasAlpha()) || alpha < 0.999) {
+ s->setColourMaterial(GL_DIFFUSE);
+ s->enable(GL_COLOR_MATERIAL);
+ s->enable(GL_BLEND);
+ s->enable(GL_ALPHA_TEST);
+ s->setTranslucent();
+ s->disable(GL_COLOR_MATERIAL);
+ } else {
+ s->disable(GL_BLEND);
+ s->disable(GL_ALPHA_TEST);
+ s->setOpaque();
+ }
+ }
+ s->force();
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of SGFlashAnimation
+////////////////////////////////////////////////////////////////////////
+SGFlashAnimation::SGFlashAnimation(SGPropertyNode_ptr props)
+ : SGAnimation( props, new SGCustomTransform )
+{
+ _axis[0] = props->getFloatValue("axis/x", 0);
+ _axis[1] = props->getFloatValue("axis/y", 0);
+ _axis[2] = props->getFloatValue("axis/z", 1);
+
+ _center[0] = props->getFloatValue("center/x-m", 0);
+ _center[1] = props->getFloatValue("center/y-m", 0);
+ _center[2] = props->getFloatValue("center/z-m", 0);
+
+ _offset = props->getFloatValue("offset", 0.0);
+ _factor = props->getFloatValue("factor", 1.0);
+ _power = props->getFloatValue("power", 1.0);
+ _two_sides = props->getBoolValue("two-sides", false);
+
+ _min_v = props->getFloatValue("min", 0.0);
+ _max_v = props->getFloatValue("max", 1.0);
+
+ ((SGCustomTransform *)_branch)->setTransCallback( &SGFlashAnimation::flashCallback, this );
+}
+
+SGFlashAnimation::~SGFlashAnimation()
+{
+}
+
+void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
+{
+ ((SGFlashAnimation *)d)->flashCallback( r, f, m );
+}
+
+void SGFlashAnimation::flashCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
+{
+ sgVec3 transformed_axis;
+ sgXformVec3( transformed_axis, _axis, m );
+ sgNormalizeVec3( transformed_axis );
+
+ 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;
+ else if ( cos_angle > 0 )
+ scale_factor = _factor * (float)pow( cos_angle, _power ) + _offset;
+
+ if ( scale_factor < _min_v )
+ scale_factor = _min_v;
+ if ( scale_factor > _max_v )
+ scale_factor = _max_v;
+
+ sgMat4 transform;
+ sgMakeIdentMat4( transform );
+ transform[0][0] = scale_factor;
+ transform[1][1] = scale_factor;
+ transform[2][2] = scale_factor;
+ transform[3][0] = _center[0] * ( 1 - scale_factor );
+ transform[3][1] = _center[1] * ( 1 - scale_factor );
+ transform[3][2] = _center[2] * ( 1 - scale_factor );
+
+ sgCopyMat4( r, m );
+ sgPreMultMat4( r, transform );
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of SGDistScaleAnimation
+////////////////////////////////////////////////////////////////////////
+SGDistScaleAnimation::SGDistScaleAnimation(SGPropertyNode_ptr props)
+ : SGAnimation( props, new SGCustomTransform ),
+ _factor(props->getFloatValue("factor", 1.0)),
+ _offset(props->getFloatValue("offset", 0.0)),
+ _min_v(props->getFloatValue("min", 0.0)),
+ _max_v(props->getFloatValue("max", 1.0)),
+ _has_min(props->hasValue("min")),
+ _has_max(props->hasValue("max")),
+ _table(read_interpolation_table(props))
+{
+ _center[0] = props->getFloatValue("center/x-m", 0);
+ _center[1] = props->getFloatValue("center/y-m", 0);
+ _center[2] = props->getFloatValue("center/z-m", 0);
+
+ ((SGCustomTransform *)_branch)->setTransCallback( &SGDistScaleAnimation::distScaleCallback, this );
+}
+
+SGDistScaleAnimation::~SGDistScaleAnimation()
+{
+}
+
+void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m, void *d )
+{
+ ((SGDistScaleAnimation *)d)->distScaleCallback( r, f, m );
+}
+
+void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 m )
+{
+ sgVec3 view;
+ sgFullXformPnt3( view, _center, m );
+
+ float scale_factor = sgLengthVec3( view );
+ if (_table == 0) {
+ scale_factor = _factor * scale_factor + _offset;
+ if ( _has_min && scale_factor < _min_v )
+ scale_factor = _min_v;
+ if ( _has_max && scale_factor > _max_v )
+ scale_factor = _max_v;
+ } else {
+ scale_factor = _table->interpolate( scale_factor );
+ }
+
+ sgMat4 transform;
+ sgMakeIdentMat4( transform );
+ transform[0][0] = scale_factor;
+ transform[1][1] = scale_factor;
+ transform[2][2] = scale_factor;
+ transform[3][0] = _center[0] * ( 1 - scale_factor );
+ transform[3][1] = _center[1] * ( 1 - scale_factor );
+ transform[3][2] = _center[2] * ( 1 - scale_factor );
+
+ sgCopyMat4( r, m );
+ sgPreMultMat4( r, transform );
+}
+
+////////////////////////////////////////////////////////////////////////
+// Implementation of SGShadowAnimation
+////////////////////////////////////////////////////////////////////////
+
+SGShadowAnimation::SGShadowAnimation ( SGPropertyNode *prop_root,
+ SGPropertyNode_ptr props )
+ : SGAnimation(props, new ssgBranch),
+ _condition(0),
+ _condition_value(true)
+{
+ animation_type = 1;
+ SGPropertyNode_ptr node = props->getChild("condition");
+ if (node != 0) {
+ _condition = sgReadCondition(prop_root, node);
+ _condition_value = false;
+ }
+}
+
+SGShadowAnimation::~SGShadowAnimation ()
+{
+ delete _condition;
+}
+
+int
+SGShadowAnimation::update()
+{
+ if (_condition)
+ _condition_value = _condition->test();
+ return 2;
+}
+
+bool SGShadowAnimation::get_condition_value(void) {
+ return _condition_value;
+}
+
// end of animation.cxx