]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/model/animation.cxx
Modified Files:
[simgear.git] / simgear / scene / model / animation.cxx
index 67c69cb08d8b3d7fdf1470a2bb9a944bf2ae15d2..47bee355cd18f3214edbe2a5feb3e98c5ea6ab69 100644 (file)
@@ -3,20 +3,32 @@
 //
 // 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 <plib/sg.h>
-#include <plib/ssg.h>
-#include <plib/ul.h>
+#include <osg/AlphaFunc>
+#include <osg/AutoTransform>
+#include <osg/ColorMatrix>
+#include <osg/Drawable>
+#include <osg/Geode>
+#include <osg/LOD>
+#include <osg/MatrixTransform>
+#include <osg/StateSet>
+#include <osg/Switch>
+#include <osg/TexMat>
 
 #include <simgear/math/interpolater.hxx>
 #include <simgear/props/condition.hxx>
 #include <simgear/props/props.hxx>
+#include <simgear/math/sg_random.h>
+#include <simgear/scene/util/SGNodeMasks.hxx>
 
 #include "animation.hxx"
-
+#include "model.hxx"
 
 \f
 ////////////////////////////////////////////////////////////////////////
@@ -27,8 +39,8 @@
  * Set up the transform matrix for a spin or rotation.
  */
 static void
-set_rotation (sgMat4 &matrix, double position_deg,
-              sgVec3 &center, sgVec3 &axis)
+set_rotation (osg::Matrix &matrix, double position_deg,
+              const osg::Vec3 &center, const osg::Vec3 &axis)
 {
  float temp_angle = -position_deg * SG_DEGREES_TO_RADIANS ;
  
@@ -42,78 +54,55 @@ set_rotation (sgMat4 &matrix, double position_deg,
  float y = axis[1];
  float z = axis[2];
 
- matrix[0][0] = t * x * x + c ;
- matrix[0][1] = t * y * x - s * z ;
- matrix[0][2] = t * z * x + s * y ;
- matrix[0][3] = SG_ZERO;
+ matrix(0, 0) = t * x * x + c ;
+ matrix(0, 1) = t * y * x - s * z ;
+ matrix(0, 2) = t * z * x + s * y ;
+ matrix(0, 3) = SG_ZERO;
  
- matrix[1][0] = t * x * y + s * z ;
- matrix[1][1] = t * y * y + c ;
- matrix[1][2] = t * z * y - s * x ;
- matrix[1][3] = SG_ZERO;
+ matrix(1, 0) = t * x * y + s * z ;
+ matrix(1, 1) = t * y * y + c ;
+ matrix(1, 2) = t * z * y - s * x ;
+ matrix(1, 3) = SG_ZERO;
  
- matrix[2][0] = t * x * z - s * y ;
- matrix[2][1] = t * y * z + s * x ;
- matrix[2][2] = t * z * z + c ;
- matrix[2][3] = SG_ZERO;
+ matrix(2, 0) = t * x * z - s * y ;
+ matrix(2, 1) = t * y * z + s * x ;
+ matrix(2, 2) = t * z * z + c ;
+ matrix(2, 3) = SG_ZERO;
 
   // hint to the compiler to put these into FP registers
  x = center[0];
  y = center[1];
  z = center[2];
  
- matrix[3][0] = x - x*matrix[0][0] - y*matrix[1][0] - z*matrix[2][0];
- matrix[3][1] = y - x*matrix[0][1] - y*matrix[1][1] - z*matrix[2][1];
- matrix[3][2] = z - x*matrix[0][2] - y*matrix[1][2] - z*matrix[2][2];
- matrix[3][3] = SG_ONE;
+ matrix(3, 0) = x - x*matrix(0, 0) - y*matrix(1, 0) - z*matrix(2, 0);
+ matrix(3, 1) = y - x*matrix(0, 1) - y*matrix(1, 1) - z*matrix(2, 1);
+ matrix(3, 2) = z - x*matrix(0, 2) - y*matrix(1, 2) - z*matrix(2, 2);
+ matrix(3, 3) = SG_ONE;
 }
 
 /**
  * Set up the transform matrix for a translation.
  */
 static void
-set_translation (sgMat4 &matrix, double position_m, sgVec3 &axis)
+set_translation (osg::Matrix &matrix, double position_m, const osg::Vec3 &axis)
 {
-  sgVec3 xyz;
-  sgScaleVec3(xyz, axis, position_m);
-  sgMakeTransMat4(matrix, xyz);
+  osg::Vec3 xyz = axis * position_m;
+  matrix.makeIdentity();
+  matrix(3, 0) = xyz[0];
+  matrix(3, 1) = xyz[1];
+  matrix(3, 2) = xyz[2];
 }
 
 /**
  * Set up the transform matrix for a scale operation.
  */
 static void
-set_scale (sgMat4 &matrix, double x, double y, double z)
-{
-  sgMakeIdentMat4( matrix );
-  matrix[0][0] = x;
-  matrix[1][1] = y;
-  matrix[2][2] = z;
-}
-
-/**
- * Recursively process all kids to change the alpha values
- */
-static void
-change_alpha( ssgBase *_branch, float _blend )
+set_scale (osg::Matrix &matrix, double x, double y, double z)
 {
-  int i;
-
-  for (i = 0; i < ((ssgBranch *)_branch)->getNumKids(); i++)
-    change_alpha( ((ssgBranch *)_branch)->getKid(i), _blend );
-
-  if ( !_branch->isAKindOf(ssgTypeLeaf())
-       && !_branch->isAKindOf(ssgTypeVtxTable())
-       && !_branch->isAKindOf(ssgTypeVTable()) )
-    return;
-
-  int num_colors = ((ssgLeaf *)_branch)->getNumColours();
-
-  for (i = 0; i < num_colors; i++)
-  {
-    float *color =  ((ssgLeaf *)_branch)->getColour(i);
-    color[3] = _blend;
-  }
+  matrix.makeIdentity();
+  matrix(0, 0) = x;
+  matrix(1, 1) = y;
+  matrix(2, 2) = z;
 }
 
 /**
@@ -170,13 +159,16 @@ read_interpolation_table (SGPropertyNode_ptr props)
 // Implementation of SGAnimation
 ////////////////////////////////////////////////////////////////////////
 
-// Initialize the static data member
-double SGAnimation::sim_time_sec = 0.0;
-
-SGAnimation::SGAnimation (SGPropertyNode_ptr props, ssgBranch * branch)
-    : _branch(branch)
+SGAnimation::SGAnimation (SGPropertyNode_ptr props, osg::Group * branch)
+    : _branch(branch),
+    animation_type(0)
 {
-    _branch->setName(props->getStringValue("name", 0));
+    _branch->setName(props->getStringValue("name", "Animation"));
+    if ( props->getBoolValue( "enable-hot", true ) ) {
+        _branch->setNodeMask(SG_NODEMASK_TERRAIN_BIT|_branch->getNodeMask());
+    } else {
+        _branch->setNodeMask(~SG_NODEMASK_TERRAIN_BIT&_branch->getNodeMask());
+    }
 }
 
 SGAnimation::~SGAnimation ()
@@ -189,10 +181,15 @@ SGAnimation::init ()
 }
 
 void
-SGAnimation::update()
+SGAnimation::restore()
 {
 }
 
+void
+SGAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
+{
+    traverse(node, nv);
+}
 
 \f
 ////////////////////////////////////////////////////////////////////////
@@ -200,7 +197,7 @@ SGAnimation::update()
 ////////////////////////////////////////////////////////////////////////
 
 SGNullAnimation::SGNullAnimation (SGPropertyNode_ptr props)
-  : SGAnimation(props, new ssgBranch)
+  : SGAnimation(props, new osg::Group)
 {
 }
 
@@ -216,13 +213,17 @@ 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)
-
+  : SGAnimation(props, new osg::LOD),
+    _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);
     }
@@ -246,7 +247,7 @@ SGRangeAnimation::SGRangeAnimation (SGPropertyNode *prop_root,
        _max = props->getFloatValue("max-m", 0);
        ranges[1] = _max * _max_factor;
     }
-    ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
+    static_cast<osg::LOD*>(_branch)->setRange(0, ranges[0], ranges[1]);
 }
 
 SGRangeAnimation::~SGRangeAnimation ()
@@ -254,25 +255,26 @@ SGRangeAnimation::~SGRangeAnimation ()
 }
 
 void
-SGRangeAnimation::update()
+SGRangeAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
 {
-    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;
+  }
+  static_cast<osg::LOD*>(_branch)->setRange(0, ranges[0], ranges[1]);
+  traverse(node, nv);
 }
 
 
@@ -282,8 +284,18 @@ SGRangeAnimation::update()
 ////////////////////////////////////////////////////////////////////////
 
 SGBillboardAnimation::SGBillboardAnimation (SGPropertyNode_ptr props)
-    : SGAnimation(props, new ssgCutout(props->getBoolValue("spherical", true)))
+  : SGAnimation(props, new osg::AutoTransform)
 {
+//OSGFIXME: verify
+  bool spherical = props->getBoolValue("spherical", true);
+  osg::AutoTransform* autoTrans = static_cast<osg::AutoTransform*>(_branch);
+  if (spherical) {
+    autoTrans->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN);
+  } else {
+    autoTrans->setAutoRotateMode(osg::AutoTransform::NO_ROTATION);
+    autoTrans->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
+  }
+  autoTrans->setAutoScaleToScreen(false);
 }
 
 SGBillboardAnimation::~SGBillboardAnimation ()
@@ -298,7 +310,7 @@ SGBillboardAnimation::~SGBillboardAnimation ()
 
 SGSelectAnimation::SGSelectAnimation( SGPropertyNode *prop_root,
                                   SGPropertyNode_ptr props )
-  : SGAnimation(props, new ssgSelector),
+  : SGAnimation(props, new osg::Switch),
     _condition(0)
 {
   SGPropertyNode_ptr node = props->getChild("condition");
@@ -312,29 +324,35 @@ SGSelectAnimation::~SGSelectAnimation ()
 }
 
 void
-SGSelectAnimation::update()
-{
-  if (_condition != 0 && _condition->test()) 
-      ((ssgSelector *)_branch)->select(0xffff);
+SGSelectAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
+{ 
+  if (_condition != 0 && _condition->test())
+    static_cast<osg::Switch*>(_branch)->setAllChildrenOn();
   else
-      ((ssgSelector *)_branch)->select(0x0000);
+    static_cast<osg::Switch*>(_branch)->setAllChildrenOff();
+  traverse(node, nv);
 }
 
-
 \f
 ////////////////////////////////////////////////////////////////////////
 // Implementation of SGSpinAnimation
 ////////////////////////////////////////////////////////////////////////
 
 SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
-                              SGPropertyNode_ptr props,
-                              double sim_time_sec )
-  : SGAnimation(props, new ssgTransform),
+                                  SGPropertyNode_ptr props,
+                                  double sim_time_sec )
+  : SGAnimation(props, new osg::MatrixTransform),
+    _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 )
+    _factor( props, "factor", 1.0 ),
+    _position_deg( props, "starting-position-deg", 0.0 ),
+    _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;
@@ -363,7 +381,13 @@ SGSpinAnimation::SGSpinAnimation( SGPropertyNode *prop_root,
        _center[1] = props->getFloatValue("center/y-m", 0);
        _center[2] = props->getFloatValue("center/z-m", 0);
     }
-    sgNormalizeVec3(_axis);
+    
+    _axis.normalize();
+
+    if ( _use_personality ) {
+      _factor.shuffle();
+      _position_deg.shuffle();
+    }
 }
 
 SGSpinAnimation::~SGSpinAnimation ()
@@ -371,19 +395,24 @@ SGSpinAnimation::~SGSpinAnimation ()
 }
 
 void
-SGSpinAnimation::update()
+SGSpinAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
 {
-  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);
+  double sim_time_sec = nv->getFrameStamp()->getReferenceTime();
+  if ( _condition == 0 || _condition->test() ) {
+    double dt;
+    float velocity_rpms;
+    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);
+    _position_deg -= 360*floor(_position_deg/360);
+
+    osg::Matrix _matrix;
+    set_rotation(_matrix, _position_deg, _center, _axis);
+    static_cast<osg::MatrixTransform*>(_branch)->setMatrix(_matrix);
+  }
+  traverse(node, nv);
 }
 
 
@@ -393,11 +422,29 @@ SGSpinAnimation::update()
 ////////////////////////////////////////////////////////////////////////
 
 SGTimedAnimation::SGTimedAnimation (SGPropertyNode_ptr props)
-  : SGAnimation(props, new ssgSelector),
+  : SGAnimation(props, new osg::Switch),
+    _use_personality( props->getBoolValue("use-personality",false) ),
     _duration_sec(props->getDoubleValue("duration-sec", 1.0)),
-    _last_time_sec(0),
-    _step(-1)
+    _last_time_sec( 0 ),
+    _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 ()
@@ -405,15 +452,47 @@ SGTimedAnimation::~SGTimedAnimation ()
 }
 
 void
-SGTimedAnimation::update()
+SGTimedAnimation::init()
+{
+    if ( !_use_personality ) {
+        for ( unsigned i = 0; i < getBranch()->getNumChildren(); 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 (_duration_sec < 0.01)
+        _duration_sec = 0.01;
+    if ( _total_duration_sec < 0.01 )
+        _total_duration_sec = 0.01;
+
+    static_cast<osg::Switch*>(getBranch())->setSingleChildOn(_step);
+}
+
+void
+SGTimedAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
 {
-    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);
+    double sim_time_sec = nv->getFrameStamp()->getReferenceTime();
+    _last_time_sec -= _total_duration_sec*floor((sim_time_sec - _last_time_sec)/_total_duration_sec);
+    double duration = _duration_sec;
+    if ( _step < _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()->getNumChildren() )
+        _step = 0;
+      static_cast<osg::Switch*>(getBranch())->setSingleChildOn(_step);
     }
+    traverse(node, nv);
 }
 
 
@@ -424,7 +503,7 @@ SGTimedAnimation::update()
 
 SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
                                   SGPropertyNode_ptr props )
-    : SGAnimation(props, new ssgTransform),
+  : SGAnimation(props, new osg::MatrixTransform),
       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
       _factor(props->getDoubleValue("factor", 1.0)),
@@ -433,19 +512,28 @@ 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;
-    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;
@@ -453,17 +541,14 @@ SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
         _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);
+    _axis.normalize();
 }
 
 SGRotateAnimation::~SGRotateAnimation ()
@@ -472,19 +557,23 @@ SGRotateAnimation::~SGRotateAnimation ()
 }
 
 void
-SGRotateAnimation::update()
+SGRotateAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
 {
-  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());
+    }
+    osg::Matrix _matrix;
+    set_rotation(_matrix, _position_deg, _center, _axis);
+    static_cast<osg::MatrixTransform*>(_branch)->setMatrix(_matrix);
   }
-  set_rotation(_matrix, _position_deg, _center, _axis);
-  ((ssgTransform *)_branch)->setTransform(_matrix);
+  traverse(node, nv);
 }
 
 \f
@@ -494,17 +583,29 @@ SGRotateAnimation::update()
 
 SGBlendAnimation::SGBlendAnimation( SGPropertyNode *prop_root,
                                         SGPropertyNode_ptr props )
-  : SGAnimation(props, new ssgTransform),
+  : SGAnimation(props, new osg::Group),
+    _use_personality( props->getBoolValue("use-personality",false) ),
     _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
-    _offset(props->getDoubleValue("offset", 0.0)),
-    _factor(props->getDoubleValue("factor", 1.0)),
     _table(read_interpolation_table(props)),
+    _prev_value(1.0),
+    _offset(props,"offset",0.0),
+    _factor(props,"factor",1.0),
     _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))
 {
+  // OSGFIXME: does ot work like that!!!
+  // depends on a not so wide available extension
+
+  _colorMatrix = new osg::ColorMatrix;
+  osg::StateSet* stateSet = _branch->getOrCreateStateSet();
+  stateSet->setAttribute(_colorMatrix.get());
+
+  if ( _use_personality ) {
+    _factor.shuffle();
+    _offset.shuffle();
+  }
 }
 
 SGBlendAnimation::~SGBlendAnimation ()
@@ -513,7 +614,7 @@ SGBlendAnimation::~SGBlendAnimation ()
 }
 
 void
-SGBlendAnimation::update()
+SGBlendAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
 {
   double _blend;
 
@@ -530,8 +631,9 @@ SGBlendAnimation::update()
 
   if (_blend != _prev_value) {
     _prev_value = _blend;
-    change_alpha( _branch, _blend );
+    _colorMatrix->getMatrix()(3, 3) = _blend;
   }
+  traverse(node, nv);
 }
 
 
@@ -542,21 +644,32 @@ SGBlendAnimation::update()
 
 SGTranslateAnimation::SGTranslateAnimation( SGPropertyNode *prop_root,
                                         SGPropertyNode_ptr props )
-  : SGAnimation(props, new ssgTransform),
-      _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
-    _offset_m(props->getDoubleValue("offset-m", 0.0)),
-    _factor(props->getDoubleValue("factor", 1.0)),
+  : SGAnimation(props, new osg::MatrixTransform),
+    _use_personality( props->getBoolValue("use-personality",false) ),
+    _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
+    _offset_m( props, "offset-m", 0.0 ),
+    _factor( props, "factor", 1.0 ),
     _table(read_interpolation_table(props)),
     _has_min(props->hasValue("min-m")),
     _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);
-  sgNormalizeVec3(_axis);
+  _axis.normalize();
+
+  if ( _use_personality ) {
+    _factor.shuffle();
+    _offset_m.shuffle();
+  }
 }
 
 SGTranslateAnimation::~SGTranslateAnimation ()
@@ -565,19 +678,25 @@ SGTranslateAnimation::~SGTranslateAnimation ()
 }
 
 void
-SGTranslateAnimation::update()
+SGTranslateAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
 {
-  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());
+    }
+
+    osg::Matrix _matrix;
+    set_translation(_matrix, _position_m, _axis);
+    static_cast<osg::MatrixTransform*>(_branch)->setMatrix(_matrix);
   }
-  set_translation(_matrix, _position_m, _axis);
-  ((ssgTransform *)_branch)->setTransform(_matrix);
+  traverse(node, nv);
 }
 
 
@@ -588,14 +707,15 @@ SGTranslateAnimation::update()
 
 SGScaleAnimation::SGScaleAnimation( SGPropertyNode *prop_root,
                                         SGPropertyNode_ptr props )
-  : SGAnimation(props, new ssgTransform),
-      _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
-    _x_factor(props->getDoubleValue("x-factor", 1.0)),
-    _y_factor(props->getDoubleValue("y-factor", 1.0)),
-    _z_factor(props->getDoubleValue("z-factor", 1.0)),
-    _x_offset(props->getDoubleValue("x-offset", 1.0)),
-    _y_offset(props->getDoubleValue("y-offset", 1.0)),
-    _z_offset(props->getDoubleValue("z-offset", 1.0)),
+  : SGAnimation(props, new osg::MatrixTransform),
+    _use_personality( props->getBoolValue("use-personality",false) ),
+    _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
+    _x_factor(props,"x-factor",1.0),
+    _y_factor(props,"y-factor",1.0),
+    _z_factor(props,"z-factor",1.0),
+    _x_offset(props,"x-offset",1.0),
+    _y_offset(props,"y-offset",1.0),
+    _z_offset(props,"z-offset",1.0),
     _table(read_interpolation_table(props)),
     _has_min_x(props->hasValue("x-min")),
     _has_min_y(props->hasValue("y-min")),
@@ -610,6 +730,14 @@ SGScaleAnimation::SGScaleAnimation( SGPropertyNode *prop_root,
     _max_y(props->getDoubleValue("y-max")),
     _max_z(props->getDoubleValue("z-max"))
 {
+  if ( _use_personality ) {
+    _x_factor.shuffle();
+    _x_offset.shuffle();
+    _y_factor.shuffle();
+    _y_offset.shuffle();
+    _z_factor.shuffle();
+    _z_offset.shuffle();
+  }
 }
 
 SGScaleAnimation::~SGScaleAnimation ()
@@ -618,7 +746,7 @@ SGScaleAnimation::~SGScaleAnimation ()
 }
 
 void
-SGScaleAnimation::update()
+SGScaleAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
 {
   if (_table == 0) {
       _x_scale = _prop->getDoubleValue() * _x_factor + _x_offset;
@@ -650,8 +778,10 @@ SGScaleAnimation::update()
     _z_scale = _table->interpolate(_prop->getDoubleValue());
   }
 
+  osg::Matrix _matrix;
   set_scale(_matrix, _x_scale, _y_scale, _z_scale );
-  ((ssgTransform *)_branch)->setTransform(_matrix);
+  static_cast<osg::MatrixTransform*>(_branch)->setMatrix(_matrix);
+  traverse(node, nv);
 }
 
 
@@ -661,7 +791,7 @@ SGScaleAnimation::update()
 
 SGTexRotateAnimation::SGTexRotateAnimation( SGPropertyNode *prop_root,
                                   SGPropertyNode_ptr props )
-    : SGAnimation(props, new ssgTexTrans),
+    : SGAnimation(props, new osg::Group),
       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
       _offset_deg(props->getDoubleValue("offset-deg", 0.0)),
       _factor(props->getDoubleValue("factor", 1.0)),
@@ -670,15 +800,24 @@ SGTexRotateAnimation::SGTexRotateAnimation( 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 *node = props->getChild("condition");
+  if (node != 0)
+    _condition = sgReadCondition(prop_root, node);
+
   _center[0] = props->getFloatValue("center/x", 0);
   _center[1] = props->getFloatValue("center/y", 0);
   _center[2] = props->getFloatValue("center/z", 0);
   _axis[0] = props->getFloatValue("axis/x", 0);
   _axis[1] = props->getFloatValue("axis/y", 0);
   _axis[2] = props->getFloatValue("axis/z", 0);
-  sgNormalizeVec3(_axis);
+  _axis.normalize();
+
+  osg::StateSet* stateSet = _branch->getOrCreateStateSet();
+  _texMat = new osg::TexMat;
+  stateSet->setTextureAttribute(0, _texMat.get());
 }
 
 SGTexRotateAnimation::~SGTexRotateAnimation ()
@@ -687,19 +826,23 @@ SGTexRotateAnimation::~SGTexRotateAnimation ()
 }
 
 void
-SGTexRotateAnimation::update()
+SGTexRotateAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
 {
-  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 || _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());
+    }
+    osg::Matrix _matrix;
+    set_rotation(_matrix, _position_deg, _center, _axis);
+    _texMat->setMatrix(_matrix);
   }
-  set_rotation(_matrix, _position_deg, _center, _axis);
-  ((ssgTexTrans *)_branch)->setTransform(_matrix);
+  traverse(node, nv);
 }
 
 
@@ -709,7 +852,7 @@ SGTexRotateAnimation::update()
 
 SGTexTranslateAnimation::SGTexTranslateAnimation( SGPropertyNode *prop_root,
                                         SGPropertyNode_ptr props )
-  : SGAnimation(props, new ssgTexTrans),
+  : SGAnimation(props, new osg::Group),
       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
     _offset(props->getDoubleValue("offset", 0.0)),
     _factor(props->getDoubleValue("factor", 1.0)),
@@ -720,12 +863,21 @@ SGTexTranslateAnimation::SGTexTranslateAnimation( SGPropertyNode *prop_root,
     _min(props->getDoubleValue("min")),
     _has_max(props->hasValue("max")),
     _max(props->getDoubleValue("max")),
-    _position(props->getDoubleValue("starting-position", 0))
+    _position(props->getDoubleValue("starting-position", 0)),
+    _condition(0)
 {
+  SGPropertyNode *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);
-  sgNormalizeVec3(_axis);
+  _axis.normalize();
+
+  osg::StateSet* stateSet = _branch->getOrCreateStateSet();
+  _texMat = new osg::TexMat;
+  stateSet->setTextureAttribute(0, _texMat.get());
 }
 
 SGTexTranslateAnimation::~SGTexTranslateAnimation ()
@@ -734,19 +886,23 @@ SGTexTranslateAnimation::~SGTexTranslateAnimation ()
 }
 
 void
-SGTexTranslateAnimation::update()
+SGTexTranslateAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
 {
-  if (_table == 0) {
-    _position = (apply_mods(_prop->getDoubleValue(), _step, _scroll) + _offset) * _factor;
-    if (_has_min && _position < _min)
-      _position = _min;
-    if (_has_max && _position > _max)
-      _position = _max;
-  } else {
-    _position = _table->interpolate(apply_mods(_prop->getDoubleValue(), _step, _scroll));
+  if (!_condition || _condition->test()) {
+    if (_table == 0) {
+      _position = (apply_mods(_prop->getDoubleValue(), _step, _scroll) + _offset) * _factor;
+      if (_has_min && _position < _min)
+        _position = _min;
+      if (_has_max && _position > _max)
+        _position = _max;
+    } else {
+      _position = _table->interpolate(apply_mods(_prop->getDoubleValue(), _step, _scroll));
+    }
+    osg::Matrix _matrix;
+    set_translation(_matrix, _position, _axis);
+    _texMat->setMatrix(_matrix);
   }
-  set_translation(_matrix, _position, _axis);
-  ((ssgTexTrans *)_branch)->setTransform(_matrix);
+  traverse(node, nv);
 }
 
 
@@ -756,7 +912,7 @@ SGTexTranslateAnimation::update()
 
 SGTexMultipleAnimation::SGTexMultipleAnimation( SGPropertyNode *prop_root,
                                         SGPropertyNode_ptr props )
-  : SGAnimation(props, new ssgTexTrans),
+  : SGAnimation(props, new osg::Group),
       _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true))
 {
   unsigned int i;
@@ -788,7 +944,7 @@ SGTexMultipleAnimation::SGTexMultipleAnimation( SGPropertyNode *prop_root,
       _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
       _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
       _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
-      sgNormalizeVec3(_transform[i].axis);
+      _transform[i].axis.normalize();
       _num_transforms++;
     } else if (!strcmp("texrotate",transform_nodes[i]->getStringValue("subtype", 0))) {
 
@@ -811,24 +967,26 @@ SGTexMultipleAnimation::SGTexMultipleAnimation( SGPropertyNode *prop_root,
       _transform[i].axis[0] = transform_props->getFloatValue("axis/x", 0);
       _transform[i].axis[1] = transform_props->getFloatValue("axis/y", 0);
       _transform[i].axis[2] = transform_props->getFloatValue("axis/z", 0);
-      sgNormalizeVec3(_transform[i].axis);
+      _transform[i].axis.normalize();
       _num_transforms++;
     }
   }
+  osg::StateSet* stateSet = _branch->getOrCreateStateSet();
+  _texMat = new osg::TexMat;
+  stateSet->setTextureAttribute(0, _texMat.get());
 }
 
 SGTexMultipleAnimation::~SGTexMultipleAnimation ()
 {
-  // delete _table;
-  delete _transform;
+   delete [] _transform;
 }
 
 void
-SGTexMultipleAnimation::update()
+SGTexMultipleAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
 {
   int i;
-  sgMat4 tmatrix;
-  sgMakeIdentMat4(tmatrix);
+  osg::Matrix tmatrix;
+  tmatrix.makeIdentity();
   for (i = 0; i < _num_transforms; i++) {
 
     if(_transform[i].subtype == 0) {
@@ -843,8 +1001,9 @@ SGTexMultipleAnimation::update()
       } else {
          _transform[i].position = _transform[i].table->interpolate(apply_mods(_transform[i].prop->getDoubleValue(), _transform[i].step,_transform[i].scroll));
       }
-      set_translation(_transform[i].matrix, _transform[i].position, _transform[i].axis);
-      sgPreMultMat4(tmatrix, _transform[i].matrix);
+      osg::Matrix matrix;
+      set_translation(matrix, _transform[i].position, _transform[i].axis);
+      tmatrix = matrix*tmatrix;
 
     } else if (_transform[i].subtype == 1) {
 
@@ -859,11 +1018,14 @@ SGTexMultipleAnimation::update()
      } else {
         _transform[i].position = _transform[i].table->interpolate(_transform[i].prop->getDoubleValue());
       }
-      set_rotation(_transform[i].matrix, _transform[i].position, _transform[i].center, _transform[i].axis);
-      sgPreMultMat4(tmatrix, _transform[i].matrix);
+
+      osg::Matrix matrix;
+      set_rotation(matrix, _transform[i].position, _transform[i].center, _transform[i].axis);
+      tmatrix = matrix*tmatrix;
     }
   }
-  ((ssgTexTrans *)_branch)->setTransform(tmatrix);
+  _texMat->setMatrix(tmatrix);
+  traverse(node, nv);
 }
 
 
@@ -873,7 +1035,7 @@ SGTexMultipleAnimation::update()
 ////////////////////////////////////////////////////////////////////////
 
 SGAlphaTestAnimation::SGAlphaTestAnimation(SGPropertyNode_ptr props)
-  : SGAnimation(props, new ssgBranch)
+  : SGAnimation(props, new osg::Group)
 {
   _alpha_clamp = props->getFloatValue("alpha-factor", 0.0);
 }
@@ -884,22 +1046,594 @@ SGAlphaTestAnimation::~SGAlphaTestAnimation ()
 
 void SGAlphaTestAnimation::init()
 {
-  setAlphaClampToBranch(_branch,_alpha_clamp);
+  osg::StateSet* stateSet = _branch->getOrCreateStateSet();
+  osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
+  alphaFunc->setFunction(osg::AlphaFunc::GREATER);
+  alphaFunc->setReferenceValue(_alpha_clamp);
+  stateSet->setAttribute(alphaFunc);
+  stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
+  stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
 }
 
-void SGAlphaTestAnimation::setAlphaClampToBranch(ssgBranch *b, float clamp)
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of SGMaterialAnimation
+////////////////////////////////////////////////////////////////////////
+
+SGMaterialAnimation::SGMaterialAnimation( SGPropertyNode *prop_root,
+        SGPropertyNode_ptr props, const SGPath &texture_path)
+    : SGAnimation(props, new osg::Group),
+    _last_condition(false),
+    _prop_root(prop_root),
+    _prop_base(""),
+    _texture_base(texture_path),
+    _read(0),
+    _update(0),
+    _global(props->getBoolValue("global", false))
 {
-  int nb = b->getNumKids();
-  for (int i = 0; i<nb; i++) {
-    ssgEntity *e = b->getKid(i);
-    if (e->isAKindOf(ssgTypeLeaf())) {
-      ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
-      s->enable( GL_ALPHA_TEST );
-      s->setAlphaClamp( clamp );
-    } else if (e->isAKindOf(ssgTypeBranch())) {
-      setAlphaClampToBranch( (ssgBranch*)e, clamp );
+    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);
+        _texture2D = SGLoadTexture2D(_texture);
+        _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;
+
+    _alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0);
+}
+
+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);
+
+    // OSGFIXME
+    osg::StateSet* stateSet = _branch->getOrCreateStateSet();
+    if (_update & THRESHOLD) {
+      stateSet->setAttribute(_alphaFunc.get(), osg::StateAttribute::OVERRIDE);
+      stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
+    }
+    if (_update & TEXTURE) {
+      stateSet->setTextureAttribute(0, _texture2D.get(), osg::StateAttribute::OVERRIDE);
+      stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
+    }
+}
+
+void
+SGMaterialAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
+{
+    if (_condition) {
+        bool cond = _condition->test();
+        if (cond && !_last_condition)
+            _update |= _static_update;
+
+        _last_condition = cond;
+        if (!cond) {
+            traverse(node, nv);
+            return;
+        }
+    }
+
+    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;
+    }
+    traverse(node, nv);
+}
+
+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;
+}
+
+class SGMaterialAnimationCloneVisitor : public osg::NodeVisitor {
+public:
+  SGMaterialAnimationCloneVisitor() :
+    osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
+  {
+    setVisitorType(osg::NodeVisitor::NODE_VISITOR);
+  }
+  virtual void apply(osg::Node& node)
+  {
+    traverse(node);
+    osg::StateSet* stateSet = node.getStateSet();
+    if (!stateSet)
+      return;
+    if (1 < stateSet->referenceCount()) {
+      osg::CopyOp copyOp(osg::CopyOp::DEEP_COPY_STATESETS);
+      osg::Object* object = stateSet->clone(copyOp);
+      stateSet = static_cast<osg::StateSet*>(object);
+      node.setStateSet(stateSet);
+    }
+    cloneMaterial(stateSet);
+  }
+  virtual void apply(osg::Geode& node)
+  {
+    apply((osg::Node&)node);
+    traverse(node);
+    unsigned nDrawables = node.getNumDrawables();
+    for (unsigned i = 0; i < nDrawables; ++i) {
+      osg::Drawable* drawable = node.getDrawable(i);
+      osg::StateSet* stateSet = drawable->getStateSet();
+      if (!stateSet)
+        continue;
+      if (1 < stateSet->referenceCount()) {
+        osg::CopyOp copyOp(osg::CopyOp::DEEP_COPY_STATESETS);
+        osg::Object* object = stateSet->clone(copyOp);
+        stateSet = static_cast<osg::StateSet*>(object);
+        drawable->setStateSet(stateSet);
+      }
+      cloneMaterial(stateSet);
+    }
+  }
+  void cloneMaterial(osg::StateSet* stateSet)
+  {
+    
+    osg::StateAttribute* stateAttr;
+    stateAttr = stateSet->getAttribute(osg::StateAttribute::MATERIAL);
+    if (!stateAttr)
+      return;
+    osg::CopyOp copyOp(osg::CopyOp::DEEP_COPY_STATEATTRIBUTES);
+    osg::Object* object = stateAttr->clone(copyOp);
+    osg::Material* material = static_cast<osg::Material*>(object);
+    materialList.push_back(material);
+    while (stateSet->getAttribute(osg::StateAttribute::MATERIAL)) {
+      stateSet->removeAttribute(osg::StateAttribute::MATERIAL);
+    }
+    stateSet->setAttribute(material);
+  }
+  std::vector<osg::Material*> materialList;
+};
+
+void SGMaterialAnimation::cloneMaterials(osg::Group *b)
+{
+  SGMaterialAnimationCloneVisitor cloneVisitor;
+  b->accept(cloneVisitor);
+  _materialList.swap(cloneVisitor.materialList);
+}
+
+void SGMaterialAnimation::setMaterialBranch(osg::Group *b)
+{
+  std::vector<osg::Material*>::iterator i;
+  for (i = _materialList.begin(); i != _materialList.end(); ++i) {
+    osg::Material* material = *i;
+    if (_update & DIFFUSE) {
+      osg::Vec4 v = _diff.rgba();
+      float alpha = material->getDiffuse(osg::Material::FRONT_AND_BACK)[3];
+      material->setColorMode(osg::Material::DIFFUSE);
+      material->setDiffuse(osg::Material::FRONT_AND_BACK,
+                           osg::Vec4(v[0], v[1], v[2], alpha));
+    }
+    if (_update & AMBIENT) {
+      material->setColorMode(osg::Material::AMBIENT);
+      material->setDiffuse(osg::Material::FRONT_AND_BACK, _amb.rgba());
+    }
+    if (_update & EMISSION)
+      material->setEmission(osg::Material::FRONT_AND_BACK, _emis.rgba());
+    if (_update & SPECULAR)
+      material->setSpecular(osg::Material::FRONT_AND_BACK, _spec.rgba());
+    if (_update & SHININESS)
+      material->setShininess(osg::Material::FRONT_AND_BACK,
+                             clamp(_shi, 0.0, 128.0));
+    if (_update & TRANSPARENCY) {
+      osg::Vec4 v = material->getDiffuse(osg::Material::FRONT_AND_BACK);
+      float trans = _trans.value * _trans.factor + _trans.offset;
+      trans = trans < _trans.min ? _trans.min : trans > _trans.max ? _trans.max : trans;
+      material->setDiffuse(osg::Material::FRONT_AND_BACK,
+                           osg::Vec4(v[0], v[1], v[2], trans));
+    }
+    if (_update & THRESHOLD)
+        _alphaFunc->setReferenceValue(clamp(_thresh));
+    // OSGFIXME
+//     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();
+//         }
+//     }
+  }
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of SGFlashAnimation
+////////////////////////////////////////////////////////////////////////
+class SGFlashAnimationTransform : public osg::Transform {
+public:
+  SGFlashAnimationTransform(SGPropertyNode* props)
+  {
+    getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
+
+    _axis[0] = props->getFloatValue("axis/x", 0);
+    _axis[1] = props->getFloatValue("axis/y", 0);
+    _axis[2] = props->getFloatValue("axis/z", 1);
+    _axis.normalize();
+    
+    _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);
+  }
+
+  virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
+                                         osg::NodeVisitor* nv) const 
+  {
+    double scale_factor = computeScaleFactor(nv);
+    osg::Matrix 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 );
+    if (_referenceFrame == RELATIVE_RF)
+      matrix.preMult(transform);
+    else
+      matrix = transform;
+
+    return true;
   }
+  
+  virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
+                                         osg::NodeVisitor* nv) const
+  {
+    double scale_factor = computeScaleFactor(nv);
+    if (fabs(scale_factor) <= std::numeric_limits<double>::min())
+      return false;
+    osg::Matrix transform;
+    double rScaleFactor = 1/scale_factor;
+    transform(0,0) = rScaleFactor;
+    transform(1,1) = rScaleFactor;
+    transform(2,2) = rScaleFactor;
+    transform(3,0) = rScaleFactor*_center[0] * ( scale_factor - 1 );
+    transform(3,1) = rScaleFactor*_center[1] * ( scale_factor - 1 );
+    transform(3,2) = rScaleFactor*_center[2] * ( scale_factor - 1 );
+    if (_referenceFrame == RELATIVE_RF)
+      matrix.postMult(transform);
+    else
+      matrix = transform;
+    return true;
+  }
+
+  double computeScaleFactor(osg::NodeVisitor* nv) const
+  {
+    if (!nv)
+      return 1;
+
+    osg::Vec3 localEyeToCenter = nv->getEyePoint() - _center;
+    localEyeToCenter.normalize();
+
+    double cos_angle = localEyeToCenter*_axis;
+    double scale_factor = 0;
+    if ( _two_sides && cos_angle < 0 )
+      scale_factor = _factor * pow( -cos_angle, _power ) + _offset;
+    else if ( cos_angle > 0 )
+      scale_factor = _factor * pow( cos_angle, _power ) + _offset;
+    
+    if ( scale_factor < _min_v )
+      scale_factor = _min_v;
+    if ( scale_factor > _max_v )
+      scale_factor = _max_v;
+
+    return scale_factor;
+  }
+
+private:
+  osg::Vec3 _axis, _center;
+  double _power, _factor, _offset, _min_v, _max_v;
+  bool _two_sides;
+};
+
+SGFlashAnimation::SGFlashAnimation(SGPropertyNode_ptr props)
+  : SGAnimation( props, new SGFlashAnimationTransform(props) )
+{
+}
+
+SGFlashAnimation::~SGFlashAnimation()
+{
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of SGDistScaleAnimation
+////////////////////////////////////////////////////////////////////////
+class SGDistScaleTransform : public osg::Transform {
+public:
+  SGDistScaleTransform(SGPropertyNode* props)
+  {
+    getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
+
+    _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);
+  }
+  ~SGDistScaleTransform()
+  {
+    delete _table;
+  }
+
+  virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
+                                         osg::NodeVisitor* nv) const 
+  {
+    osg::Matrix transform;
+    double scale_factor = computeScaleFactor(nv);
+    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 );
+    if (_referenceFrame == RELATIVE_RF)
+      matrix.preMult(transform);
+    else
+      matrix = transform;
+    return true;
+  }
+  
+  virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
+                                         osg::NodeVisitor* nv) const
+  {
+    double scale_factor = computeScaleFactor(nv);
+    if (fabs(scale_factor) <= std::numeric_limits<double>::min())
+      return false;
+    osg::Matrix transform;
+    double rScaleFactor = 1/scale_factor;
+    transform(0,0) = rScaleFactor;
+    transform(1,1) = rScaleFactor;
+    transform(2,2) = rScaleFactor;
+    transform(3,0) = rScaleFactor*_center[0] * ( scale_factor - 1 );
+    transform(3,1) = rScaleFactor*_center[1] * ( scale_factor - 1 );
+    transform(3,2) = rScaleFactor*_center[2] * ( scale_factor - 1 );
+    if (_referenceFrame == RELATIVE_RF)
+      matrix.postMult(transform);
+    else
+      matrix = transform;
+    return true;
+  }
+
+  double computeScaleFactor(osg::NodeVisitor* nv) const
+  {
+    if (!nv)
+      return 1;
+
+    osg::Vec3 localEyeToCenter = _center - nv->getEyePoint();
+    double scale_factor = localEyeToCenter.length();
+    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 );
+    }
+
+    return scale_factor;
+  }
+
+
+private:
+  osg::Vec3 _center;
+  float _factor, _offset, _min_v, _max_v;
+  bool _has_min, _has_max;
+  SGInterpTable * _table;
+};
+
+SGDistScaleAnimation::SGDistScaleAnimation(SGPropertyNode_ptr props)
+  : SGAnimation( props, new SGDistScaleTransform(props) )
+{
+}
+
+SGDistScaleAnimation::~SGDistScaleAnimation()
+{
+}
+
+////////////////////////////////////////////////////////////////////////
+// Implementation of SGShadowAnimation
+////////////////////////////////////////////////////////////////////////
+
+SGShadowAnimation::SGShadowAnimation ( SGPropertyNode *prop_root,
+                                       SGPropertyNode_ptr props )
+  : SGAnimation(props, new osg::Group),
+    _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;
+}
+
+void
+SGShadowAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
+{
+    if (_condition)
+        _condition_value = _condition->test();
+
+    if ( _condition_value ) {
+        _branch->setNodeMask(SG_NODEMASK_SHADOW_BIT|_branch->getNodeMask());
+    } else {
+        _branch->setNodeMask(~SG_NODEMASK_SHADOW_BIT&_branch->getNodeMask());
+    }
+    traverse(node, nv);
+}
+
+bool SGShadowAnimation::get_condition_value(void) {
+    return _condition_value;
 }
 
 // end of animation.cxx