]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/model/animation.cxx
Frederic Bouvier:
[simgear.git] / simgear / scene / model / animation.cxx
index ce6870861af67379c66d01ffd74f774250203678..8a1c73e2281ef3bb5701cdc727f25969bf626b84 100644 (file)
 #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
 ////////////////////////////////////////////////////////////////////////
@@ -174,11 +176,17 @@ read_interpolation_table (SGPropertyNode_ptr props)
 
 // 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->setName(props->getStringValue("name", 0));
+    if ( props->getBoolValue( "enable-hot", true ) ) {
+        _branch->setTraversalMaskBits( SSGTRAV_HOT );
+    } else {
+        _branch->clrTraversalMaskBits( SSGTRAV_HOT );
+    }
 }
 
 SGAnimation::~SGAnimation ()
@@ -190,8 +198,14 @@ SGAnimation::init ()
 {
 }
 
-void
+int
 SGAnimation::update()
+{
+    return 1;
+}
+
+void
+SGAnimation::restore()
 {
 }
 
@@ -219,12 +233,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);
     }
@@ -255,26 +273,27 @@ SGRangeAnimation::~SGRangeAnimation ()
 {
 }
 
-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 1;
 }
 
 
@@ -313,13 +332,14 @@ SGSelectAnimation::~SGSelectAnimation ()
   delete _condition;
 }
 
-void
+int
 SGSelectAnimation::update()
 {
   if (_condition != 0 && _condition->test()) 
       ((ssgSelector *)_branch)->select(0xffff);
   else
       ((ssgSelector *)_branch)->select(0x0000);
+  return 1;
 }
 
 
@@ -335,8 +355,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;
@@ -372,20 +397,23 @@ SGSpinAnimation::~SGSpinAnimation ()
 {
 }
 
-void
+int
 SGSpinAnimation::update()
 {
-  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);
+  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);
+  }
+  return 1;
 }
 
 
@@ -396,10 +424,28 @@ SGSpinAnimation::update()
 
 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 ()
@@ -407,15 +453,91 @@ SGTimedAnimation::~SGTimedAnimation ()
 }
 
 void
+SGTimedAnimation::init()
+{
+    if ( !_use_personality ) {
+        for ( size_t i = 0; i < getBranch()->getNumKids(); i++ ) {
+            double v;
+            if ( i < _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 ) ) {
+            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, 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 );
+            key->setDoubleValue( total, this, TOTAL_DURATION_SEC );
+            key->setIntValue( 0, this, STEP );
+            key->setIntValue( 1, this, INIT );
+        }
+
+        _step = key->getIntValue( this, STEP );
+        _last_time_sec = key->getDoubleValue( this, LAST_TIME_SEC );
+        _total_duration_sec = key->getDoubleValue( this, TOTAL_DURATION_SEC );
+        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, _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 );
+        key->setIntValue( _step, this, STEP );
+    } 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;
 }
 
 
@@ -435,8 +557,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;
@@ -473,20 +600,23 @@ SGRotateAnimation::~SGRotateAnimation ()
   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 1;
 }
 
 \f
@@ -498,14 +628,14 @@ SGBlendAnimation::SGBlendAnimation( SGPropertyNode *prop_root,
                                         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))
 {
 }
 
@@ -514,7 +644,7 @@ SGBlendAnimation::~SGBlendAnimation ()
     delete _table;
 }
 
-void
+int
 SGBlendAnimation::update()
 {
   double _blend;
@@ -534,6 +664,7 @@ SGBlendAnimation::update()
     _prev_value = _blend;
     change_alpha( _branch, _blend );
   }
+  return 1;
 }
 
 
@@ -553,8 +684,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);
@@ -566,20 +702,23 @@ SGTranslateAnimation::~SGTranslateAnimation ()
   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() + _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;
 }
 
 
@@ -619,7 +758,7 @@ SGScaleAnimation::~SGScaleAnimation ()
   delete _table;
 }
 
-void
+int
 SGScaleAnimation::update()
 {
   if (_table == 0) {
@@ -654,6 +793,7 @@ SGScaleAnimation::update()
 
   set_scale(_matrix, _x_scale, _y_scale, _z_scale );
   ((ssgTransform *)_branch)->setTransform(_matrix);
+  return 1;
 }
 
 
@@ -688,7 +828,7 @@ SGTexRotateAnimation::~SGTexRotateAnimation ()
   delete _table;
 }
 
-void
+int
 SGTexRotateAnimation::update()
 {
   if (_table == 0) {
@@ -702,6 +842,7 @@ SGTexRotateAnimation::update()
   }
   set_rotation(_matrix, _position_deg, _center, _axis);
   ((ssgTexTrans *)_branch)->setTransform(_matrix);
+  return 1;
 }
 
 
@@ -735,7 +876,7 @@ SGTexTranslateAnimation::~SGTexTranslateAnimation ()
   delete _table;
 }
 
-void
+int
 SGTexTranslateAnimation::update()
 {
   if (_table == 0) {
@@ -749,6 +890,7 @@ SGTexTranslateAnimation::update()
   }
   set_translation(_matrix, _position, _axis);
   ((ssgTexTrans *)_branch)->setTransform(_matrix);
+  return 1;
 }
 
 
@@ -825,7 +967,7 @@ SGTexMultipleAnimation::~SGTexMultipleAnimation ()
   delete _transform;
 }
 
-void
+int
 SGTexMultipleAnimation::update()
 {
   int i;
@@ -866,6 +1008,7 @@ SGTexMultipleAnimation::update()
     }
   }
   ((ssgTexTrans *)_branch)->setTransform(tmatrix);
+  return 1;
 }
 
 
@@ -904,4 +1047,135 @@ void SGAlphaTestAnimation::setAlphaClampToBranch(ssgBranch *b, float clamp)
   }
 }
 
+
+\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 );
+}
+
 // end of animation.cxx