X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fscene%2Fmodel%2Fanimation.cxx;h=80c08be2bfc5b002f68728229b3644471df9b3b4;hb=d04cf4d8978866eb80a1639b6d4ddfe387338c77;hp=a894b7ca8b020c012f4c1d1845bd73742b0c8dbb;hpb=d534cf6f02e773fb8270b480e76a78a735598ac8;p=simgear.git diff --git a/simgear/scene/model/animation.cxx b/simgear/scene/model/animation.cxx index a894b7ca..80c08be2 100644 --- a/simgear/scene/model/animation.cxx +++ b/simgear/scene/model/animation.cxx @@ -10,12 +10,18 @@ #include // for strcmp() #include #include +#include + +#include +#include +#include #include #include #include #include #include +#include #include #include #include @@ -24,6 +30,10 @@ #include #include #include +#include +#include +#include + #include #include @@ -36,7 +46,15 @@ #include "animation.hxx" #include "model.hxx" +#include "SGTranslateTransform.hxx" #include "SGMaterialAnimation.hxx" +#include "SGRotateTransform.hxx" +#include "SGScaleTransform.hxx" +#include "SGInteractionAnimation.hxx" + +using OpenThreads::Mutex; +using OpenThreads::ReentrantMutex; +using OpenThreads::ScopedLock; //////////////////////////////////////////////////////////////////////// @@ -101,35 +119,6 @@ set_translation (osg::Matrix &matrix, double position_m, const SGVec3d &axis) matrix(3, 2) = xyz[2]; } -/** - * Modify property value by step and scroll settings in texture translations - */ -static double -apply_mods(double property, double step, double scroll) -{ - - double modprop; - if(step > 0) { - double scrollval = 0.0; - if(scroll > 0) { - // calculate scroll amount (for odometer like movement) - double remainder = step - fmod(fabs(property), step); - if (remainder < scroll) { - scrollval = (scroll - remainder) / scroll * step; - } - } - // apply stepping of input value - if(property > 0) - modprop = ((floor(property/step) * step) + scrollval); - else - modprop = ((ceil(property/step) * step) + scrollval); - } else { - modprop = property; - } - return modprop; - -} - /** * Read an interpolation table from properties. */ @@ -142,195 +131,109 @@ read_interpolation_table(const SGPropertyNode* props) return new SGInterpTable(table_node); } -//////////////////////////////////////////////////////////////////////// -// Utility value classes -//////////////////////////////////////////////////////////////////////// -class SGScaleOffsetValue : public SGDoubleValue { -public: - SGScaleOffsetValue(SGPropertyNode const* propertyNode) : - _propertyNode(propertyNode), - _scale(1), - _offset(0), - _min(-SGLimitsd::max()), - _max(SGLimitsd::max()) - { } - void setScale(double scale) - { _scale = scale; } - void setOffset(double offset) - { _offset = offset; } - void setMin(double min) - { _min = min; } - void setMax(double max) - { _max = max; } - - virtual double getValue() const - { - double value = _propertyNode ? _propertyNode->getDoubleValue() : 0; - return std::min(_max, std::max(_min, _offset + _scale*value)); - } -private: - SGSharedPtr _propertyNode; - double _scale; - double _offset; - double _min; - double _max; -}; +static std::string +unit_string(const char* value, const char* unit) +{ + return std::string(value) + unit; +} -class SGPersScaleOffsetValue : public SGDoubleValue { +class SGPersonalityScaleOffsetExpression : public SGUnaryExpression { public: - SGPersScaleOffsetValue(SGPropertyNode const* propertyNode, - SGPropertyNode const* config, - const char* scalename, const char* offsetname, - double defScale = 1, double defOffset = 0) : - _propertyNode(propertyNode), - _scale(config, scalename, defScale), - _offset(config, offsetname, defOffset), - _min(-SGLimitsd::max()), - _max(SGLimitsd::max()) + SGPersonalityScaleOffsetExpression(SGExpression* expr, + SGPropertyNode const* config, + const std::string& scalename, + const std::string& offsetname, + double defScale = 1, + double defOffset = 0) : + SGUnaryExpression(expr), + _scale(config, scalename.c_str(), defScale), + _offset(config, offsetname.c_str(), defOffset) { } void setScale(double scale) { _scale = scale; } void setOffset(double offset) { _offset = offset; } - void setMin(double min) - { _min = min; } - void setMax(double max) - { _max = max; } - virtual double getValue() const + virtual void eval(double& value, const simgear::expression::Binding* b) const { _offset.shuffle(); _scale.shuffle(); - double value = _propertyNode ? _propertyNode->getDoubleValue() : 0; - return SGMiscd::clip(_offset + _scale*value, _min, _max); + value = _offset + _scale*getOperand()->getValue(b); } + + virtual bool isConst() const { return false; } + private: - SGSharedPtr _propertyNode; mutable SGPersonalityParameter _scale; mutable SGPersonalityParameter _offset; - double _min; - double _max; }; -class SGInterpTableValue : public SGDoubleValue { -public: - SGInterpTableValue(SGPropertyNode const* propertyNode, - SGInterpTable const* interpTable) : - _propertyNode(propertyNode), - _interpTable(interpTable) - { } - virtual double getValue() const - { return _interpTable->interpolate(_propertyNode ? _propertyNode->getDoubleValue() : 0); } -private: - SGSharedPtr _propertyNode; - SGSharedPtr _interpTable; -}; - -class SGTexScaleOffsetValue : public SGDoubleValue { -public: - SGTexScaleOffsetValue(const SGPropertyNode* propertyNode) : - _propertyNode(propertyNode), - _scale(1), - _offset(0), - _step(0), - _scroll(0), - _min(-SGLimitsd::max()), - _max(SGLimitsd::max()) - { } - void setScale(double scale) - { _scale = scale; } - void setOffset(double offset) - { _offset = offset; } - void setStep(double step) - { _step = step; } - void setScroll(double scroll) - { _scroll = scroll; } - void setMin(double min) - { _min = min; } - void setMax(double max) - { _max = max; } - - virtual double getValue() const - { - double value = _propertyNode ? _propertyNode->getDoubleValue() : 0; - value = apply_mods(value, _step, _scroll); - return SGMiscd::clip(_scale*(_offset + value), _min, _max); - } -private: - SGSharedPtr _propertyNode; - double _scale; - double _offset; - double _step; - double _scroll; - double _min; - double _max; -}; -class SGTexTableValue : public SGDoubleValue { -public: - SGTexTableValue(const SGPropertyNode* propertyNode, - const SGInterpTable* interpTable) : - _propertyNode(propertyNode), - _interpTable(interpTable) - { } - void setStep(double step) - { _step = step; } - void setScroll(double scroll) - { _scroll = scroll; } - virtual double getValue() const - { - double value = _propertyNode ? _propertyNode->getDoubleValue() : 0; - value = apply_mods(value, _step, _scroll); - return _interpTable->interpolate(value); - } -private: - SGSharedPtr _propertyNode; - SGSharedPtr _interpTable; - double _step; - double _scroll; -}; +static SGExpressiond* +read_factor_offset(const SGPropertyNode* configNode, SGExpressiond* expr, + const std::string& factor, const std::string& offset) +{ + double factorValue = configNode->getDoubleValue(factor, 1); + if (factorValue != 1) + expr = new SGScaleExpression(expr, factorValue); + double offsetValue = configNode->getDoubleValue(offset, 0); + if (offsetValue != 0) + expr = new SGBiasExpression(expr, offsetValue); + return expr; +} -static std::string -unit_string(const char* value, const char* unit) +static SGExpressiond* +read_offset_factor(const SGPropertyNode* configNode, SGExpressiond* expr, + const std::string& factor, const std::string& offset) { - return std::string(value) + unit; + double offsetValue = configNode->getDoubleValue(offset, 0); + if (offsetValue != 0) + expr = new SGBiasExpression(expr, offsetValue); + double factorValue = configNode->getDoubleValue(factor, 1); + if (factorValue != 1) + expr = new SGScaleExpression(expr, factorValue); + return expr; } -static SGDoubleValue* +SGExpressiond* read_value(const SGPropertyNode* configNode, SGPropertyNode* modelRoot, const char* unit, double defMin, double defMax) { - std::string inputPropertyName; - inputPropertyName = configNode->getStringValue("property", ""); - if (!inputPropertyName.empty()) { + SGExpression* value = 0; + + std::string inputPropertyName = configNode->getStringValue("property", ""); + if (inputPropertyName.empty()) { + std::string spos = unit_string("starting-position", unit); + double initPos = configNode->getDoubleValue(spos, 0); + value = new SGConstExpression(initPos); + } else { SGPropertyNode* inputProperty; - inputProperty = modelRoot->getNode(inputPropertyName.c_str(), true); - SGInterpTable* interpTable = read_interpolation_table(configNode); - if (interpTable) { - SGInterpTableValue* value; - value = new SGInterpTableValue(inputProperty, interpTable); - return value; + inputProperty = modelRoot->getNode(inputPropertyName, true); + value = new SGPropertyExpression(inputProperty); + } + + SGInterpTable* interpTable = read_interpolation_table(configNode); + if (interpTable) { + return new SGInterpTableExpression(value, interpTable); + } else { + std::string offset = unit_string("offset", unit); + std::string min = unit_string("min", unit); + std::string max = unit_string("max", unit); + + if (configNode->getBoolValue("use-personality", false)) { + value = new SGPersonalityScaleOffsetExpression(value, configNode, + "factor", offset); } else { - std::string offset = unit_string("offset", unit); - std::string min = unit_string("min", unit); - std::string max = unit_string("max", unit); - - if (configNode->getBoolValue("use-personality", false)) { - SGPersScaleOffsetValue* value; - value = new SGPersScaleOffsetValue(inputProperty, configNode, - "factor", offset.c_str()); - value->setMin(configNode->getDoubleValue(min.c_str(), defMin)); - value->setMax(configNode->getDoubleValue(max.c_str(), defMax)); - return value; - } else { - SGScaleOffsetValue* value = new SGScaleOffsetValue(inputProperty); - value->setScale(configNode->getDoubleValue("factor", 1)); - value->setOffset(configNode->getDoubleValue(offset.c_str(), 0)); - value->setMin(configNode->getDoubleValue(min.c_str(), defMin)); - value->setMax(configNode->getDoubleValue(max.c_str(), defMax)); - return value; - } + value = read_factor_offset(configNode, value, "factor", offset); } + + double minClip = configNode->getDoubleValue(min, defMin); + double maxClip = configNode->getDoubleValue(max, defMax); + if (minClip > SGMiscd::min(SGLimitsd::min(), -SGLimitsd::max()) || + maxClip < SGLimitsd::max()) + value = new SGClipExpression(value, minClip, maxClip); + + return value; } return 0; } @@ -435,6 +338,24 @@ public: } }; +namespace +{ +// Set all drawables to not use display lists. OSG will use +// glDrawArrays instead. +struct DoDrawArraysVisitor : public osg::NodeVisitor { + DoDrawArraysVisitor() : + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) + {} + void apply(osg::Geode& geode) + { + using namespace osg; + using namespace std; + + for (int i = 0; i < (int)geode.getNumDrawables(); ++i) + geode.getDrawable(i)->setUseDisplayList(false); + } +}; +} SGAnimation::SGAnimation(const SGPropertyNode* configNode, SGPropertyNode* modelRoot) : @@ -466,7 +387,8 @@ SGAnimation::~SGAnimation() bool SGAnimation::animate(osg::Node* node, const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) + SGPropertyNode* modelRoot, + const osgDB::ReaderWriter::Options* options) { std::string type = configNode->getStringValue("type", "none"); if (type == "alpha-test") { @@ -484,8 +406,11 @@ SGAnimation::animate(osg::Node* node, const SGPropertyNode* configNode, } else if (type == "flash") { SGFlashAnimation animInst(configNode, modelRoot); animInst.apply(node); + } else if (type == "interaction") { + SGInteractionAnimation animInst(configNode, modelRoot); + animInst.apply(node); } else if (type == "material") { - SGMaterialAnimation animInst(configNode, modelRoot); + SGMaterialAnimation animInst(configNode, modelRoot, options); animInst.apply(node); } else if (type == "noshadow") { SGShadowAnimation animInst(configNode, modelRoot); @@ -506,7 +431,7 @@ SGAnimation::animate(osg::Node* node, const SGPropertyNode* configNode, SGSelectAnimation animInst(configNode, modelRoot); animInst.apply(node); } else if (type == "shader") { - SGShaderAnimation animInst(configNode, modelRoot); + SGShaderAnimation animInst(configNode, modelRoot, options); animInst.apply(node); } else if (type == "textranslate" || type == "texrotate" || type == "texmultiple") { @@ -551,9 +476,9 @@ SGAnimation::install(osg::Node& node) else node.setNodeMask(~SG_NODEMASK_TERRAIN_BIT & node.getNodeMask()); if (!_disableShadow) - node.setNodeMask( SG_NODEMASK_SHADOW_BIT | node.getNodeMask()); + node.setNodeMask( SG_NODEMASK_CASTSHADOW_BIT | node.getNodeMask()); else - node.setNodeMask(~SG_NODEMASK_SHADOW_BIT & node.getNodeMask()); + node.setNodeMask(~SG_NODEMASK_CASTSHADOW_BIT & node.getNodeMask()); } osg::Group* @@ -703,58 +628,25 @@ SGGroupAnimation::createAnimationGroup(osg::Group& parent) // Implementation of translate animation //////////////////////////////////////////////////////////////////////// -class SGTranslateAnimation::Transform : public osg::Transform { -public: - Transform() : - _axis(0, 0, 0), - _value(0) - { setReferenceFrame(RELATIVE_RF); } - void setAxis(const SGVec3d& axis) - { _axis = axis; dirtyBound(); } - void setValue(double value) - { _value = value; dirtyBound(); } - virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, - osg::NodeVisitor* nv) const - { - assert(_referenceFrame == RELATIVE_RF); - osg::Matrix tmp; - set_translation(tmp, _value, _axis); - matrix.preMult(tmp); - return true; - } - virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix, - osg::NodeVisitor* nv) const - { - assert(_referenceFrame == RELATIVE_RF); - osg::Matrix tmp; - set_translation(tmp, -_value, _axis); - matrix.postMult(tmp); - return true; - } -private: - SGVec3d _axis; - double _value; -}; - class SGTranslateAnimation::UpdateCallback : public osg::NodeCallback { public: UpdateCallback(SGCondition const* condition, - SGDoubleValue const* animationValue) : + SGExpressiond const* animationValue) : _condition(condition), _animationValue(animationValue) { } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { if (!_condition || _condition->test()) { - SGTranslateAnimation::Transform* transform; - transform = static_cast(node); + SGTranslateTransform* transform; + transform = static_cast(node); transform->setValue(_animationValue->getValue()); } traverse(node, nv); } public: SGSharedPtr _condition; - SGSharedPtr _animationValue; + SGSharedPtr _animationValue; }; SGTranslateAnimation::SGTranslateAnimation(const SGPropertyNode* configNode, @@ -762,25 +654,39 @@ SGTranslateAnimation::SGTranslateAnimation(const SGPropertyNode* configNode, SGAnimation(configNode, modelRoot) { _condition = getCondition(); - _animationValue = read_value(configNode, modelRoot, "-m", - -SGLimitsd::max(), SGLimitsd::max()); - _axis[0] = configNode->getDoubleValue("axis/x", 0); - _axis[1] = configNode->getDoubleValue("axis/y", 0); - _axis[2] = configNode->getDoubleValue("axis/z", 0); + SGSharedPtr value; + value = read_value(configNode, modelRoot, "-m", + -SGLimitsd::max(), SGLimitsd::max()); + _animationValue = value->simplify(); + if (_animationValue) + _initialValue = _animationValue->getValue(); + else + _initialValue = 0; + + if (configNode->hasValue("axis/x1-m")) { + SGVec3d v1, v2; + v1[0] = configNode->getDoubleValue("axis/x1-m", 0); + v1[1] = configNode->getDoubleValue("axis/y1-m", 0); + v1[2] = configNode->getDoubleValue("axis/z1-m", 0); + v2[0] = configNode->getDoubleValue("axis/x2-m", 0); + v2[1] = configNode->getDoubleValue("axis/y2-m", 0); + v2[2] = configNode->getDoubleValue("axis/z2-m", 0); + _axis = v2 - v1; + } else { + _axis[0] = configNode->getDoubleValue("axis/x", 0); + _axis[1] = configNode->getDoubleValue("axis/y", 0); + _axis[2] = configNode->getDoubleValue("axis/z", 0); + } if (8*SGLimitsd::min() < norm(_axis)) _axis = normalize(_axis); - - _initialValue = configNode->getDoubleValue("starting-position-m", 0); - _initialValue *= configNode->getDoubleValue("factor", 1); - _initialValue += configNode->getDoubleValue("offset-m", 0); } osg::Group* SGTranslateAnimation::createAnimationGroup(osg::Group& parent) { - Transform* transform = new Transform; + SGTranslateTransform* transform = new SGTranslateTransform; transform->setName("translate animation"); - if (_animationValue) { + if (_animationValue && !_animationValue->isConst()) { UpdateCallback* uc = new UpdateCallback(_condition, _animationValue); transform->setUpdateCallback(uc); } @@ -795,78 +701,31 @@ SGTranslateAnimation::createAnimationGroup(osg::Group& parent) // Implementation of rotate/spin animation //////////////////////////////////////////////////////////////////////// -class SGRotateAnimation::Transform : public osg::Transform { -public: - Transform() - { setReferenceFrame(RELATIVE_RF); } - void setCenter(const SGVec3d& center) - { _center = center; dirtyBound(); } - void setAxis(const SGVec3d& axis) - { _axis = axis; dirtyBound(); } - void setAngle(double angle) - { _angle = angle; } - double getAngle() const - { return _angle; } - virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, - osg::NodeVisitor* nv) const - { - // This is the fast path, optimize a bit - assert(_referenceFrame == RELATIVE_RF); - // FIXME optimize - osg::Matrix tmp; - set_rotation(tmp, _angle, _center, _axis); - matrix.preMult(tmp); - return true; - } - virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix, - osg::NodeVisitor* nv) const - { - assert(_referenceFrame == RELATIVE_RF); - // FIXME optimize - osg::Matrix tmp; - set_rotation(tmp, -_angle, _center, _axis); - matrix.postMult(tmp); - return true; - } - virtual osg::BoundingSphere computeBound() const - { - osg::BoundingSphere bs = osg::Group::computeBound(); - osg::BoundingSphere centerbs(_center.osg(), bs.radius()); - centerbs.expandBy(bs); - return centerbs; - } - -private: - SGVec3d _center; - SGVec3d _axis; - double _angle; -}; - class SGRotateAnimation::UpdateCallback : public osg::NodeCallback { public: UpdateCallback(SGCondition const* condition, - SGDoubleValue const* animationValue) : + SGExpressiond const* animationValue) : _condition(condition), _animationValue(animationValue) { } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { if (!_condition || _condition->test()) { - SGRotateAnimation::Transform* transform; - transform = static_cast(node); - transform->setAngle(_animationValue->getValue()); + SGRotateTransform* transform; + transform = static_cast(node); + transform->setAngleDeg(_animationValue->getValue()); } traverse(node, nv); } public: SGSharedPtr _condition; - SGSharedPtr _animationValue; + SGSharedPtr _animationValue; }; class SGRotateAnimation::SpinUpdateCallback : public osg::NodeCallback { public: SpinUpdateCallback(SGCondition const* condition, - SGDoubleValue const* animationValue) : + SGExpressiond const* animationValue) : _condition(condition), _animationValue(animationValue), _lastTime(-1) @@ -874,8 +733,8 @@ public: virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { if (!_condition || _condition->test()) { - SGRotateAnimation::Transform* transform; - transform = static_cast(node); + SGRotateTransform* transform; + transform = static_cast(node); double t = nv->getFrameStamp()->getReferenceTime(); double dt = 0; @@ -883,31 +742,35 @@ public: dt = t - _lastTime; _lastTime = t; double velocity_rpms = _animationValue->getValue()/60; - double angle = transform->getAngle(); + double angle = transform->getAngleDeg(); angle += dt*velocity_rpms*360; angle -= 360*floor(angle/360); - transform->setAngle(angle); + transform->setAngleDeg(angle); } traverse(node, nv); } public: SGSharedPtr _condition; - SGSharedPtr _animationValue; + SGSharedPtr _animationValue; double _lastTime; }; -SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode, SGPropertyNode* modelRoot) : +SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode, + SGPropertyNode* modelRoot) : SGAnimation(configNode, modelRoot) { std::string type = configNode->getStringValue("type", ""); _isSpin = (type == "spin"); _condition = getCondition(); - _animationValue = read_value(configNode, modelRoot, "-deg", - -SGLimitsd::max(), SGLimitsd::max()); - _initialValue = configNode->getDoubleValue("starting-position-deg", 0); - _initialValue *= configNode->getDoubleValue("factor", 1); - _initialValue += configNode->getDoubleValue("offset-deg", 0); + SGSharedPtr value; + value = read_value(configNode, modelRoot, "-deg", + -SGLimitsd::max(), SGLimitsd::max()); + _animationValue = value->simplify(); + if (_animationValue) + _initialValue = _animationValue->getValue(); + else + _initialValue = 0; _center = SGVec3d::zeros(); if (configNode->hasValue("axis/x1-m")) { @@ -936,19 +799,19 @@ SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode, SGPropert osg::Group* SGRotateAnimation::createAnimationGroup(osg::Group& parent) { - Transform* transform = new Transform; + SGRotateTransform* transform = new SGRotateTransform; transform->setName("rotate animation"); if (_isSpin) { SpinUpdateCallback* uc; uc = new SpinUpdateCallback(_condition, _animationValue); transform->setUpdateCallback(uc); - } else if (_animationValue) { + } else if (_animationValue || !_animationValue->isConst()) { UpdateCallback* uc = new UpdateCallback(_condition, _animationValue); transform->setUpdateCallback(uc); } transform->setCenter(_center); transform->setAxis(_axis); - transform->setAngle(_initialValue); + transform->setAngleDeg(_initialValue); parent.addChild(transform); return transform; } @@ -958,87 +821,10 @@ SGRotateAnimation::createAnimationGroup(osg::Group& parent) // Implementation of scale animation //////////////////////////////////////////////////////////////////////// -class SGScaleAnimation::Transform : public osg::Transform { -public: - Transform() : - _center(0, 0, 0), - _scaleFactor(1, 1, 1), - _boundScale(0) - { - setReferenceFrame(RELATIVE_RF); - } - void setCenter(const SGVec3d& center) - { - _center = center; - dirtyBound(); - } - void setScaleFactor(const SGVec3d& scaleFactor) - { - if (_boundScale < normI(scaleFactor)) - dirtyBound(); - _scaleFactor = scaleFactor; - } - void setScaleFactor(double scaleFactor) - { - if (_boundScale < fabs(scaleFactor)) - dirtyBound(); - _scaleFactor = SGVec3d(scaleFactor, scaleFactor, scaleFactor); - } - virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, - osg::NodeVisitor* nv) const - { - assert(_referenceFrame == RELATIVE_RF); - osg::Matrix transform; - transform(0,0) = _scaleFactor[0]; - transform(1,1) = _scaleFactor[1]; - transform(2,2) = _scaleFactor[2]; - transform(3,0) = _center[0]*(1 - _scaleFactor[0]); - transform(3,1) = _center[1]*(1 - _scaleFactor[1]); - transform(3,2) = _center[2]*(1 - _scaleFactor[2]); - matrix.preMult(transform); - return true; - } - virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix, - osg::NodeVisitor* nv) const - { - assert(_referenceFrame == RELATIVE_RF); - if (fabs(_scaleFactor[0]) < SGLimitsd::min()) - return false; - if (fabs(_scaleFactor[1]) < SGLimitsd::min()) - return false; - if (fabs(_scaleFactor[2]) < SGLimitsd::min()) - return false; - SGVec3d rScaleFactor(1/_scaleFactor[0], - 1/_scaleFactor[1], - 1/_scaleFactor[2]); - osg::Matrix transform; - transform(0,0) = rScaleFactor[0]; - transform(1,1) = rScaleFactor[1]; - transform(2,2) = rScaleFactor[2]; - transform(3,0) = _center[0]*(1 - rScaleFactor[0]); - transform(3,1) = _center[1]*(1 - rScaleFactor[1]); - transform(3,2) = _center[2]*(1 - rScaleFactor[2]); - matrix.postMult(transform); - return true; - } - virtual osg::BoundingSphere computeBound() const - { - osg::BoundingSphere bs = osg::Group::computeBound(); - _boundScale = normI(_scaleFactor); - bs.radius() *= _boundScale; - return bs; - } - -private: - SGVec3d _center; - SGVec3d _scaleFactor; - mutable double _boundScale; -}; - class SGScaleAnimation::UpdateCallback : public osg::NodeCallback { public: UpdateCallback(const SGCondition* condition, - SGSharedPtr animationValue[3]) : + SGSharedPtr animationValue[3]) : _condition(condition) { _animationValue[0] = animationValue[0]; @@ -1048,8 +834,8 @@ public: virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { if (!_condition || _condition->test()) { - SGScaleAnimation::Transform* transform; - transform = static_cast(node); + SGScaleTransform* transform; + transform = static_cast(node); SGVec3d scale(_animationValue[0]->getValue(), _animationValue[1]->getValue(), _animationValue[2]->getValue()); @@ -1059,7 +845,7 @@ public: } public: SGSharedPtr _condition; - SGSharedPtr _animationValue[3]; + SGSharedPtr _animationValue[3]; }; SGScaleAnimation::SGScaleAnimation(const SGPropertyNode* configNode, @@ -1069,61 +855,72 @@ SGScaleAnimation::SGScaleAnimation(const SGPropertyNode* configNode, _condition = getCondition(); // default offset/factor for all directions - double offset = configNode->getDoubleValue("offset", 1); + double offset = configNode->getDoubleValue("offset", 0); double factor = configNode->getDoubleValue("factor", 1); + SGSharedPtr inPropExpr; + std::string inputPropertyName; inputPropertyName = configNode->getStringValue("property", ""); - SGPropertyNode* inputProperty = 0; - if (!inputPropertyName.empty()) { - inputProperty = modelRoot->getNode(inputPropertyName.c_str(), true); + if (inputPropertyName.empty()) { + inPropExpr = new SGConstExpression(0); + } else { + SGPropertyNode* inputProperty; + inputProperty = modelRoot->getNode(inputPropertyName, true); + inPropExpr = new SGPropertyExpression(inputProperty); } + SGInterpTable* interpTable = read_interpolation_table(configNode); if (interpTable) { - SGInterpTableValue* value; - value = new SGInterpTableValue(inputProperty, interpTable); - _animationValue[0] = value; - _animationValue[1] = value; - _animationValue[2] = value; + SGSharedPtr value; + value = new SGInterpTableExpression(inPropExpr, interpTable); + _animationValue[0] = value->simplify(); + _animationValue[1] = value->simplify(); + _animationValue[2] = value->simplify(); } else if (configNode->getBoolValue("use-personality", false)) { - SGPersScaleOffsetValue* value; - value = new SGPersScaleOffsetValue(inputProperty, configNode, - "x-factor", "x-offset", - factor, offset); - value->setMin(configNode->getDoubleValue("x-min", 0)); - value->setMax(configNode->getDoubleValue("x-max", SGLimitsd::max())); - _animationValue[0] = value; - value = new SGPersScaleOffsetValue(inputProperty, configNode, - "y-factor", "y-offset", - factor, offset); - value->setMin(configNode->getDoubleValue("y-min", 0)); - value->setMax(configNode->getDoubleValue("y-max", SGLimitsd::max())); - _animationValue[1] = value; - value = new SGPersScaleOffsetValue(inputProperty, configNode, - "z-factor", "z-offset", - factor, offset); - value->setMin(configNode->getDoubleValue("z-min", 0)); - value->setMax(configNode->getDoubleValue("z-max", SGLimitsd::max())); - _animationValue[2] = value; + SGSharedPtr value; + value = new SGPersonalityScaleOffsetExpression(inPropExpr, configNode, + "x-factor", "x-offset", + factor, offset); + double minClip = configNode->getDoubleValue("x-min", 0); + double maxClip = configNode->getDoubleValue("x-max", SGLimitsd::max()); + value = new SGClipExpression(value, minClip, maxClip); + _animationValue[0] = value->simplify(); + + value = new SGPersonalityScaleOffsetExpression(inPropExpr, configNode, + "y-factor", "y-offset", + factor, offset); + minClip = configNode->getDoubleValue("y-min", 0); + maxClip = configNode->getDoubleValue("y-max", SGLimitsd::max()); + value = new SGClipExpression(value, minClip, maxClip); + _animationValue[1] = value->simplify(); + + value = new SGPersonalityScaleOffsetExpression(inPropExpr, configNode, + "z-factor", "z-offset", + factor, offset); + minClip = configNode->getDoubleValue("z-min", 0); + maxClip = configNode->getDoubleValue("z-max", SGLimitsd::max()); + value = new SGClipExpression(value, minClip, maxClip); + _animationValue[2] = value->simplify(); } else { - SGScaleOffsetValue* value = new SGScaleOffsetValue(inputProperty); - value->setScale(configNode->getDoubleValue("x-factor", factor)); - value->setOffset(configNode->getDoubleValue("x-offset", offset)); - value->setMin(configNode->getDoubleValue("x-min", 0)); - value->setMax(configNode->getDoubleValue("x-max", SGLimitsd::max())); - _animationValue[0] = value; - value = new SGScaleOffsetValue(inputProperty); - value->setScale(configNode->getDoubleValue("y-factor", factor)); - value->setOffset(configNode->getDoubleValue("y-offset", offset)); - value->setMin(configNode->getDoubleValue("y-min", 0)); - value->setMax(configNode->getDoubleValue("y-max", SGLimitsd::max())); - _animationValue[1] = value; - value = new SGScaleOffsetValue(inputProperty); - value->setScale(configNode->getDoubleValue("z-factor", factor)); - value->setOffset(configNode->getDoubleValue("z-offset", offset)); - value->setMin(configNode->getDoubleValue("z-min", 0)); - value->setMax(configNode->getDoubleValue("z-max", SGLimitsd::max())); - _animationValue[2] = value; + SGSharedPtr value; + value = read_factor_offset(configNode, inPropExpr, "x-factor", "x-offset"); + double minClip = configNode->getDoubleValue("x-min", 0); + double maxClip = configNode->getDoubleValue("x-max", SGLimitsd::max()); + value = new SGClipExpression(value, minClip, maxClip); + _animationValue[0] = value->simplify(); + + value = read_factor_offset(configNode, inPropExpr, "y-factor", "y-offset"); + minClip = configNode->getDoubleValue("y-min", 0); + maxClip = configNode->getDoubleValue("y-max", SGLimitsd::max()); + value = new SGClipExpression(value, minClip, maxClip); + _animationValue[1] = value->simplify(); + + value = read_factor_offset(configNode, inPropExpr, "z-factor", "z-offset"); + minClip = configNode->getDoubleValue("z-min", 0); + maxClip = configNode->getDoubleValue("z-max", SGLimitsd::max()); + value = new SGClipExpression(value, minClip, maxClip); + _animationValue[2] = value->simplify(); } _initialValue[0] = configNode->getDoubleValue("x-starting-scale", 1); _initialValue[0] *= configNode->getDoubleValue("x-factor", factor); @@ -1142,7 +939,7 @@ SGScaleAnimation::SGScaleAnimation(const SGPropertyNode* configNode, osg::Group* SGScaleAnimation::createAnimationGroup(osg::Group& parent) { - Transform* transform = new Transform; + SGScaleTransform* transform = new SGScaleTransform; transform->setName("scale animation"); transform->setCenter(_center); transform->setScaleFactor(_initialValue); @@ -1153,17 +950,45 @@ SGScaleAnimation::createAnimationGroup(osg::Group& parent) } +// Don't create a new state state everytime we need GL_NORMALIZE! + +namespace +{ +Mutex normalizeMutex; + +osg::StateSet* getNormalizeStateSet() +{ + static osg::ref_ptr normalizeStateSet; + ScopedLock lock(normalizeMutex); + if (!normalizeStateSet.valid()) { + normalizeStateSet = new osg::StateSet; + normalizeStateSet->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + normalizeStateSet->setDataVariance(osg::Object::STATIC); + } + return normalizeStateSet.get(); +} +} + //////////////////////////////////////////////////////////////////////// // Implementation of dist scale animation //////////////////////////////////////////////////////////////////////// class SGDistScaleAnimation::Transform : public osg::Transform { public: + Transform() : _min_v(0.0), _max_v(0.0), _factor(0.0), _offset(0.0) {} + Transform(const Transform& rhs, + const osg::CopyOp& copyOp = osg::CopyOp::SHALLOW_COPY) + : osg::Transform(rhs, copyOp), _table(rhs._table), _center(rhs._center), + _min_v(rhs._min_v), _max_v(rhs._max_v), _factor(rhs._factor), + _offset(rhs._offset) + { + } + META_Node(simgear, SGDistScaleAnimation::Transform); Transform(const SGPropertyNode* configNode) { setName(configNode->getStringValue("name", "dist scale animation")); setReferenceFrame(RELATIVE_RF); - getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + setStateSet(getNormalizeStateSet()); _factor = configNode->getFloatValue("factor", 1); _offset = configNode->getFloatValue("offset", 0); _min_v = configNode->getFloatValue("min", SGLimitsf::epsilon()); @@ -1206,13 +1031,23 @@ public: return true; } + static bool writeLocalData(const osg::Object& obj, osgDB::Output& fw) + { + const Transform& trans = static_cast(obj); + fw.indent() << "center " << trans._center << "\n"; + fw.indent() << "min_v " << trans._min_v << "\n"; + fw.indent() << "max_v " << trans._max_v << "\n"; + fw.indent() << "factor " << trans._factor << "\n"; + fw.indent() << "offset " << trans._offset << "\n"; + return true; + } private: double computeScaleFactor(osg::NodeVisitor* nv) const { if (!nv) return 1; - double scale_factor = (_center.osg() - nv->getEyePoint()).length(); + double scale_factor = (toOsg(_center) - nv->getEyePoint()).length(); if (_table == 0) { scale_factor = _factor * scale_factor + _offset; } else { @@ -1249,6 +1084,17 @@ SGDistScaleAnimation::createAnimationGroup(osg::Group& parent) return transform; } +namespace +{ + osgDB::RegisterDotOsgWrapperProxy distScaleAnimationTransformProxy + ( + new SGDistScaleAnimation::Transform, + "SGDistScaleAnimation::Transform", + "Object Node Transform SGDistScaleAnimation::Transform Group", + 0, + &SGDistScaleAnimation::Transform::writeLocalData + ); +} //////////////////////////////////////////////////////////////////////// // Implementation of flash animation @@ -1256,11 +1102,24 @@ SGDistScaleAnimation::createAnimationGroup(osg::Group& parent) class SGFlashAnimation::Transform : public osg::Transform { public: + Transform() : _power(0.0), _factor(0.0), _offset(0.0), _min_v(0.0), + _max_v(0.0), _two_sides(false) + {} + + Transform(const Transform& rhs, + const osg::CopyOp& copyOp = osg::CopyOp::SHALLOW_COPY) + : osg::Transform(rhs, copyOp), _center(rhs._center), _axis(rhs._axis), + _power(rhs._power), _factor(rhs._factor), _offset(rhs._offset), + _min_v(rhs._min_v), _max_v(rhs._max_v), _two_sides(rhs._two_sides) + { + } + META_Node(simgear, SGFlashAnimation::Transform); + Transform(const SGPropertyNode* configNode) { setReferenceFrame(RELATIVE_RF); setName(configNode->getStringValue("name", "flash animation")); - getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); + setStateSet(getNormalizeStateSet()); _axis[0] = configNode->getFloatValue("axis/x", 0); _axis[1] = configNode->getFloatValue("axis/y", 0); @@ -1312,6 +1171,21 @@ public: return true; } + static bool writeLocalData(const osg::Object& obj, osgDB::Output& fw) + { + const Transform& trans = static_cast(obj); + fw.indent() << "center " << trans._center[0] << " " + << trans._center[1] << " " << trans._center[2] << " " << "\n"; + fw.indent() << "axis " << trans._axis[0] << " " + << trans._axis[1] << " " << trans._axis[2] << " " << "\n"; + fw.indent() << "power " << trans._power << " \n"; + fw.indent() << "min_v " << trans._min_v << "\n"; + fw.indent() << "max_v " << trans._max_v << "\n"; + fw.indent() << "factor " << trans._factor << "\n"; + fw.indent() << "offset " << trans._offset << "\n"; + fw.indent() << "twosides " << (trans._two_sides ? "true" : "false") << "\n"; + return true; + } private: double computeScaleFactor(osg::NodeVisitor* nv) const { @@ -1366,13 +1240,29 @@ SGFlashAnimation::createAnimationGroup(osg::Group& parent) return transform; } +namespace +{ + osgDB::RegisterDotOsgWrapperProxy flashAnimationTransformProxy + ( + new SGFlashAnimation::Transform, + "SGFlashAnimation::Transform", + "Object Node Transform SGFlashAnimation::Transform Group", + 0, + &SGFlashAnimation::Transform::writeLocalData + ); +} //////////////////////////////////////////////////////////////////////// -// Implementation of flash animation +// Implementation of billboard animation //////////////////////////////////////////////////////////////////////// class SGBillboardAnimation::Transform : public osg::Transform { public: + Transform() : _spherical(true) {} + Transform(const Transform& rhs, + const osg::CopyOp& copyOp = osg::CopyOp::SHALLOW_COPY) + : osg::Transform(rhs, copyOp), _spherical(rhs._spherical) {} + META_Node(simgear, SGBillboardAnimation::Transform); Transform(const SGPropertyNode* configNode) : _spherical(configNode->getBoolValue("spherical", true)) { @@ -1409,7 +1299,13 @@ public: // Hmm, don't yet know how to get that back ... return false; } + static bool writeLocalData(const osg::Object& obj, osgDB::Output& fw) + { + const Transform& trans = static_cast(obj); + fw.indent() << (trans._spherical ? "true" : "false") << "\n"; + return true; + } private: bool _spherical; }; @@ -1429,6 +1325,17 @@ SGBillboardAnimation::createAnimationGroup(osg::Group& parent) return transform; } +namespace +{ + osgDB::RegisterDotOsgWrapperProxy billboardAnimationTransformProxy + ( + new SGBillboardAnimation::Transform, + "SGBillboardAnimation::Transform", + "Object Node Transform SGBillboardAnimation::Transform Group", + 0, + &SGBillboardAnimation::Transform::writeLocalData + ); +} //////////////////////////////////////////////////////////////////////// // Implementation of a range animation @@ -1437,8 +1344,8 @@ SGBillboardAnimation::createAnimationGroup(osg::Group& parent) class SGRangeAnimation::UpdateCallback : public osg::NodeCallback { public: UpdateCallback(const SGCondition* condition, - const SGDoubleValue* minAnimationValue, - const SGDoubleValue* maxAnimationValue, + const SGExpressiond* minAnimationValue, + const SGExpressiond* maxAnimationValue, double minValue, double maxValue) : _condition(condition), _minAnimationValue(minAnimationValue), @@ -1469,8 +1376,8 @@ public: private: SGSharedPtr _condition; - SGSharedPtr _minAnimationValue; - SGSharedPtr _maxAnimationValue; + SGSharedPtr _minAnimationValue; + SGSharedPtr _maxAnimationValue; double _minStaticValue; double _maxStaticValue; }; @@ -1485,18 +1392,23 @@ SGRangeAnimation::SGRangeAnimation(const SGPropertyNode* configNode, inputPropertyName = configNode->getStringValue("min-property", ""); if (!inputPropertyName.empty()) { SGPropertyNode* inputProperty; - inputProperty = modelRoot->getNode(inputPropertyName.c_str(), true); - SGScaleOffsetValue* value = new SGScaleOffsetValue(inputProperty); - value->setScale(configNode->getDoubleValue("min-factor", 1)); - _minAnimationValue = value; + inputProperty = modelRoot->getNode(inputPropertyName, true); + SGSharedPtr value; + value = new SGPropertyExpression(inputProperty); + + value = read_factor_offset(configNode, value, "min-factor", "min-offset"); + _minAnimationValue = value->simplify(); } inputPropertyName = configNode->getStringValue("max-property", ""); if (!inputPropertyName.empty()) { SGPropertyNode* inputProperty; inputProperty = modelRoot->getNode(inputPropertyName.c_str(), true); - SGScaleOffsetValue* value = new SGScaleOffsetValue(inputProperty); - value->setScale(configNode->getDoubleValue("max-factor", 1)); - _maxAnimationValue = value; + + SGSharedPtr value; + value = new SGPropertyExpression(inputProperty); + + value = read_factor_offset(configNode, value, "max-factor", "max-offset"); + _maxAnimationValue = value->simplify(); } _initialValue[0] = configNode->getDoubleValue("min-m", 0); @@ -1586,30 +1498,73 @@ SGAlphaTestAnimation::SGAlphaTestAnimation(const SGPropertyNode* configNode, { } +namespace +{ +// Keep one copy of the most common alpha test its state set. +ReentrantMutex alphaTestMutex; +osg::ref_ptr standardAlphaFunc; +osg::ref_ptr alphaFuncStateSet; + +osg::AlphaFunc* makeAlphaFunc(float clamp) +{ + ScopedLock lock(alphaTestMutex); + if (osg::equivalent(clamp, 0.01f)) { + if (standardAlphaFunc.valid()) + return standardAlphaFunc.get(); + clamp = .01; + } + osg::AlphaFunc* alphaFunc = new osg::AlphaFunc; + alphaFunc->setFunction(osg::AlphaFunc::GREATER); + alphaFunc->setReferenceValue(clamp); + alphaFunc->setDataVariance(osg::Object::STATIC); + if (osg::equivalent(clamp, 0.01f)) + standardAlphaFunc = alphaFunc; + return alphaFunc; +} + +osg::StateSet* makeAlphaTestStateSet(float clamp) +{ + using namespace OpenThreads; + ScopedLock lock(alphaTestMutex); + if (osg::equivalent(clamp, 0.01f)) { + if (alphaFuncStateSet.valid()) + return alphaFuncStateSet.get(); + } + osg::AlphaFunc* alphaFunc = makeAlphaFunc(clamp); + osg::StateSet* stateSet = new osg::StateSet; + stateSet->setAttributeAndModes(alphaFunc, + (osg::StateAttribute::ON + | osg::StateAttribute::OVERRIDE)); + stateSet->setDataVariance(osg::Object::STATIC); + if (osg::equivalent(clamp, 0.01f)) + alphaFuncStateSet = stateSet; + return stateSet; +} +} void SGAlphaTestAnimation::install(osg::Node& node) { SGAnimation::install(node); - - cloneDrawables(node); - removeMode(node, GL_ALPHA_TEST); - removeAttribute(node, osg::StateAttribute::ALPHAFUNC); - osg::StateSet* stateSet = node.getOrCreateStateSet(); - osg::AlphaFunc* alphaFunc = new osg::AlphaFunc; - alphaFunc->setFunction(osg::AlphaFunc::GREATER); float alphaClamp = getConfig()->getFloatValue("alpha-factor", 0); - alphaFunc->setReferenceValue(alphaClamp); - stateSet->setAttribute(alphaFunc); - stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON); + osg::StateSet* stateSet = node.getStateSet(); + if (!stateSet) { + node.setStateSet(makeAlphaTestStateSet(alphaClamp)); + } else { + stateSet->setAttributeAndModes(makeAlphaFunc(alphaClamp), + (osg::StateAttribute::ON + | osg::StateAttribute::OVERRIDE)); + } } - ////////////////////////////////////////////////////////////////////// // Blend animation installer ////////////////////////////////////////////////////////////////////// +// XXX This needs to be replaced by something using TexEnvCombine to +// change the blend factor. Changing the alpha values in the geometry +// is bogus. class SGBlendAnimation::BlendVisitor : public osg::NodeVisitor { public: BlendVisitor(float blend) : @@ -1627,7 +1582,6 @@ public: unsigned nDrawables = node.getNumDrawables(); for (unsigned i = 0; i < nDrawables; ++i) { osg::Drawable* drawable = node.getDrawable(i); - updateStateSet(drawable->getStateSet()); osg::Geometry* geometry = drawable->asGeometry(); if (!geometry) continue; @@ -1637,11 +1591,11 @@ public: osg::Vec4Array* vec4Array = dynamic_cast(array); if (!vec4Array) continue; - geometry->dirtyDisplayList(); - vec4Array->dirty(); for (unsigned k = 0; k < vec4Array->size(); ++k) { (*vec4Array)[k][3] = _blend; } + vec4Array->dirty(); + updateStateSet(drawable->getStateSet()); } } void updateStateSet(osg::StateSet* stateSet) @@ -1669,7 +1623,7 @@ private: class SGBlendAnimation::UpdateCallback : public osg::NodeCallback { public: - UpdateCallback(const SGPropertyNode* configNode, const SGDoubleValue* v) : + UpdateCallback(const SGPropertyNode* configNode, const SGExpressiond* v) : _prev_value(-1), _animationValue(v) { } @@ -1685,7 +1639,7 @@ public: } public: double _prev_value; - SGSharedPtr _animationValue; + SGSharedPtr _animationValue; }; @@ -1716,6 +1670,8 @@ SGBlendAnimation::install(osg::Node& node) // make sure we do not change common geometries, // that also creates new display lists for these subgeometries. cloneDrawables(node); + DoDrawArraysVisitor visitor; + node.accept(visitor); } @@ -1841,9 +1797,9 @@ public: virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { if (_condition->test()) - node->setNodeMask( SG_NODEMASK_SHADOW_BIT | node->getNodeMask()); + node->setNodeMask( SG_NODEMASK_CASTSHADOW_BIT | node->getNodeMask()); else - node->setNodeMask(~SG_NODEMASK_SHADOW_BIT & node->getNodeMask()); + node->setNodeMask(~SG_NODEMASK_CASTSHADOW_BIT & node->getNodeMask()); traverse(node, nv); } @@ -1896,8 +1852,6 @@ public: Translation(const SGVec3d& axis) : _axis(axis) { } - void setValue(double value) - { _value = value; } virtual void transform(osg::Matrix& matrix) { osg::Matrix tmp; @@ -1946,7 +1900,7 @@ public: for (i = _transforms.begin(); i != _transforms.end(); ++i) i->transform->transform(texMat->getMatrix()); } - void appendTransform(Transform* transform, SGDoubleValue* value) + void appendTransform(Transform* transform, SGExpressiond* value) { Entry entry = { transform, value }; transform->transform(_matrix); @@ -1956,7 +1910,7 @@ public: private: struct Entry { SGSharedPtr transform; - SGSharedPtr value; + SGSharedPtr value; }; typedef std::vector TransformList; TransformList _transforms; @@ -1976,6 +1930,7 @@ SGTexTransformAnimation::createAnimationGroup(osg::Group& parent) osg::Group* group = new osg::Group; group->setName("texture transform group"); osg::StateSet* stateSet = group->getOrCreateStateSet(); + stateSet->setDataVariance(osg::Object::DYNAMIC); osg::TexMat* texMat = new osg::TexMat; UpdateCallback* updateCallback = new UpdateCallback(getCondition()); // interpret the configs ... @@ -2012,28 +1967,40 @@ void SGTexTransformAnimation::appendTexTranslate(const SGPropertyNode* config, UpdateCallback* updateCallback) { - std::string propertyName = config->getStringValue("property", "/null"); - SGPropertyNode* inputNode; - inputNode = getModelRoot()->getNode(propertyName.c_str(), true); + std::string propertyName = config->getStringValue("property", ""); + SGSharedPtr value; + if (propertyName.empty()) + value = new SGConstExpression(0); + else { + SGPropertyNode* inputProperty = getModelRoot()->getNode(propertyName, true); + value = new SGPropertyExpression(inputProperty); + } - SGDoubleValue* animationValue; SGInterpTable* table = read_interpolation_table(config); if (table) { - SGTexTableValue* value; - value = new SGTexTableValue(inputNode, table); - value->setStep(config->getDoubleValue("step", 0)); - value->setScroll(config->getDoubleValue("scroll", 0)); - animationValue = value; + value = new SGInterpTableExpression(value, table); + double biasValue = config->getDoubleValue("bias", 0); + if (biasValue != 0) + value = new SGBiasExpression(value, biasValue); + value = new SGStepExpression(value, + config->getDoubleValue("step", 0), + config->getDoubleValue("scroll", 0)); + value = value->simplify(); } else { - SGTexScaleOffsetValue* value; - value = new SGTexScaleOffsetValue(inputNode); - value->setScale(config->getDoubleValue("factor", 1)); - value->setOffset(config->getDoubleValue("offset", 0)); - value->setStep(config->getDoubleValue("step", 0)); - value->setScroll(config->getDoubleValue("scroll", 0)); - value->setMin(config->getDoubleValue("min", -SGLimitsd::max())); - value->setMax(config->getDoubleValue("max", SGLimitsd::max())); - animationValue = value; + double biasValue = config->getDoubleValue("bias", 0); + if (biasValue != 0) + value = new SGBiasExpression(value, biasValue); + value = new SGStepExpression(value, + config->getDoubleValue("step", 0), + config->getDoubleValue("scroll", 0)); + value = read_offset_factor(config, value, "factor", "offset"); + + if (config->hasChild("min") || config->hasChild("max")) { + double minClip = config->getDoubleValue("min", -SGLimitsd::max()); + double maxClip = config->getDoubleValue("max", SGLimitsd::max()); + value = new SGClipExpression(value, minClip, maxClip); + } + value = value->simplify(); } SGVec3d axis(config->getDoubleValue("axis/x", 0), config->getDoubleValue("axis/y", 0), @@ -2041,35 +2008,47 @@ SGTexTransformAnimation::appendTexTranslate(const SGPropertyNode* config, Translation* translation; translation = new Translation(normalize(axis)); translation->setValue(config->getDoubleValue("starting-position", 0)); - updateCallback->appendTransform(translation, animationValue); + updateCallback->appendTransform(translation, value); } void SGTexTransformAnimation::appendTexRotate(const SGPropertyNode* config, UpdateCallback* updateCallback) { - std::string propertyName = config->getStringValue("property", "/null"); - SGPropertyNode* inputNode; - inputNode = getModelRoot()->getNode(propertyName.c_str(), true); + std::string propertyName = config->getStringValue("property", ""); + SGSharedPtr value; + if (propertyName.empty()) + value = new SGConstExpression(0); + else { + SGPropertyNode* inputProperty = getModelRoot()->getNode(propertyName, true); + value = new SGPropertyExpression(inputProperty); + } - SGDoubleValue* animationValue; SGInterpTable* table = read_interpolation_table(config); if (table) { - SGTexTableValue* value; - value = new SGTexTableValue(inputNode, table); - value->setStep(config->getDoubleValue("step", 0)); - value->setScroll(config->getDoubleValue("scroll", 0)); - animationValue = value; + value = new SGInterpTableExpression(value, table); + double biasValue = config->getDoubleValue("bias", 0); + if (biasValue != 0) + value = new SGBiasExpression(value, biasValue); + value = new SGStepExpression(value, + config->getDoubleValue("step", 0), + config->getDoubleValue("scroll", 0)); + value = value->simplify(); } else { - SGTexScaleOffsetValue* value; - value = new SGTexScaleOffsetValue(inputNode); - value->setScale(config->getDoubleValue("factor", 1)); - value->setOffset(config->getDoubleValue("offset-deg", 0)); - value->setStep(config->getDoubleValue("step", 0)); - value->setScroll(config->getDoubleValue("scroll", 0)); - value->setMin(config->getDoubleValue("min-deg", -SGLimitsd::max())); - value->setMax(config->getDoubleValue("max-deg", SGLimitsd::max())); - animationValue = value; + double biasValue = config->getDoubleValue("bias", 0); + if (biasValue != 0) + value = new SGBiasExpression(value, biasValue); + value = new SGStepExpression(value, + config->getDoubleValue("step", 0), + config->getDoubleValue("scroll", 0)); + value = read_offset_factor(config, value, "factor", "offset-deg"); + + if (config->hasChild("min-deg") || config->hasChild("max-deg")) { + double minClip = config->getDoubleValue("min-deg", -SGLimitsd::max()); + double maxClip = config->getDoubleValue("max-deg", SGLimitsd::max()); + value = new SGClipExpression(value, minClip, maxClip); + } + value = value->simplify(); } SGVec3d axis(config->getDoubleValue("axis/x", 0), config->getDoubleValue("axis/y", 0), @@ -2080,7 +2059,7 @@ SGTexTransformAnimation::appendTexRotate(const SGPropertyNode* config, Rotation* rotation; rotation = new Rotation(normalize(axis), center); rotation->setValue(config->getDoubleValue("starting-position-deg", 0)); - updateCallback->appendTransform(rotation, animationValue); + updateCallback->appendTransform(rotation, value); } @@ -2092,12 +2071,16 @@ class SGPickAnimation::PickCallback : public SGPickCallback { public: PickCallback(const SGPropertyNode* configNode, SGPropertyNode* modelRoot) : - _button(configNode->getIntValue("button", -1)), _repeatable(configNode->getBoolValue("repeatable", false)), _repeatInterval(configNode->getDoubleValue("interval-sec", 0.1)) { SG_LOG(SG_INPUT, SG_DEBUG, "Reading all bindings"); std::vector bindings; + + bindings = configNode->getChildren("button"); + for (unsigned int i = 0; i < bindings.size(); ++i) { + _buttons.push_back( bindings[i]->getIntValue() ); + } bindings = configNode->getChildren("binding"); for (unsigned int i = 0; i < bindings.size(); ++i) { _bindingsDown.push_back(new SGBinding(bindings[i], modelRoot)); @@ -2113,12 +2096,19 @@ public: } virtual bool buttonPressed(int button, const Info&) { - if (0 <= _button && button != _button) + bool found = false; + for( std::vector::iterator it = _buttons.begin(); it != _buttons.end(); it++ ) { + if( *it == button ) { + found = true; + break; + } + } + if (!found ) return false; SGBindingList::const_iterator i; for (i = _bindingsDown.begin(); i != _bindingsDown.end(); ++i) (*i)->fire(); - _repeatTime = 0; + _repeatTime = -_repeatInterval; // anti-bobble: delay start of repeat return true; } virtual void buttonReleased(void) @@ -2143,7 +2133,7 @@ public: private: SGBindingList _bindingsDown; SGBindingList _bindingsUp; - int _button; + std::vector _buttons; bool _repeatable; double _repeatInterval; double _repeatTime; @@ -2162,14 +2152,16 @@ SGPickAnimation::createAnimationGroup(osg::Group& parent) // Contains the normal geometry that is interactive osg::ref_ptr normalGroup = new osg::Group; + normalGroup->setName("pick normal group"); normalGroup->addChild(commonGroup); // Used to render the geometry with just yellow edges osg::Group* highlightGroup = new osg::Group; + highlightGroup->setName("pick highlight group"); highlightGroup->setNodeMask(SG_NODEMASK_PICK_BIT); highlightGroup->addChild(commonGroup); SGSceneUserData* ud; - ud = SGSceneUserData::getOrCreateSceneUserData(highlightGroup); + ud = SGSceneUserData::getOrCreateSceneUserData(commonGroup); std::vector actions; actions = getConfig()->getChildren("action"); for (unsigned int i = 0; i < actions.size(); ++i)