]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/model/animation.cxx
model.[ch]xx:
[simgear.git] / simgear / scene / model / animation.cxx
index b17b14384027e62fc4b003f75b876869ea759599..faec6334f9751a4319eea14c6caeaa61d2cb0c00 100644 (file)
@@ -3,6 +3,9 @@
 //
 // 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>
@@ -179,7 +182,8 @@ 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 ) ) {
@@ -293,7 +297,7 @@ SGRangeAnimation::update()
     ranges[1] = 1000000000.f;
   }
   ((ssgRangeSelector *)_branch)->setRanges(ranges, 2);
-  return 1;
+  return 2;
 }
 
 
@@ -339,7 +343,7 @@ SGSelectAnimation::update()
       ((ssgSelector *)_branch)->select(0xffff);
   else
       ((ssgSelector *)_branch)->select(0x0000);
-  return 1;
+  return 2;
 }
 
 
@@ -630,14 +634,18 @@ SGRotateAnimation::SGRotateAnimation( SGPropertyNode *prop_root,
     _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;
@@ -645,15 +653,12 @@ 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);
 }
@@ -679,7 +684,7 @@ SGRotateAnimation::update()
     set_rotation(_matrix, _position_deg, _center, _axis);
     ((ssgTransform *)_branch)->setTransform(_matrix);
   }
-  return 1;
+  return 2;
 }
 
 \f
@@ -770,7 +775,7 @@ SGTranslateAnimation::update()
 {
   if (_condition == 0 || _condition->test()) {
     if (_table == 0) {
-      _position_m = (_prop->getDoubleValue() + _offset_m) * _factor;
+      _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)
@@ -781,7 +786,7 @@ SGTranslateAnimation::update()
     set_translation(_matrix, _position_m, _axis);
     ((ssgTransform *)_branch)->setTransform(_matrix);
   }
-  return 1;
+  return 2;
 }
 
 
@@ -856,7 +861,7 @@ SGScaleAnimation::update()
 
   set_scale(_matrix, _x_scale, _y_scale, _z_scale );
   ((ssgTransform *)_branch)->setTransform(_matrix);
-  return 1;
+  return 2;
 }
 
 
@@ -905,7 +910,7 @@ SGTexRotateAnimation::update()
   }
   set_rotation(_matrix, _position_deg, _center, _axis);
   ((ssgTexTrans *)_branch)->setTransform(_matrix);
-  return 1;
+  return 2;
 }
 
 
@@ -953,7 +958,7 @@ SGTexTranslateAnimation::update()
   }
   set_translation(_matrix, _position, _axis);
   ((ssgTexTrans *)_branch)->setTransform(_matrix);
-  return 1;
+  return 2;
 }
 
 
@@ -1070,7 +1075,7 @@ SGTexMultipleAnimation::update()
     }
   }
   ((ssgTexTrans *)_branch)->setTransform(tmatrix);
-  return 1;
+  return 2;
 }
 
 
@@ -1112,95 +1117,275 @@ void SGAlphaTestAnimation::setAlphaClampToBranch(ssgBranch *b, float clamp)
 
 \f
 ////////////////////////////////////////////////////////////////////////
-// Implementation of SGEmissionAnimation
+// Implementation of SGMaterialAnimation
 ////////////////////////////////////////////////////////////////////////
 
-SGEmissionAnimation::SGEmissionAnimation( SGPropertyNode *prop_root, SGPropertyNode_ptr props)
-  : SGAnimation(props, new ssgBranch),
-   _prop((SGPropertyNode *)prop_root->getNode(props->getStringValue("property", "/null"), true)),
-  _color0(props->getFloatValue("emiss-red", 0.0)),
-  _color1(props->getFloatValue("emiss-green", 0.0)),
-  _color2(props->getFloatValue("emiss-blue", 0.0)),
-  _old_brightness(0.0),
-  _cached_material(0),
-  _cloned_material(0)
-{
+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;
 }
 
-SGEmissionAnimation::~SGEmissionAnimation ()
+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 SGEmissionAnimation::init()
+void SGMaterialAnimation::init()
 {
-    // clone material state(s) for this branch
-    cloneMaterials(_branch);
+    if (!_global)
+        cloneMaterials(_branch);
 }
 
-void SGEmissionAnimation::cloneMaterials(ssgBranch *b)
+int SGMaterialAnimation::update()
 {
-    // clone material state(s) for this branch
-    int nb = b->getNumKids();
+    if (_condition) {
+        bool cond = _condition->test();
+        if (cond && !_last_condition)
+            _update |= _static_update;
 
-    // Traverse the branch(es) and make clones of material settings for the leaves on 
-    // this branch (ssgSimpleState objects). 
-    // Try to be efficient (only make a new clone if the original is different
-    // than the previous).
+        _last_condition = cond;
+        if (!cond)
+            return 2;
+    }
 
-    for (int i = 0; i<nb; i++) {
-      ssgEntity *e = b->getKid(i);
-      if (e->isAKindOf(ssgTypeLeaf())) {
-        ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
-        // if this is a new material state, then make a copy of it...
-        if (!_cached_material || _cached_material != s) {
-           _cached_material = s;
-           _cloned_material = (ssgSimpleState*)s->clone(SSG_CLONE_STATE);
+    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;
         }
-        // set the material to the clone...
-        ((ssgLeaf*)e)->setState( _cloned_material );
-      } else if (e->isAKindOf(ssgTypeBranch())) {
-        cloneMaterials( (ssgBranch*)e );
-      }
     }
+    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;
 }
 
-int SGEmissionAnimation::update()
+void SGMaterialAnimation::cloneMaterials(ssgBranch *b)
 {
-  float brightness = _prop->getFloatValue();
+    for (int i = 0; i < b->getNumKids(); i++)
+        cloneMaterials((ssgBranch *)b->getKid(i));
 
-  // clamp brightness 0 ~ 1
-  if (brightness < 0.00) brightness = 0.00;
-  if (brightness > 1.00) brightness = 1.00;
+    if (!b->isAKindOf(ssgTypeLeaf()) || !((ssgLeaf *)b)->hasState())
+        return;
 
-  // no need to update states unless something changes...
-  if (brightness != _old_brightness) {
-    _old_brightness = brightness; // save it
-    float rd,gr,bl;
-    rd = _color0 * brightness;
-    gr = _color1 * brightness;
-    bl = _color2 * brightness;
-    setEmissionBranch(_branch, rd, gr, bl);
-  }
-  return 1;
+    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 SGEmissionAnimation::setEmissionBranch(ssgBranch *b, float color0, float color1, float color2)
+void SGMaterialAnimation::setMaterialBranch(ssgBranch *b)
 {
-  int nb = b->getNumKids();
+    for (int i = 0; i < b->getNumKids(); i++)
+        setMaterialBranch((ssgBranch *)b->getKid(i));
 
-  for (int i = 0; i<nb; i++) {
-    ssgEntity *e = b->getKid(i);
-    if (e->isAKindOf(ssgTypeLeaf())) {
-      ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
-      s->setMaterial( GL_EMISSION, color0, color1, color2, 0.0 );
-    } else if (e->isAKindOf(ssgTypeBranch())) {
-      setEmissionBranch((ssgBranch*)e, color0, color1, color2);
+    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
 ////////////////////////////////////////////////////////////////////////
@@ -1330,4 +1515,39 @@ void SGDistScaleAnimation::distScaleCallback( sgMat4 r, sgFrustum *f, sgMat4 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