1 // animation.cxx - classes to manage model animation.
2 // Written by David Megginson, started 2002.
4 // This file is in the Public Domain, and comes with no warranty.
7 # include <simgear_config.h>
10 #include <string.h> // for strcmp()
13 #include <osg/AlphaFunc>
14 #include <osg/Drawable>
16 #include <osg/Geometry>
18 #include <osg/StateSet>
21 #include <osg/Texture2D>
22 #include <osg/Transform>
23 #include <osgDB/ReadFile>
25 #include <simgear/math/interpolater.hxx>
26 #include <simgear/props/condition.hxx>
27 #include <simgear/props/props.hxx>
28 #include <simgear/scene/util/SGNodeMasks.hxx>
29 #include <simgear/scene/util/SGStateAttributeVisitor.hxx>
31 #include "animation.hxx"
34 #include "SGMaterialAnimation.hxx"
37 ////////////////////////////////////////////////////////////////////////
38 // Static utility functions.
39 ////////////////////////////////////////////////////////////////////////
42 * Set up the transform matrix for a spin or rotation.
45 set_rotation (osg::Matrix &matrix, double position_deg,
46 const SGVec3d ¢er, const SGVec3d &axis)
48 double temp_angle = -SGMiscd::deg2rad(position_deg);
50 double s = sin(temp_angle);
51 double c = cos(temp_angle);
54 // axis was normalized at load time
55 // hint to the compiler to put these into FP registers
60 matrix(0, 0) = t * x * x + c ;
61 matrix(0, 1) = t * y * x - s * z ;
62 matrix(0, 2) = t * z * x + s * y ;
65 matrix(1, 0) = t * x * y + s * z ;
66 matrix(1, 1) = t * y * y + c ;
67 matrix(1, 2) = t * z * y - s * x ;
70 matrix(2, 0) = t * x * z - s * y ;
71 matrix(2, 1) = t * y * z + s * x ;
72 matrix(2, 2) = t * z * z + c ;
75 // hint to the compiler to put these into FP registers
80 matrix(3, 0) = x - x*matrix(0, 0) - y*matrix(1, 0) - z*matrix(2, 0);
81 matrix(3, 1) = y - x*matrix(0, 1) - y*matrix(1, 1) - z*matrix(2, 1);
82 matrix(3, 2) = z - x*matrix(0, 2) - y*matrix(1, 2) - z*matrix(2, 2);
87 * Set up the transform matrix for a translation.
90 set_translation (osg::Matrix &matrix, double position_m, const SGVec3d &axis)
92 SGVec3d xyz = axis * position_m;
93 matrix.makeIdentity();
94 matrix(3, 0) = xyz[0];
95 matrix(3, 1) = xyz[1];
96 matrix(3, 2) = xyz[2];
100 * Modify property value by step and scroll settings in texture translations
103 apply_mods(double property, double step, double scroll)
108 double scrollval = 0.0;
110 // calculate scroll amount (for odometer like movement)
111 double remainder = step - fmod(fabs(property), step);
112 if (remainder < scroll) {
113 scrollval = (scroll - remainder) / scroll * step;
116 // apply stepping of input value
118 modprop = ((floor(property/step) * step) + scrollval);
120 modprop = ((ceil(property/step) * step) + scrollval);
129 * Read an interpolation table from properties.
131 static SGInterpTable *
132 read_interpolation_table(const SGPropertyNode* props)
134 const SGPropertyNode* table_node = props->getNode("interpolation");
137 return new SGInterpTable(table_node);
140 ////////////////////////////////////////////////////////////////////////
141 // Utility value classes
142 ////////////////////////////////////////////////////////////////////////
143 class SGScaleOffsetValue : public SGDoubleValue {
145 SGScaleOffsetValue(SGPropertyNode const* propertyNode) :
146 _propertyNode(propertyNode),
149 _min(-SGLimitsd::max()),
150 _max(SGLimitsd::max())
152 void setScale(double scale)
154 void setOffset(double offset)
155 { _offset = offset; }
156 void setMin(double min)
158 void setMax(double max)
161 virtual double getValue() const
163 double value = _propertyNode ? _propertyNode->getDoubleValue() : 0;
164 return std::min(_max, std::max(_min, _offset + _scale*value));
167 SGSharedPtr<SGPropertyNode const> _propertyNode;
174 class SGPersScaleOffsetValue : public SGDoubleValue {
176 SGPersScaleOffsetValue(SGPropertyNode const* propertyNode,
177 SGPropertyNode const* config,
178 const char* scalename, const char* offsetname,
179 double defScale = 1, double defOffset = 0) :
180 _propertyNode(propertyNode),
181 _scale(config, scalename, defScale),
182 _offset(config, offsetname, defOffset),
183 _min(-SGLimitsd::max()),
184 _max(SGLimitsd::max())
186 void setScale(double scale)
188 void setOffset(double offset)
189 { _offset = offset; }
190 void setMin(double min)
192 void setMax(double max)
195 virtual double getValue() const
199 double value = _propertyNode ? _propertyNode->getDoubleValue() : 0;
200 return SGMiscd::clip(_offset + _scale*value, _min, _max);
203 SGSharedPtr<SGPropertyNode const> _propertyNode;
204 mutable SGPersonalityParameter<double> _scale;
205 mutable SGPersonalityParameter<double> _offset;
210 class SGInterpTableValue : public SGDoubleValue {
212 SGInterpTableValue(SGPropertyNode const* propertyNode,
213 SGInterpTable const* interpTable) :
214 _propertyNode(propertyNode),
215 _interpTable(interpTable)
217 virtual double getValue() const
218 { return _interpTable->interpolate(_propertyNode->getDoubleValue()); }
220 SGSharedPtr<SGPropertyNode const> _propertyNode;
221 SGSharedPtr<SGInterpTable const> _interpTable;
224 class SGTexScaleOffsetValue : public SGDoubleValue {
226 SGTexScaleOffsetValue(const SGPropertyNode* propertyNode) :
227 _propertyNode(propertyNode),
232 _min(-SGLimitsd::max()),
233 _max(SGLimitsd::max())
235 void setScale(double scale)
237 void setOffset(double offset)
238 { _offset = offset; }
239 void setStep(double step)
241 void setScroll(double scroll)
242 { _scroll = scroll; }
243 void setMin(double min)
245 void setMax(double max)
248 virtual double getValue() const
250 double value = _propertyNode ? _propertyNode->getDoubleValue() : 0;
251 value = apply_mods(value, _step, _scroll);
252 return SGMiscd::clip(_scale*(_offset + value), _min, _max);
255 SGSharedPtr<const SGPropertyNode> _propertyNode;
264 class SGTexTableValue : public SGDoubleValue {
266 SGTexTableValue(const SGPropertyNode* propertyNode,
267 const SGInterpTable* interpTable) :
268 _propertyNode(propertyNode),
269 _interpTable(interpTable)
271 void setStep(double step)
273 void setScroll(double scroll)
274 { _scroll = scroll; }
275 virtual double getValue() const
277 double value = _propertyNode ? _propertyNode->getDoubleValue() : 0;
278 value = apply_mods(value, _step, _scroll);
279 return _interpTable->interpolate(value);
282 SGSharedPtr<SGPropertyNode const> _propertyNode;
283 SGSharedPtr<SGInterpTable const> _interpTable;
289 unit_string(const char* value, const char* unit)
291 return std::string(value) + unit;
294 static SGDoubleValue*
295 read_value(const SGPropertyNode* configNode, SGPropertyNode* modelRoot,
296 const char* unit, double defMin, double defMax)
298 std::string inputPropertyName;
299 inputPropertyName = configNode->getStringValue("property", "");
300 if (!inputPropertyName.empty()) {
301 SGPropertyNode* inputProperty;
302 inputProperty = modelRoot->getNode(inputPropertyName.c_str(), true);
303 SGInterpTable* interpTable = read_interpolation_table(configNode);
305 SGInterpTableValue* value;
306 value = new SGInterpTableValue(inputProperty, interpTable);
309 std::string offset = unit_string("offset", unit);
310 std::string min = unit_string("min", unit);
311 std::string max = unit_string("max", unit);
313 if (configNode->getBoolValue("use-personality", false)) {
314 SGPersScaleOffsetValue* value;
315 value = new SGPersScaleOffsetValue(inputProperty, configNode,
316 "factor", offset.c_str());
317 value->setMin(configNode->getDoubleValue(min.c_str(), defMin));
318 value->setMax(configNode->getDoubleValue(max.c_str(), defMax));
321 SGScaleOffsetValue* value = new SGScaleOffsetValue(inputProperty);
322 value->setScale(configNode->getDoubleValue("factor", 1));
323 value->setOffset(configNode->getDoubleValue(offset.c_str(), 0));
324 value->setMin(configNode->getDoubleValue(min.c_str(), defMin));
325 value->setMax(configNode->getDoubleValue(max.c_str(), defMax));
334 ////////////////////////////////////////////////////////////////////////
335 // Animation installer
336 ////////////////////////////////////////////////////////////////////////
338 class SGAnimation::RemoveModeVisitor : public SGStateAttributeVisitor {
340 RemoveModeVisitor(osg::StateAttribute::GLMode mode) :
343 virtual void apply(osg::StateSet* stateSet)
347 stateSet->removeMode(_mode);
350 osg::StateAttribute::GLMode _mode;
353 class SGAnimation::RemoveAttributeVisitor : public SGStateAttributeVisitor {
355 RemoveAttributeVisitor(osg::StateAttribute::Type type) :
358 virtual void apply(osg::StateSet* stateSet)
362 while (stateSet->getAttribute(_type)) {
363 stateSet->removeAttribute(_type);
367 osg::StateAttribute::Type _type;
370 class SGAnimation::RemoveTextureModeVisitor : public SGStateAttributeVisitor {
372 RemoveTextureModeVisitor(unsigned unit, osg::StateAttribute::GLMode mode) :
376 virtual void apply(osg::StateSet* stateSet)
380 stateSet->removeTextureMode(_unit, _mode);
384 osg::StateAttribute::GLMode _mode;
387 class SGAnimation::RemoveTextureAttributeVisitor :
388 public SGStateAttributeVisitor {
390 RemoveTextureAttributeVisitor(unsigned unit,
391 osg::StateAttribute::Type type) :
395 virtual void apply(osg::StateSet* stateSet)
399 while (stateSet->getTextureAttribute(_unit, _type)) {
400 stateSet->removeTextureAttribute(_unit, _type);
405 osg::StateAttribute::Type _type;
408 class SGAnimation::BinToInheritVisitor : public SGStateAttributeVisitor {
410 virtual void apply(osg::StateSet* stateSet)
414 stateSet->setRenderBinToInherit();
418 class SGAnimation::DrawableCloneVisitor : public osg::NodeVisitor {
420 DrawableCloneVisitor() :
421 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
423 void apply(osg::Geode& geode)
425 for (unsigned i = 0 ; i < geode.getNumDrawables(); ++i) {
426 osg::CopyOp copyOp(osg::CopyOp::DEEP_COPY_ALL &
427 ~osg::CopyOp::DEEP_COPY_TEXTURES);
428 geode.setDrawable(i, copyOp(geode.getDrawable(i)));
434 SGAnimation::SGAnimation(const SGPropertyNode* configNode,
435 SGPropertyNode* modelRoot) :
436 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
438 _configNode(configNode),
439 _modelRoot(modelRoot)
441 _name = configNode->getStringValue("name", "");
442 _enableHOT = configNode->getBoolValue("enable-hot", true);
443 _disableShadow = configNode->getBoolValue("disable-shadow", false);
444 std::vector<SGPropertyNode_ptr> objectNames =
445 configNode->getChildren("object-name");
446 for (unsigned i = 0; i < objectNames.size(); ++i)
447 _objectNames.push_back(objectNames[i]->getStringValue());
450 SGAnimation::~SGAnimation()
455 SG_LOG(SG_IO, SG_ALERT, "Could not find at least one of the following"
456 " objects for animation:\n");
457 std::list<std::string>::const_iterator i;
458 for (i = _objectNames.begin(); i != _objectNames.end(); ++i)
459 SG_LOG(SG_IO, SG_ALERT, *i << "\n");
463 SGAnimation::animate(osg::Node* node, const SGPropertyNode* configNode,
464 SGPropertyNode* modelRoot)
466 std::string type = configNode->getStringValue("type", "none");
467 if (type == "alpha-test") {
468 SGAlphaTestAnimation animInst(configNode, modelRoot);
469 animInst.apply(node);
470 } else if (type == "billboard") {
471 SGBillboardAnimation animInst(configNode, modelRoot);
472 animInst.apply(node);
473 } else if (type == "blend") {
474 SGBlendAnimation animInst(configNode, modelRoot);
475 animInst.apply(node);
476 } else if (type == "dist-scale") {
477 SGDistScaleAnimation animInst(configNode, modelRoot);
478 animInst.apply(node);
479 } else if (type == "flash") {
480 SGFlashAnimation animInst(configNode, modelRoot);
481 animInst.apply(node);
482 } else if (type == "material") {
483 SGMaterialAnimation animInst(configNode, modelRoot);
484 animInst.apply(node);
485 } else if (type == "noshadow") {
486 SGShadowAnimation animInst(configNode, modelRoot);
487 animInst.apply(node);
488 } else if (type == "range") {
489 SGRangeAnimation animInst(configNode, modelRoot);
490 animInst.apply(node);
491 } else if (type == "rotate" || type == "spin") {
492 SGRotateAnimation animInst(configNode, modelRoot);
493 animInst.apply(node);
494 } else if (type == "scale") {
495 SGScaleAnimation animInst(configNode, modelRoot);
496 animInst.apply(node);
497 } else if (type == "select") {
498 SGSelectAnimation animInst(configNode, modelRoot);
499 animInst.apply(node);
500 } else if (type == "shader") {
501 SGShaderAnimation animInst(configNode, modelRoot);
502 animInst.apply(node);
503 } else if (type == "textranslate" || type == "texrotate" ||
504 type == "texmultiple") {
505 SGTexTransformAnimation animInst(configNode, modelRoot);
506 animInst.apply(node);
507 } else if (type == "timed") {
508 SGTimedAnimation animInst(configNode, modelRoot);
509 animInst.apply(node);
510 } else if (type == "translate") {
511 SGTranslateAnimation animInst(configNode, modelRoot);
512 animInst.apply(node);
513 } else if (type == "null" || type == "none" || type.empty()) {
514 SGGroupAnimation animInst(configNode, modelRoot);
515 animInst.apply(node);
524 SGAnimation::apply(osg::Node* node)
526 // duh what a special case ...
527 if (_objectNames.empty()) {
528 osg::Group* group = node->asGroup();
530 osg::ref_ptr<osg::Group> animationGroup;
531 installInGroup(std::string(), *group, animationGroup);
538 SGAnimation::install(osg::Node& node)
542 node.setNodeMask( SG_NODEMASK_TERRAIN_BIT | node.getNodeMask());
544 node.setNodeMask(~SG_NODEMASK_TERRAIN_BIT & node.getNodeMask());
546 node.setNodeMask( SG_NODEMASK_SHADOW_BIT | node.getNodeMask());
548 node.setNodeMask(~SG_NODEMASK_SHADOW_BIT & node.getNodeMask());
552 SGAnimation::createAnimationGroup(osg::Group& parent)
554 // default implementation, we do not need a new group
555 // for every animation type. Usually animations that just change
556 // the StateSet of some parts of the model
561 SGAnimation::apply(osg::Group& group)
563 // the trick is to first traverse the children and then
564 // possibly splice in a new group node if required.
565 // Else we end up in a recursive loop where we infinitly insert new
569 // Note that this algorithm preserves the order of the child objects
570 // like they appear in the object-name tags.
571 // The timed animations require this
572 osg::ref_ptr<osg::Group> animationGroup;
573 std::list<std::string>::const_iterator nameIt;
574 for (nameIt = _objectNames.begin(); nameIt != _objectNames.end(); ++nameIt)
575 installInGroup(*nameIt, group, animationGroup);
579 SGAnimation::installInGroup(const std::string& name, osg::Group& group,
580 osg::ref_ptr<osg::Group>& animationGroup)
582 int i = group.getNumChildren() - 1;
583 for (; 0 <= i; --i) {
584 osg::Node* child = group.getChild(i);
585 if (name.empty() || child->getName() == name) {
586 // fire the installation of the animation
589 // create a group node on demand
590 if (!animationGroup.valid()) {
591 animationGroup = createAnimationGroup(group);
592 // Animation type that does not require a new group,
593 // in this case we can stop and look for the next object
594 if (animationGroup.valid() && !_name.empty())
595 animationGroup->setName(_name);
597 if (animationGroup.valid()) {
598 animationGroup->addChild(child);
599 group.removeChild(i);
606 SGAnimation::removeMode(osg::Node& node, osg::StateAttribute::GLMode mode)
608 RemoveModeVisitor visitor(mode);
609 node.accept(visitor);
613 SGAnimation::removeAttribute(osg::Node& node, osg::StateAttribute::Type type)
615 RemoveAttributeVisitor visitor(type);
616 node.accept(visitor);
620 SGAnimation::removeTextureMode(osg::Node& node, unsigned unit,
621 osg::StateAttribute::GLMode mode)
623 RemoveTextureModeVisitor visitor(unit, mode);
624 node.accept(visitor);
628 SGAnimation::removeTextureAttribute(osg::Node& node, unsigned unit,
629 osg::StateAttribute::Type type)
631 RemoveTextureAttributeVisitor visitor(unit, type);
632 node.accept(visitor);
636 SGAnimation::setRenderBinToInherit(osg::Node& node)
638 BinToInheritVisitor visitor;
639 node.accept(visitor);
643 SGAnimation::cloneDrawables(osg::Node& node)
645 DrawableCloneVisitor visitor;
646 node.accept(visitor);
650 SGAnimation::getCondition() const
652 const SGPropertyNode* conditionNode = _configNode->getChild("condition");
655 return sgReadCondition(_modelRoot, conditionNode);
660 ////////////////////////////////////////////////////////////////////////
661 // Implementation of null animation
662 ////////////////////////////////////////////////////////////////////////
664 // Ok, that is to build a subgraph from different other
665 // graph nodes. I guess that this stems from the time where modellers
666 // could not build hierarchical trees ...
667 SGGroupAnimation::SGGroupAnimation(const SGPropertyNode* configNode,
668 SGPropertyNode* modelRoot):
669 SGAnimation(configNode, modelRoot)
674 SGGroupAnimation::createAnimationGroup(osg::Group& parent)
676 osg::Group* group = new osg::Group;
677 parent.addChild(group);
682 ////////////////////////////////////////////////////////////////////////
683 // Implementation of translate animation
684 ////////////////////////////////////////////////////////////////////////
686 class SGTranslateAnimation::Transform : public osg::Transform {
691 { setReferenceFrame(RELATIVE_RF); }
692 void setAxis(const SGVec3d& axis)
693 { _axis = axis; dirtyBound(); }
694 void setValue(double value)
695 { _value = value; dirtyBound(); }
696 virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
697 osg::NodeVisitor* nv) const
699 assert(_referenceFrame == RELATIVE_RF);
701 set_translation(tmp, _value, _axis);
705 virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
706 osg::NodeVisitor* nv) const
708 assert(_referenceFrame == RELATIVE_RF);
710 set_translation(tmp, -_value, _axis);
711 matrix.postMult(tmp);
719 class SGTranslateAnimation::UpdateCallback : public osg::NodeCallback {
721 UpdateCallback(SGCondition const* condition,
722 SGDoubleValue const* animationValue) :
723 _condition(condition),
724 _animationValue(animationValue)
726 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
728 if (!_condition || _condition->test()) {
729 SGTranslateAnimation::Transform* transform;
730 transform = static_cast<SGTranslateAnimation::Transform*>(node);
731 transform->setValue(_animationValue->getValue());
736 SGSharedPtr<SGCondition const> _condition;
737 SGSharedPtr<SGDoubleValue const> _animationValue;
740 SGTranslateAnimation::SGTranslateAnimation(const SGPropertyNode* configNode,
741 SGPropertyNode* modelRoot) :
742 SGAnimation(configNode, modelRoot)
744 _condition = getCondition();
745 _animationValue = read_value(configNode, modelRoot, "-m",
746 -SGLimitsd::max(), SGLimitsd::max());
747 _axis[0] = configNode->getDoubleValue("axis/x", 0);
748 _axis[1] = configNode->getDoubleValue("axis/y", 0);
749 _axis[2] = configNode->getDoubleValue("axis/z", 0);
750 if (8*SGLimitsd::min() < norm(_axis))
751 _axis = normalize(_axis);
753 _initialValue = configNode->getDoubleValue("starting-position-m", 0);
754 _initialValue *= configNode->getDoubleValue("factor", 1);
755 _initialValue += configNode->getDoubleValue("offset-m", 0);
759 SGTranslateAnimation::createAnimationGroup(osg::Group& parent)
761 Transform* transform = new Transform;
762 transform->setName("translate animation");
763 if (_animationValue) {
764 UpdateCallback* uc = new UpdateCallback(_condition, _animationValue);
765 transform->setUpdateCallback(uc);
767 transform->setAxis(_axis);
768 transform->setValue(_initialValue);
769 parent.addChild(transform);
774 ////////////////////////////////////////////////////////////////////////
775 // Implementation of rotate/spin animation
776 ////////////////////////////////////////////////////////////////////////
778 class SGRotateAnimation::Transform : public osg::Transform {
781 { setReferenceFrame(RELATIVE_RF); }
782 void setCenter(const SGVec3d& center)
783 { _center = center; dirtyBound(); }
784 void setAxis(const SGVec3d& axis)
785 { _axis = axis; dirtyBound(); }
786 void setAngle(double angle)
788 double getAngle() const
790 virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
791 osg::NodeVisitor* nv) const
793 // This is the fast path, optimize a bit
794 assert(_referenceFrame == RELATIVE_RF);
797 set_rotation(tmp, _angle, _center, _axis);
801 virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
802 osg::NodeVisitor* nv) const
804 assert(_referenceFrame == RELATIVE_RF);
807 set_rotation(tmp, -_angle, _center, _axis);
808 matrix.postMult(tmp);
811 virtual osg::BoundingSphere computeBound() const
813 osg::BoundingSphere bs = osg::Group::computeBound();
814 osg::BoundingSphere centerbs(_center.osg(), bs.radius());
815 centerbs.expandBy(bs);
825 class SGRotateAnimation::UpdateCallback : public osg::NodeCallback {
827 UpdateCallback(SGCondition const* condition,
828 SGDoubleValue const* animationValue) :
829 _condition(condition),
830 _animationValue(animationValue)
832 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
834 if (!_condition || _condition->test()) {
835 SGRotateAnimation::Transform* transform;
836 transform = static_cast<SGRotateAnimation::Transform*>(node);
837 transform->setAngle(_animationValue->getValue());
842 SGSharedPtr<SGCondition const> _condition;
843 SGSharedPtr<SGDoubleValue const> _animationValue;
846 class SGRotateAnimation::SpinUpdateCallback : public osg::NodeCallback {
848 SpinUpdateCallback(SGCondition const* condition,
849 SGDoubleValue const* animationValue) :
850 _condition(condition),
851 _animationValue(animationValue),
854 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
856 if (!_condition || _condition->test()) {
857 SGRotateAnimation::Transform* transform;
858 transform = static_cast<SGRotateAnimation::Transform*>(node);
860 double t = nv->getFrameStamp()->getReferenceTime();
865 double velocity_rpms = _animationValue->getValue()/60;
866 double angle = transform->getAngle();
867 angle += dt*velocity_rpms*360;
868 angle -= 360*floor(angle/360);
869 transform->setAngle(angle);
874 SGSharedPtr<SGCondition const> _condition;
875 SGSharedPtr<SGDoubleValue const> _animationValue;
879 SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode, SGPropertyNode* modelRoot) :
880 SGAnimation(configNode, modelRoot)
882 std::string type = configNode->getStringValue("type", "");
883 _isSpin = (type == "spin");
885 _condition = getCondition();
886 _animationValue = read_value(configNode, modelRoot, "-deg",
887 -SGLimitsd::max(), SGLimitsd::max());
888 _initialValue = configNode->getDoubleValue("starting-position-deg", 0);
889 _initialValue *= configNode->getDoubleValue("factor", 1);
890 _initialValue += configNode->getDoubleValue("offset-deg", 0);
892 _center = SGVec3d::zeros();
893 if (configNode->hasValue("axis/x1-m")) {
895 v1[0] = configNode->getDoubleValue("axis/x1-m", 0);
896 v1[1] = configNode->getDoubleValue("axis/y1-m", 0);
897 v1[2] = configNode->getDoubleValue("axis/z1-m", 0);
898 v2[0] = configNode->getDoubleValue("axis/x2-m", 0);
899 v2[1] = configNode->getDoubleValue("axis/y2-m", 0);
900 v2[2] = configNode->getDoubleValue("axis/z2-m", 0);
901 _center = 0.5*(v1+v2);
904 _axis[0] = configNode->getDoubleValue("axis/x", 0);
905 _axis[1] = configNode->getDoubleValue("axis/y", 0);
906 _axis[2] = configNode->getDoubleValue("axis/z", 0);
908 if (8*SGLimitsd::min() < norm(_axis))
909 _axis = normalize(_axis);
911 _center[0] = configNode->getDoubleValue("center/x-m", _center[0]);
912 _center[1] = configNode->getDoubleValue("center/y-m", _center[1]);
913 _center[2] = configNode->getDoubleValue("center/z-m", _center[2]);
917 SGRotateAnimation::createAnimationGroup(osg::Group& parent)
919 Transform* transform = new Transform;
920 transform->setName("rotate animation");
922 SpinUpdateCallback* uc;
923 uc = new SpinUpdateCallback(_condition, _animationValue);
924 transform->setUpdateCallback(uc);
925 } else if (_animationValue) {
926 UpdateCallback* uc = new UpdateCallback(_condition, _animationValue);
927 transform->setUpdateCallback(uc);
929 transform->setCenter(_center);
930 transform->setAxis(_axis);
931 transform->setAngle(_initialValue);
932 parent.addChild(transform);
937 ////////////////////////////////////////////////////////////////////////
938 // Implementation of scale animation
939 ////////////////////////////////////////////////////////////////////////
941 class SGScaleAnimation::Transform : public osg::Transform {
945 _scaleFactor(1, 1, 1),
948 setReferenceFrame(RELATIVE_RF);
950 void setCenter(const SGVec3d& center)
955 void setScaleFactor(const SGVec3d& scaleFactor)
957 if (_boundScale < normI(scaleFactor))
959 _scaleFactor = scaleFactor;
961 void setScaleFactor(double scaleFactor)
963 if (_boundScale < fabs(scaleFactor))
965 _scaleFactor = SGVec3d(scaleFactor, scaleFactor, scaleFactor);
967 virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
968 osg::NodeVisitor* nv) const
970 assert(_referenceFrame == RELATIVE_RF);
971 osg::Matrix transform;
972 transform(0,0) = _scaleFactor[0];
973 transform(1,1) = _scaleFactor[1];
974 transform(2,2) = _scaleFactor[2];
975 transform(3,0) = _center[0]*(1 - _scaleFactor[0]);
976 transform(3,1) = _center[1]*(1 - _scaleFactor[1]);
977 transform(3,2) = _center[2]*(1 - _scaleFactor[2]);
978 matrix.preMult(transform);
981 virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
982 osg::NodeVisitor* nv) const
984 assert(_referenceFrame == RELATIVE_RF);
985 if (fabs(_scaleFactor[0]) < SGLimitsd::min())
987 if (fabs(_scaleFactor[1]) < SGLimitsd::min())
989 if (fabs(_scaleFactor[2]) < SGLimitsd::min())
991 SGVec3d rScaleFactor(1/_scaleFactor[0],
994 osg::Matrix transform;
995 transform(0,0) = rScaleFactor[0];
996 transform(1,1) = rScaleFactor[1];
997 transform(2,2) = rScaleFactor[2];
998 transform(3,0) = _center[0]*(1 - rScaleFactor[0]);
999 transform(3,1) = _center[1]*(1 - rScaleFactor[1]);
1000 transform(3,2) = _center[2]*(1 - rScaleFactor[2]);
1001 matrix.postMult(transform);
1004 virtual osg::BoundingSphere computeBound() const
1006 osg::BoundingSphere bs = osg::Group::computeBound();
1007 _boundScale = normI(_scaleFactor);
1008 bs.radius() *= _boundScale;
1014 SGVec3d _scaleFactor;
1015 mutable double _boundScale;
1018 class SGScaleAnimation::UpdateCallback : public osg::NodeCallback {
1020 UpdateCallback(const SGCondition* condition,
1021 SGSharedPtr<const SGDoubleValue> animationValue[3]) :
1022 _condition(condition)
1024 _animationValue[0] = animationValue[0];
1025 _animationValue[1] = animationValue[1];
1026 _animationValue[2] = animationValue[2];
1028 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
1030 if (!_condition || _condition->test()) {
1031 SGScaleAnimation::Transform* transform;
1032 transform = static_cast<SGScaleAnimation::Transform*>(node);
1033 SGVec3d scale(_animationValue[0]->getValue(),
1034 _animationValue[1]->getValue(),
1035 _animationValue[2]->getValue());
1036 transform->setScaleFactor(scale);
1041 SGSharedPtr<SGCondition const> _condition;
1042 SGSharedPtr<SGDoubleValue const> _animationValue[3];
1045 SGScaleAnimation::SGScaleAnimation(const SGPropertyNode* configNode,
1046 SGPropertyNode* modelRoot) :
1047 SGAnimation(configNode, modelRoot)
1049 _condition = getCondition();
1051 // default offset/factor for all directions
1052 double offset = configNode->getDoubleValue("offset", 1);
1053 double factor = configNode->getDoubleValue("factor", 1);
1055 std::string inputPropertyName;
1056 inputPropertyName = configNode->getStringValue("property", "");
1057 if (!inputPropertyName.empty()) {
1058 SGPropertyNode* inputProperty;
1059 inputProperty = modelRoot->getNode(inputPropertyName.c_str(), true);
1060 SGInterpTable* interpTable = read_interpolation_table(configNode);
1062 SGInterpTableValue* value;
1063 value = new SGInterpTableValue(inputProperty, interpTable);
1064 _animationValue[0] = value;
1065 _animationValue[1] = value;
1066 _animationValue[2] = value;
1067 } else if (configNode->getBoolValue("use-personality", false)) {
1068 SGPersScaleOffsetValue* value;
1069 value = new SGPersScaleOffsetValue(inputProperty, configNode,
1070 "x-factor", "x-offset",
1072 value->setMin(configNode->getDoubleValue("x-min", 0));
1073 value->setMax(configNode->getDoubleValue("x-max", SGLimitsd::max()));
1074 _animationValue[0] = value;
1075 value = new SGPersScaleOffsetValue(inputProperty, configNode,
1076 "y-factor", "y-offset",
1078 value->setMin(configNode->getDoubleValue("y-min", 0));
1079 value->setMax(configNode->getDoubleValue("y-max", SGLimitsd::max()));
1080 _animationValue[1] = value;
1081 value = new SGPersScaleOffsetValue(inputProperty, configNode,
1082 "z-factor", "z-offset",
1084 value->setMin(configNode->getDoubleValue("z-min", 0));
1085 value->setMax(configNode->getDoubleValue("z-max", SGLimitsd::max()));
1086 _animationValue[2] = value;
1088 SGScaleOffsetValue* value = new SGScaleOffsetValue(inputProperty);
1089 value->setScale(configNode->getDoubleValue("x-factor", factor));
1090 value->setOffset(configNode->getDoubleValue("x-offset", offset));
1091 value->setMin(configNode->getDoubleValue("x-min", 0));
1092 value->setMax(configNode->getDoubleValue("x-max", SGLimitsd::max()));
1093 _animationValue[0] = value;
1094 value = new SGScaleOffsetValue(inputProperty);
1095 value->setScale(configNode->getDoubleValue("y-factor", factor));
1096 value->setOffset(configNode->getDoubleValue("y-offset", offset));
1097 value->setMin(configNode->getDoubleValue("y-min", 0));
1098 value->setMax(configNode->getDoubleValue("y-max", SGLimitsd::max()));
1099 _animationValue[1] = value;
1100 value = new SGScaleOffsetValue(inputProperty);
1101 value->setScale(configNode->getDoubleValue("z-factor", factor));
1102 value->setOffset(configNode->getDoubleValue("z-offset", offset));
1103 value->setMin(configNode->getDoubleValue("z-min", 0));
1104 value->setMax(configNode->getDoubleValue("z-max", SGLimitsd::max()));
1105 _animationValue[2] = value;
1108 _initialValue[0] = configNode->getDoubleValue("x-starting-scale", 1);
1109 _initialValue[0] *= configNode->getDoubleValue("x-factor", factor);
1110 _initialValue[0] += configNode->getDoubleValue("x-offset", offset);
1111 _initialValue[1] = configNode->getDoubleValue("y-starting-scale", 1);
1112 _initialValue[1] *= configNode->getDoubleValue("y-factor", factor);
1113 _initialValue[1] += configNode->getDoubleValue("y-offset", offset);
1114 _initialValue[2] = configNode->getDoubleValue("z-starting-scale", 1);
1115 _initialValue[2] *= configNode->getDoubleValue("z-factor", factor);
1116 _initialValue[2] += configNode->getDoubleValue("z-offset", offset);
1117 _center[0] = configNode->getDoubleValue("center/x-m", 0);
1118 _center[1] = configNode->getDoubleValue("center/y-m", 0);
1119 _center[2] = configNode->getDoubleValue("center/z-m", 0);
1123 SGScaleAnimation::createAnimationGroup(osg::Group& parent)
1125 Transform* transform = new Transform;
1126 transform->setName("scale animation");
1127 transform->setCenter(_center);
1128 transform->setScaleFactor(_initialValue);
1129 UpdateCallback* uc = new UpdateCallback(_condition, _animationValue);
1130 transform->setUpdateCallback(uc);
1131 parent.addChild(transform);
1136 ////////////////////////////////////////////////////////////////////////
1137 // Implementation of dist scale animation
1138 ////////////////////////////////////////////////////////////////////////
1140 class SGDistScaleAnimation::Transform : public osg::Transform {
1142 Transform(const SGPropertyNode* configNode)
1144 setName(configNode->getStringValue("name", "dist scale animation"));
1145 setReferenceFrame(RELATIVE_RF);
1146 getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
1147 _factor = configNode->getFloatValue("factor", 1);
1148 _offset = configNode->getFloatValue("offset", 0);
1149 _min_v = configNode->getFloatValue("min", SGLimitsf::epsilon());
1150 _max_v = configNode->getFloatValue("max", SGLimitsf::max());
1151 _table = read_interpolation_table(configNode);
1152 _center[0] = configNode->getFloatValue("center/x-m", 0);
1153 _center[1] = configNode->getFloatValue("center/y-m", 0);
1154 _center[2] = configNode->getFloatValue("center/z-m", 0);
1156 virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
1157 osg::NodeVisitor* nv) const
1159 osg::Matrix transform;
1160 double scale_factor = computeScaleFactor(nv);
1161 transform(0,0) = scale_factor;
1162 transform(1,1) = scale_factor;
1163 transform(2,2) = scale_factor;
1164 transform(3,0) = _center[0]*(1 - scale_factor);
1165 transform(3,1) = _center[1]*(1 - scale_factor);
1166 transform(3,2) = _center[2]*(1 - scale_factor);
1167 matrix.preMult(transform);
1171 virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
1172 osg::NodeVisitor* nv) const
1174 double scale_factor = computeScaleFactor(nv);
1175 if (fabs(scale_factor) <= SGLimits<double>::min())
1177 osg::Matrix transform;
1178 double rScaleFactor = 1/scale_factor;
1179 transform(0,0) = rScaleFactor;
1180 transform(1,1) = rScaleFactor;
1181 transform(2,2) = rScaleFactor;
1182 transform(3,0) = _center[0]*(1 - rScaleFactor);
1183 transform(3,1) = _center[1]*(1 - rScaleFactor);
1184 transform(3,2) = _center[2]*(1 - rScaleFactor);
1185 matrix.postMult(transform);
1190 double computeScaleFactor(osg::NodeVisitor* nv) const
1195 double scale_factor = (_center.osg() - nv->getEyePoint()).length();
1197 scale_factor = _factor * scale_factor + _offset;
1199 scale_factor = _table->interpolate( scale_factor );
1201 if (scale_factor < _min_v)
1202 scale_factor = _min_v;
1203 if (scale_factor > _max_v)
1204 scale_factor = _max_v;
1206 return scale_factor;
1209 SGSharedPtr<SGInterpTable> _table;
1218 SGDistScaleAnimation::SGDistScaleAnimation(const SGPropertyNode* configNode,
1219 SGPropertyNode* modelRoot) :
1220 SGAnimation(configNode, modelRoot)
1225 SGDistScaleAnimation::createAnimationGroup(osg::Group& parent)
1227 Transform* transform = new Transform(getConfig());
1228 parent.addChild(transform);
1233 ////////////////////////////////////////////////////////////////////////
1234 // Implementation of flash animation
1235 ////////////////////////////////////////////////////////////////////////
1237 class SGFlashAnimation::Transform : public osg::Transform {
1239 Transform(const SGPropertyNode* configNode)
1241 setReferenceFrame(RELATIVE_RF);
1242 setName(configNode->getStringValue("name", "flash animation"));
1243 getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
1245 _axis[0] = configNode->getFloatValue("axis/x", 0);
1246 _axis[1] = configNode->getFloatValue("axis/y", 0);
1247 _axis[2] = configNode->getFloatValue("axis/z", 1);
1250 _center[0] = configNode->getFloatValue("center/x-m", 0);
1251 _center[1] = configNode->getFloatValue("center/y-m", 0);
1252 _center[2] = configNode->getFloatValue("center/z-m", 0);
1254 _offset = configNode->getFloatValue("offset", 0);
1255 _factor = configNode->getFloatValue("factor", 1);
1256 _power = configNode->getFloatValue("power", 1);
1257 _two_sides = configNode->getBoolValue("two-sides", false);
1259 _min_v = configNode->getFloatValue("min", SGLimitsf::epsilon());
1260 _max_v = configNode->getFloatValue("max", 1);
1262 virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
1263 osg::NodeVisitor* nv) const
1265 osg::Matrix transform;
1266 double scale_factor = computeScaleFactor(nv);
1267 transform(0,0) = scale_factor;
1268 transform(1,1) = scale_factor;
1269 transform(2,2) = scale_factor;
1270 transform(3,0) = _center[0]*(1 - scale_factor);
1271 transform(3,1) = _center[1]*(1 - scale_factor);
1272 transform(3,2) = _center[2]*(1 - scale_factor);
1273 matrix.preMult(transform);
1277 virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
1278 osg::NodeVisitor* nv) const
1280 double scale_factor = computeScaleFactor(nv);
1281 if (fabs(scale_factor) <= SGLimits<double>::min())
1283 osg::Matrix transform;
1284 double rScaleFactor = 1/scale_factor;
1285 transform(0,0) = rScaleFactor;
1286 transform(1,1) = rScaleFactor;
1287 transform(2,2) = rScaleFactor;
1288 transform(3,0) = _center[0]*(1 - rScaleFactor);
1289 transform(3,1) = _center[1]*(1 - rScaleFactor);
1290 transform(3,2) = _center[2]*(1 - rScaleFactor);
1291 matrix.postMult(transform);
1296 double computeScaleFactor(osg::NodeVisitor* nv) const
1301 osg::Vec3 localEyeToCenter = nv->getEyePoint() - _center;
1302 localEyeToCenter.normalize();
1304 double cos_angle = localEyeToCenter*_axis;
1305 double scale_factor = 0;
1306 if ( _two_sides && cos_angle < 0 )
1307 scale_factor = _factor * pow( -cos_angle, _power ) + _offset;
1308 else if ( cos_angle > 0 )
1309 scale_factor = _factor * pow( cos_angle, _power ) + _offset;
1311 if ( scale_factor < _min_v )
1312 scale_factor = _min_v;
1313 if ( scale_factor > _max_v )
1314 scale_factor = _max_v;
1316 return scale_factor;
1319 virtual osg::BoundingSphere computeBound() const
1321 // avoid being culled away by small feature culling
1322 osg::BoundingSphere bs = osg::Group::computeBound();
1323 bs.radius() *= _max_v;
1330 double _power, _factor, _offset, _min_v, _max_v;
1335 SGFlashAnimation::SGFlashAnimation(const SGPropertyNode* configNode,
1336 SGPropertyNode* modelRoot) :
1337 SGAnimation(configNode, modelRoot)
1342 SGFlashAnimation::createAnimationGroup(osg::Group& parent)
1344 Transform* transform = new Transform(getConfig());
1345 parent.addChild(transform);
1350 ////////////////////////////////////////////////////////////////////////
1351 // Implementation of flash animation
1352 ////////////////////////////////////////////////////////////////////////
1354 class SGBillboardAnimation::Transform : public osg::Transform {
1356 Transform(const SGPropertyNode* configNode) :
1357 _spherical(configNode->getBoolValue("spherical", true))
1359 setReferenceFrame(RELATIVE_RF);
1360 setName(configNode->getStringValue("name", "billboard animation"));
1362 virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
1363 osg::NodeVisitor* nv) const
1365 // More or less taken from plibs ssgCutout
1367 matrix(0,0) = 1; matrix(0,1) = 0; matrix(0,2) = 0;
1368 matrix(1,0) = 0; matrix(1,1) = 0; matrix(1,2) = -1;
1369 matrix(2,0) = 0; matrix(2,1) = 1; matrix(2,2) = 0;
1371 osg::Vec3 zAxis(matrix(2, 0), matrix(2, 1), matrix(2, 2));
1372 osg::Vec3 xAxis = osg::Vec3(0, 0, -1)^zAxis;
1373 osg::Vec3 yAxis = zAxis^xAxis;
1379 matrix(0,0) = xAxis[0]; matrix(0,1) = xAxis[1]; matrix(0,2) = xAxis[2];
1380 matrix(1,0) = yAxis[0]; matrix(1,1) = yAxis[1]; matrix(1,2) = yAxis[2];
1381 matrix(2,0) = zAxis[0]; matrix(2,1) = zAxis[1]; matrix(2,2) = zAxis[2];
1386 virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
1387 osg::NodeVisitor* nv) const
1389 // Hmm, don't yet know how to get that back ...
1398 SGBillboardAnimation::SGBillboardAnimation(const SGPropertyNode* configNode,
1399 SGPropertyNode* modelRoot) :
1400 SGAnimation(configNode, modelRoot)
1405 SGBillboardAnimation::createAnimationGroup(osg::Group& parent)
1407 Transform* transform = new Transform(getConfig());
1408 parent.addChild(transform);
1413 ////////////////////////////////////////////////////////////////////////
1414 // Implementation of a range animation
1415 ////////////////////////////////////////////////////////////////////////
1417 class SGRangeAnimation::UpdateCallback : public osg::NodeCallback {
1419 UpdateCallback(const SGCondition* condition,
1420 const SGDoubleValue* minAnimationValue,
1421 const SGDoubleValue* maxAnimationValue,
1422 double minValue, double maxValue) :
1423 _condition(condition),
1424 _minAnimationValue(minAnimationValue),
1425 _maxAnimationValue(maxAnimationValue),
1426 _minStaticValue(minValue),
1427 _maxStaticValue(maxValue)
1429 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
1431 osg::LOD* lod = static_cast<osg::LOD*>(node);
1432 if (!_condition || _condition->test()) {
1434 if (_minAnimationValue)
1435 minRange = _minAnimationValue->getValue();
1437 minRange = _minStaticValue;
1439 if (_maxAnimationValue)
1440 maxRange = _maxAnimationValue->getValue();
1442 maxRange = _maxStaticValue;
1443 lod->setRange(0, minRange, maxRange);
1445 lod->setRange(0, 0, SGLimitsf::max());
1451 SGSharedPtr<const SGCondition> _condition;
1452 SGSharedPtr<const SGDoubleValue> _minAnimationValue;
1453 SGSharedPtr<const SGDoubleValue> _maxAnimationValue;
1454 double _minStaticValue;
1455 double _maxStaticValue;
1458 SGRangeAnimation::SGRangeAnimation(const SGPropertyNode* configNode,
1459 SGPropertyNode* modelRoot) :
1460 SGAnimation(configNode, modelRoot)
1462 _condition = getCondition();
1464 std::string inputPropertyName;
1465 inputPropertyName = configNode->getStringValue("min-property", "");
1466 if (!inputPropertyName.empty()) {
1467 SGPropertyNode* inputProperty;
1468 inputProperty = modelRoot->getNode(inputPropertyName.c_str(), true);
1469 SGScaleOffsetValue* value = new SGScaleOffsetValue(inputProperty);
1470 value->setScale(configNode->getDoubleValue("min-factor", 1));
1471 _minAnimationValue = value;
1473 inputPropertyName = configNode->getStringValue("max-property", "");
1474 if (!inputPropertyName.empty()) {
1475 SGPropertyNode* inputProperty;
1476 inputProperty = modelRoot->getNode(inputPropertyName.c_str(), true);
1477 SGScaleOffsetValue* value = new SGScaleOffsetValue(inputProperty);
1478 value->setScale(configNode->getDoubleValue("max-factor", 1));
1479 _maxAnimationValue = value;
1482 _initialValue[0] = configNode->getDoubleValue("min-m", 0);
1483 _initialValue[0] *= configNode->getDoubleValue("min-factor", 1);
1484 _initialValue[1] = configNode->getDoubleValue("max-m", SGLimitsf::max());
1485 _initialValue[1] *= configNode->getDoubleValue("max-factor", 1);
1489 SGRangeAnimation::createAnimationGroup(osg::Group& parent)
1491 osg::Group* group = new osg::Group;
1492 group->setName("range animation group");
1494 osg::LOD* lod = new osg::LOD;
1495 lod->setName("range animation node");
1496 parent.addChild(lod);
1498 lod->addChild(group, _initialValue[0], _initialValue[1]);
1499 lod->setCenterMode(osg::LOD::USE_BOUNDING_SPHERE_CENTER);
1500 lod->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT);
1501 if (_minAnimationValue || _maxAnimationValue || _condition) {
1503 uc = new UpdateCallback(_condition, _minAnimationValue, _maxAnimationValue,
1504 _initialValue[0], _initialValue[1]);
1505 lod->setUpdateCallback(uc);
1511 ////////////////////////////////////////////////////////////////////////
1512 // Implementation of a select animation
1513 ////////////////////////////////////////////////////////////////////////
1515 class SGSelectAnimation::UpdateCallback : public osg::NodeCallback {
1517 UpdateCallback(const SGCondition* condition) :
1518 _condition(condition)
1520 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
1522 osg::Switch* sw = static_cast<osg::Switch*>(node);
1523 if (_condition->test())
1524 sw->setAllChildrenOn();
1526 sw->setAllChildrenOff();
1531 SGSharedPtr<SGCondition const> _condition;
1534 SGSelectAnimation::SGSelectAnimation(const SGPropertyNode* configNode,
1535 SGPropertyNode* modelRoot) :
1536 SGAnimation(configNode, modelRoot)
1541 SGSelectAnimation::createAnimationGroup(osg::Group& parent)
1543 // if no condition given, this is a noop.
1544 SGSharedPtr<SGCondition const> condition = getCondition();
1545 // trick, gets deleted with all its 'animated' children
1546 // when the animation installer returns
1548 return new osg::Group;
1550 osg::Switch* sw = new osg::Switch;
1551 sw->setName("select animation node");
1552 sw->setUpdateCallback(new UpdateCallback(condition));
1553 parent.addChild(sw);
1559 ////////////////////////////////////////////////////////////////////////
1560 // Implementation of alpha test animation
1561 ////////////////////////////////////////////////////////////////////////
1563 SGAlphaTestAnimation::SGAlphaTestAnimation(const SGPropertyNode* configNode,
1564 SGPropertyNode* modelRoot) :
1565 SGAnimation(configNode, modelRoot)
1570 SGAlphaTestAnimation::install(osg::Node& node)
1572 SGAnimation::install(node);
1574 cloneDrawables(node);
1575 removeMode(node, GL_ALPHA_TEST);
1576 removeAttribute(node, osg::StateAttribute::ALPHAFUNC);
1578 osg::StateSet* stateSet = node.getOrCreateStateSet();
1579 osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
1580 alphaFunc->setFunction(osg::AlphaFunc::GREATER);
1581 float alphaClamp = getConfig()->getFloatValue("alpha-factor", 0);
1582 alphaFunc->setReferenceValue(alphaClamp);
1583 stateSet->setAttribute(alphaFunc);
1584 stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
1589 //////////////////////////////////////////////////////////////////////
1590 // Blend animation installer
1591 //////////////////////////////////////////////////////////////////////
1593 class SGBlendAnimation::BlendVisitor : public osg::NodeVisitor {
1595 BlendVisitor(float blend) :
1596 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
1598 { setVisitorType(osg::NodeVisitor::NODE_VISITOR); }
1599 virtual void apply(osg::Node& node)
1601 updateStateSet(node.getStateSet());
1604 virtual void apply(osg::Geode& node)
1606 apply((osg::Node&)node);
1607 unsigned nDrawables = node.getNumDrawables();
1608 for (unsigned i = 0; i < nDrawables; ++i) {
1609 osg::Drawable* drawable = node.getDrawable(i);
1610 updateStateSet(drawable->getStateSet());
1611 osg::Geometry* geometry = drawable->asGeometry();
1614 osg::Array* array = geometry->getColorArray();
1617 osg::Vec4Array* vec4Array = dynamic_cast<osg::Vec4Array*>(array);
1620 geometry->dirtyDisplayList();
1622 for (unsigned k = 0; k < vec4Array->size(); ++k) {
1623 (*vec4Array)[k][3] = _blend;
1627 void updateStateSet(osg::StateSet* stateSet)
1631 osg::StateAttribute* stateAttribute;
1632 stateAttribute = stateSet->getAttribute(osg::StateAttribute::MATERIAL);
1633 if (!stateAttribute)
1635 osg::Material* material = dynamic_cast<osg::Material*>(stateAttribute);
1638 material->setAlpha(osg::Material::FRONT_AND_BACK, _blend);
1640 stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
1641 stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
1643 stateSet->setRenderingHint(osg::StateSet::DEFAULT_BIN);
1650 class SGBlendAnimation::UpdateCallback : public osg::NodeCallback {
1652 UpdateCallback(const SGPropertyNode* configNode, const SGDoubleValue* v) :
1656 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
1658 double blend = _animationValue->getValue();
1659 if (blend != _prev_value) {
1660 _prev_value = blend;
1661 BlendVisitor visitor(1-blend);
1662 node->accept(visitor);
1668 SGSharedPtr<SGDoubleValue const> _animationValue;
1672 SGBlendAnimation::SGBlendAnimation(const SGPropertyNode* configNode,
1673 SGPropertyNode* modelRoot)
1674 : SGAnimation(configNode, modelRoot),
1675 _animationValue(read_value(configNode, modelRoot, "", 0, 1))
1680 SGBlendAnimation::createAnimationGroup(osg::Group& parent)
1682 if (!_animationValue)
1685 osg::Group* group = new osg::Switch;
1686 group->setName("blend animation node");
1687 group->setUpdateCallback(new UpdateCallback(getConfig(), _animationValue));
1688 parent.addChild(group);
1693 SGBlendAnimation::install(osg::Node& node)
1695 SGAnimation::install(node);
1696 // make sure we do not change common geometries,
1697 // that also creates new display lists for these subgeometries.
1698 cloneDrawables(node);
1702 //////////////////////////////////////////////////////////////////////
1703 // Timed animation installer
1704 //////////////////////////////////////////////////////////////////////
1708 class SGTimedAnimation::UpdateCallback : public osg::NodeCallback {
1710 UpdateCallback(const SGPropertyNode* configNode) :
1713 _duration_sec(configNode->getDoubleValue("duration-sec", 1)),
1714 _last_time_sec(SGLimitsd::max()),
1715 _use_personality(configNode->getBoolValue("use-personality", false))
1717 std::vector<SGSharedPtr<SGPropertyNode> > nodes;
1718 nodes = configNode->getChildren("branch-duration-sec");
1719 for (size_t i = 0; i < nodes.size(); ++i) {
1720 unsigned ind = nodes[ i ]->getIndex();
1721 while ( ind >= _durations.size() ) {
1722 _durations.push_back(DurationSpec(_duration_sec));
1724 SGPropertyNode_ptr rNode = nodes[i]->getChild("random");
1726 _durations[ind] = DurationSpec(nodes[ i ]->getDoubleValue());
1728 _durations[ind] = DurationSpec(rNode->getDoubleValue( "min", 0),
1729 rNode->getDoubleValue( "max", 1));
1733 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
1735 assert(dynamic_cast<osg::Switch*>(node));
1736 osg::Switch* sw = static_cast<osg::Switch*>(node);
1738 unsigned nChildren = sw->getNumChildren();
1740 // blow up the durations vector to the required size
1741 while (_durations.size() < nChildren) {
1742 _durations.push_back(_duration_sec);
1744 // make sure the current index is an duration that really exists
1745 _current_index = _current_index % nChildren;
1747 // update the time and compute the current systems time value
1748 double t = nv->getFrameStamp()->getReferenceTime();
1749 if (_last_time_sec == SGLimitsd::max()) {
1752 double dt = t - _last_time_sec;
1753 if (_use_personality)
1754 dt *= 1 + 0.2*(0.5 - sg_random());
1759 double currentDuration = _durations[_current_index].get();
1760 while (currentDuration < _reminder) {
1761 _reminder -= currentDuration;
1762 _current_index = (_current_index + 1) % nChildren;
1763 currentDuration = _durations[_current_index].get();
1766 sw->setSingleChildOn(_current_index);
1772 struct DurationSpec {
1773 DurationSpec(double t) :
1774 minTime(SGMiscd::max(0.01, t)),
1775 maxTime(SGMiscd::max(0.01, t))
1777 DurationSpec(double t0, double t1) :
1778 minTime(SGMiscd::max(0.01, t0)),
1779 maxTime(SGMiscd::max(0.01, t1))
1782 { return minTime + sg_random()*(maxTime - minTime); }
1786 std::vector<DurationSpec> _durations;
1787 unsigned _current_index;
1789 double _duration_sec;
1790 double _last_time_sec;
1791 bool _use_personality;
1795 SGTimedAnimation::SGTimedAnimation(const SGPropertyNode* configNode,
1796 SGPropertyNode* modelRoot)
1797 : SGAnimation(configNode, modelRoot)
1802 SGTimedAnimation::createAnimationGroup(osg::Group& parent)
1804 osg::Switch* sw = new osg::Switch;
1805 sw->setName("timed animation node");
1806 sw->setUpdateCallback(new UpdateCallback(getConfig()));
1807 parent.addChild(sw);
1812 ////////////////////////////////////////////////////////////////////////
1813 // dynamically switch on/off shadows
1814 ////////////////////////////////////////////////////////////////////////
1816 class SGShadowAnimation::UpdateCallback : public osg::NodeCallback {
1818 UpdateCallback(const SGCondition* condition) :
1819 _condition(condition)
1821 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
1823 if (_condition->test())
1824 node->setNodeMask( SG_NODEMASK_SHADOW_BIT | node->getNodeMask());
1826 node->setNodeMask(~SG_NODEMASK_SHADOW_BIT & node->getNodeMask());
1831 SGSharedPtr<const SGCondition> _condition;
1834 SGShadowAnimation::SGShadowAnimation(const SGPropertyNode* configNode,
1835 SGPropertyNode* modelRoot) :
1836 SGAnimation(configNode, modelRoot)
1841 SGShadowAnimation::createAnimationGroup(osg::Group& parent)
1843 SGSharedPtr<SGCondition const> condition = getCondition();
1847 osg::Group* group = new osg::Group;
1848 group->setName("shadow animation");
1849 group->setUpdateCallback(new UpdateCallback(condition));
1850 parent.addChild(group);
1855 ////////////////////////////////////////////////////////////////////////
1856 // Implementation of SGTexTransformAnimation
1857 ////////////////////////////////////////////////////////////////////////
1859 class SGTexTransformAnimation::Transform : public SGReferenced {
1864 virtual ~Transform()
1866 void setValue(double value)
1868 virtual void transform(osg::Matrix&) = 0;
1873 class SGTexTransformAnimation::Translation :
1874 public SGTexTransformAnimation::Transform {
1876 Translation(const SGVec3d& axis) :
1879 void setValue(double value)
1881 virtual void transform(osg::Matrix& matrix)
1884 set_translation(tmp, _value, _axis);
1885 matrix.preMult(tmp);
1891 class SGTexTransformAnimation::Rotation :
1892 public SGTexTransformAnimation::Transform {
1894 Rotation(const SGVec3d& axis, const SGVec3d& center) :
1898 virtual void transform(osg::Matrix& matrix)
1901 set_rotation(tmp, _value, _center, _axis);
1902 matrix.preMult(tmp);
1909 class SGTexTransformAnimation::UpdateCallback :
1910 public osg::StateAttribute::Callback {
1912 UpdateCallback(const SGCondition* condition) :
1913 _condition(condition)
1915 virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor*)
1917 if (!_condition || _condition->test()) {
1918 TransformList::const_iterator i;
1919 for (i = _transforms.begin(); i != _transforms.end(); ++i)
1920 i->transform->setValue(i->value->getValue());
1922 assert(dynamic_cast<osg::TexMat*>(sa));
1923 osg::TexMat* texMat = static_cast<osg::TexMat*>(sa);
1924 texMat->getMatrix().makeIdentity();
1925 TransformList::const_iterator i;
1926 for (i = _transforms.begin(); i != _transforms.end(); ++i)
1927 i->transform->transform(texMat->getMatrix());
1929 void appendTransform(Transform* transform, SGDoubleValue* value)
1931 Entry entry = { transform, value };
1932 transform->transform(_matrix);
1933 _transforms.push_back(entry);
1938 SGSharedPtr<Transform> transform;
1939 SGSharedPtr<const SGDoubleValue> value;
1941 typedef std::vector<Entry> TransformList;
1942 TransformList _transforms;
1943 SGSharedPtr<const SGCondition> _condition;
1944 osg::Matrix _matrix;
1947 SGTexTransformAnimation::SGTexTransformAnimation(const SGPropertyNode* configNode,
1948 SGPropertyNode* modelRoot) :
1949 SGAnimation(configNode, modelRoot)
1954 SGTexTransformAnimation::createAnimationGroup(osg::Group& parent)
1956 osg::Group* group = new osg::Group;
1957 group->setName("texture transform group");
1958 osg::StateSet* stateSet = group->getOrCreateStateSet();
1959 osg::TexMat* texMat = new osg::TexMat;
1960 UpdateCallback* updateCallback = new UpdateCallback(getCondition());
1961 // interpret the configs ...
1962 std::string type = getType();
1964 if (type == "textranslate") {
1965 appendTexTranslate(getConfig(), updateCallback);
1966 } else if (type == "texrotate") {
1967 appendTexRotate(getConfig(), updateCallback);
1968 } else if (type == "texmultiple") {
1969 std::vector<SGSharedPtr<SGPropertyNode> > transformConfigs;
1970 transformConfigs = getConfig()->getChildren("transform");
1971 for (unsigned i = 0; i < transformConfigs.size(); ++i) {
1972 std::string subtype = transformConfigs[i]->getStringValue("subtype", "");
1973 if (subtype == "textranslate")
1974 appendTexTranslate(transformConfigs[i], updateCallback);
1975 else if (subtype == "texrotate")
1976 appendTexRotate(transformConfigs[i], updateCallback);
1978 SG_LOG(SG_INPUT, SG_ALERT,
1979 "Ignoring unknown texture transform subtype");
1982 SG_LOG(SG_INPUT, SG_ALERT, "Ignoring unknown texture transform type");
1985 texMat->setUpdateCallback(updateCallback);
1986 stateSet->setTextureAttribute(0, texMat);
1987 parent.addChild(group);
1992 SGTexTransformAnimation::appendTexTranslate(const SGPropertyNode* config,
1993 UpdateCallback* updateCallback)
1995 std::string propertyName = config->getStringValue("property", "/null");
1996 SGPropertyNode* inputNode;
1997 inputNode = getModelRoot()->getNode(propertyName.c_str(), true);
1999 SGDoubleValue* animationValue;
2000 SGInterpTable* table = read_interpolation_table(config);
2002 SGTexTableValue* value;
2003 value = new SGTexTableValue(inputNode, table);
2004 value->setStep(config->getDoubleValue("step", 0));
2005 value->setScroll(config->getDoubleValue("scroll", 0));
2006 animationValue = value;
2008 SGTexScaleOffsetValue* value;
2009 value = new SGTexScaleOffsetValue(inputNode);
2010 value->setScale(config->getDoubleValue("factor", 1));
2011 value->setOffset(config->getDoubleValue("offset", 0));
2012 value->setStep(config->getDoubleValue("step", 0));
2013 value->setScroll(config->getDoubleValue("scroll", 0));
2014 value->setMin(config->getDoubleValue("min", -SGLimitsd::max()));
2015 value->setMax(config->getDoubleValue("max", SGLimitsd::max()));
2016 animationValue = value;
2018 SGVec3d axis(config->getDoubleValue("axis/x", 0),
2019 config->getDoubleValue("axis/y", 0),
2020 config->getDoubleValue("axis/z", 0));
2021 Translation* translation;
2022 translation = new Translation(normalize(axis));
2023 translation->setValue(config->getDoubleValue("starting-position", 0));
2024 updateCallback->appendTransform(translation, animationValue);
2028 SGTexTransformAnimation::appendTexRotate(const SGPropertyNode* config,
2029 UpdateCallback* updateCallback)
2031 std::string propertyName = config->getStringValue("property", "/null");
2032 SGPropertyNode* inputNode;
2033 inputNode = getModelRoot()->getNode(propertyName.c_str(), true);
2035 SGDoubleValue* animationValue;
2036 SGInterpTable* table = read_interpolation_table(config);
2038 SGTexTableValue* value;
2039 value = new SGTexTableValue(inputNode, table);
2040 value->setStep(config->getDoubleValue("step", 0));
2041 value->setScroll(config->getDoubleValue("scroll", 0));
2042 animationValue = value;
2044 SGTexScaleOffsetValue* value;
2045 value = new SGTexScaleOffsetValue(inputNode);
2046 value->setScale(config->getDoubleValue("factor", 1));
2047 value->setOffset(config->getDoubleValue("offset-deg", 0));
2048 value->setStep(config->getDoubleValue("step", 0));
2049 value->setScroll(config->getDoubleValue("scroll", 0));
2050 value->setMin(config->getDoubleValue("min-deg", -SGLimitsd::max()));
2051 value->setMax(config->getDoubleValue("max-deg", SGLimitsd::max()));
2052 animationValue = value;
2054 SGVec3d axis(config->getDoubleValue("axis/x", 0),
2055 config->getDoubleValue("axis/y", 0),
2056 config->getDoubleValue("axis/z", 0));
2057 SGVec3d center(config->getDoubleValue("center/x", 0),
2058 config->getDoubleValue("center/y", 0),
2059 config->getDoubleValue("center/z", 0));
2061 rotation = new Rotation(normalize(axis), center);
2062 rotation->setValue(config->getDoubleValue("starting-position-deg", 0));
2063 updateCallback->appendTransform(rotation, animationValue);