]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/model/animation.cxx
Frederic Bouvier:
[simgear.git] / simgear / scene / model / animation.cxx
index 317df8e169903fa5c05c88d44ed13ccc9cf897d5..8a1c73e2281ef3bb5701cdc727f25969bf626b84 100644 (file)
@@ -17,7 +17,8 @@
 #include <simgear/math/sg_random.h>
 
 #include "animation.hxx"
-#include "flash.hxx"
+#include "custtrans.hxx"
+#include "personality.hxx"
 
 \f
 ////////////////////////////////////////////////////////////////////////
@@ -175,12 +176,17 @@ read_interpolation_table (SGPropertyNode_ptr props)
 
 // Initialize the static data member
 double SGAnimation::sim_time_sec = 0.0;
-ssgBranch *SGAnimation::current_object = 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 ()
@@ -418,9 +424,12 @@ 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)),
-    _step( 0 ),
-    _use_personality( props->getBoolValue("use-personality",false) )
+    _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();
@@ -437,45 +446,96 @@ SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
                                                           rNode->getDoubleValue( "max", 1.0 ) );
         }
     }
-    ((ssgSelector *)getBranch())->selectStep(_step);
 }
 
 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()
 {
-    ssgBranch *key = ( _use_personality ? current_object : 0 );
-    PersonalityMap::iterator it = _branch_duration_sec.find( key );
-    if ( it == _branch_duration_sec.end() ) {
-        vector<double> 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;
+    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 );
         }
-        it = _branch_duration_sec.insert( PersonalityMap::value_type( key, durations ) ).first;
-        _last_time_sec[ key ] = sim_time_sec;
-        _total_duration_sec[ key ] = total;
-    }
 
-    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;
+        _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;
 }
@@ -993,33 +1053,129 @@ void SGAlphaTestAnimation::setAlphaClampToBranch(ssgBranch *b, float clamp)
 // Implementation of SGFlashAnimation
 ////////////////////////////////////////////////////////////////////////
 SGFlashAnimation::SGFlashAnimation(SGPropertyNode_ptr props)
-  : SGAnimation( props, new SGFlash )
+  : SGAnimation( props, new SGCustomTransform )
 {
-  sgVec3 axis;
-  axis[0] = props->getFloatValue("axis/x", 0);
-  axis[1] = props->getFloatValue("axis/y", 0);
-  axis[2] = props->getFloatValue("axis/z", 1);
-  ((SGFlash *)_branch)->setAxis( axis );
-
-  sgVec3 center;
-  center[0] = props->getFloatValue("center/x-m", 0);
-  center[1] = props->getFloatValue("center/y-m", 0);
-  center[2] = props->getFloatValue("center/z-m", 0);
-  ((SGFlash *)_branch)->setCenter( center );
-
-  float offset = props->getFloatValue("offset", 0.0);
-  float factor = props->getFloatValue("factor", 1.0);
-  float power = props->getFloatValue("power", 1.0);
-  bool two_sides = props->getBoolValue("two-sides", false);
-  ((SGFlash *)_branch)->setParameters( power, factor, offset, two_sides );
-
-  float v_min = props->getFloatValue("min", 0.0);
-  float v_max = props->getFloatValue("max", 1.0);
-  ((SGFlash *)_branch)->setClampValues( v_min, v_max );
+  _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