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/PolygonMode>
19 #include <osg/PolygonOffset>
20 #include <osg/StateSet>
23 #include <osg/Texture2D>
24 #include <osg/Transform>
25 #include <osgDB/ReadFile>
27 #include <simgear/math/interpolater.hxx>
28 #include <simgear/props/condition.hxx>
29 #include <simgear/props/props.hxx>
30 #include <simgear/structure/SGBinding.hxx>
31 #include <simgear/scene/util/SGNodeMasks.hxx>
32 #include <simgear/scene/util/SGSceneUserData.hxx>
33 #include <simgear/scene/util/SGStateAttributeVisitor.hxx>
35 #include "animation.hxx"
38 #include "SGMaterialAnimation.hxx"
41 ////////////////////////////////////////////////////////////////////////
42 // Static utility functions.
43 ////////////////////////////////////////////////////////////////////////
46 * Set up the transform matrix for a spin or rotation.
49 set_rotation (osg::Matrix &matrix, double position_deg,
50 const SGVec3d ¢er, const SGVec3d &axis)
52 double temp_angle = -SGMiscd::deg2rad(position_deg);
54 double s = sin(temp_angle);
55 double c = cos(temp_angle);
58 // axis was normalized at load time
59 // hint to the compiler to put these into FP registers
64 matrix(0, 0) = t * x * x + c ;
65 matrix(0, 1) = t * y * x - s * z ;
66 matrix(0, 2) = t * z * x + s * y ;
69 matrix(1, 0) = t * x * y + s * z ;
70 matrix(1, 1) = t * y * y + c ;
71 matrix(1, 2) = t * z * y - s * x ;
74 matrix(2, 0) = t * x * z - s * y ;
75 matrix(2, 1) = t * y * z + s * x ;
76 matrix(2, 2) = t * z * z + c ;
79 // hint to the compiler to put these into FP registers
84 matrix(3, 0) = x - x*matrix(0, 0) - y*matrix(1, 0) - z*matrix(2, 0);
85 matrix(3, 1) = y - x*matrix(0, 1) - y*matrix(1, 1) - z*matrix(2, 1);
86 matrix(3, 2) = z - x*matrix(0, 2) - y*matrix(1, 2) - z*matrix(2, 2);
91 * Set up the transform matrix for a translation.
94 set_translation (osg::Matrix &matrix, double position_m, const SGVec3d &axis)
96 SGVec3d xyz = axis * position_m;
97 matrix.makeIdentity();
98 matrix(3, 0) = xyz[0];
99 matrix(3, 1) = xyz[1];
100 matrix(3, 2) = xyz[2];
104 * Modify property value by step and scroll settings in texture translations
107 apply_mods(double property, double step, double scroll)
112 double scrollval = 0.0;
114 // calculate scroll amount (for odometer like movement)
115 double remainder = step - fmod(fabs(property), step);
116 if (remainder < scroll) {
117 scrollval = (scroll - remainder) / scroll * step;
120 // apply stepping of input value
122 modprop = ((floor(property/step) * step) + scrollval);
124 modprop = ((ceil(property/step) * step) + scrollval);
133 * Read an interpolation table from properties.
135 static SGInterpTable *
136 read_interpolation_table(const SGPropertyNode* props)
138 const SGPropertyNode* table_node = props->getNode("interpolation");
141 return new SGInterpTable(table_node);
144 ////////////////////////////////////////////////////////////////////////
145 // Utility value classes
146 ////////////////////////////////////////////////////////////////////////
147 class SGScaleOffsetValue : public SGDoubleValue {
149 SGScaleOffsetValue(SGPropertyNode const* propertyNode) :
150 _propertyNode(propertyNode),
153 _min(-SGLimitsd::max()),
154 _max(SGLimitsd::max())
156 void setScale(double scale)
158 void setOffset(double offset)
159 { _offset = offset; }
160 void setMin(double min)
162 void setMax(double max)
165 virtual double getValue() const
167 double value = _propertyNode ? _propertyNode->getDoubleValue() : 0;
168 return std::min(_max, std::max(_min, _offset + _scale*value));
171 SGSharedPtr<SGPropertyNode const> _propertyNode;
178 class SGPersScaleOffsetValue : public SGDoubleValue {
180 SGPersScaleOffsetValue(SGPropertyNode const* propertyNode,
181 SGPropertyNode const* config,
182 const char* scalename, const char* offsetname,
183 double defScale = 1, double defOffset = 0) :
184 _propertyNode(propertyNode),
185 _scale(config, scalename, defScale),
186 _offset(config, offsetname, defOffset),
187 _min(-SGLimitsd::max()),
188 _max(SGLimitsd::max())
190 void setScale(double scale)
192 void setOffset(double offset)
193 { _offset = offset; }
194 void setMin(double min)
196 void setMax(double max)
199 virtual double getValue() const
203 double value = _propertyNode ? _propertyNode->getDoubleValue() : 0;
204 return SGMiscd::clip(_offset + _scale*value, _min, _max);
207 SGSharedPtr<SGPropertyNode const> _propertyNode;
208 mutable SGPersonalityParameter<double> _scale;
209 mutable SGPersonalityParameter<double> _offset;
214 class SGInterpTableValue : public SGDoubleValue {
216 SGInterpTableValue(SGPropertyNode const* propertyNode,
217 SGInterpTable const* interpTable) :
218 _propertyNode(propertyNode),
219 _interpTable(interpTable)
221 virtual double getValue() const
222 { return _interpTable->interpolate(_propertyNode->getDoubleValue()); }
224 SGSharedPtr<SGPropertyNode const> _propertyNode;
225 SGSharedPtr<SGInterpTable const> _interpTable;
228 class SGTexScaleOffsetValue : public SGDoubleValue {
230 SGTexScaleOffsetValue(const SGPropertyNode* propertyNode) :
231 _propertyNode(propertyNode),
236 _min(-SGLimitsd::max()),
237 _max(SGLimitsd::max())
239 void setScale(double scale)
241 void setOffset(double offset)
242 { _offset = offset; }
243 void setStep(double step)
245 void setScroll(double scroll)
246 { _scroll = scroll; }
247 void setMin(double min)
249 void setMax(double max)
252 virtual double getValue() const
254 double value = _propertyNode ? _propertyNode->getDoubleValue() : 0;
255 value = apply_mods(value, _step, _scroll);
256 return SGMiscd::clip(_scale*(_offset + value), _min, _max);
259 SGSharedPtr<const SGPropertyNode> _propertyNode;
268 class SGTexTableValue : public SGDoubleValue {
270 SGTexTableValue(const SGPropertyNode* propertyNode,
271 const SGInterpTable* interpTable) :
272 _propertyNode(propertyNode),
273 _interpTable(interpTable)
275 void setStep(double step)
277 void setScroll(double scroll)
278 { _scroll = scroll; }
279 virtual double getValue() const
281 double value = _propertyNode ? _propertyNode->getDoubleValue() : 0;
282 value = apply_mods(value, _step, _scroll);
283 return _interpTable->interpolate(value);
286 SGSharedPtr<SGPropertyNode const> _propertyNode;
287 SGSharedPtr<SGInterpTable const> _interpTable;
293 unit_string(const char* value, const char* unit)
295 return std::string(value) + unit;
298 static SGDoubleValue*
299 read_value(const SGPropertyNode* configNode, SGPropertyNode* modelRoot,
300 const char* unit, double defMin, double defMax)
302 std::string inputPropertyName;
303 inputPropertyName = configNode->getStringValue("property", "");
304 if (!inputPropertyName.empty()) {
305 SGPropertyNode* inputProperty;
306 inputProperty = modelRoot->getNode(inputPropertyName.c_str(), true);
307 SGInterpTable* interpTable = read_interpolation_table(configNode);
309 SGInterpTableValue* value;
310 value = new SGInterpTableValue(inputProperty, interpTable);
313 std::string offset = unit_string("offset", unit);
314 std::string min = unit_string("min", unit);
315 std::string max = unit_string("max", unit);
317 if (configNode->getBoolValue("use-personality", false)) {
318 SGPersScaleOffsetValue* value;
319 value = new SGPersScaleOffsetValue(inputProperty, configNode,
320 "factor", offset.c_str());
321 value->setMin(configNode->getDoubleValue(min.c_str(), defMin));
322 value->setMax(configNode->getDoubleValue(max.c_str(), defMax));
325 SGScaleOffsetValue* value = new SGScaleOffsetValue(inputProperty);
326 value->setScale(configNode->getDoubleValue("factor", 1));
327 value->setOffset(configNode->getDoubleValue(offset.c_str(), 0));
328 value->setMin(configNode->getDoubleValue(min.c_str(), defMin));
329 value->setMax(configNode->getDoubleValue(max.c_str(), defMax));
338 ////////////////////////////////////////////////////////////////////////
339 // Animation installer
340 ////////////////////////////////////////////////////////////////////////
342 class SGAnimation::RemoveModeVisitor : public SGStateAttributeVisitor {
344 RemoveModeVisitor(osg::StateAttribute::GLMode mode) :
347 virtual void apply(osg::StateSet* stateSet)
351 stateSet->removeMode(_mode);
354 osg::StateAttribute::GLMode _mode;
357 class SGAnimation::RemoveAttributeVisitor : public SGStateAttributeVisitor {
359 RemoveAttributeVisitor(osg::StateAttribute::Type type) :
362 virtual void apply(osg::StateSet* stateSet)
366 while (stateSet->getAttribute(_type)) {
367 stateSet->removeAttribute(_type);
371 osg::StateAttribute::Type _type;
374 class SGAnimation::RemoveTextureModeVisitor : public SGStateAttributeVisitor {
376 RemoveTextureModeVisitor(unsigned unit, osg::StateAttribute::GLMode mode) :
380 virtual void apply(osg::StateSet* stateSet)
384 stateSet->removeTextureMode(_unit, _mode);
388 osg::StateAttribute::GLMode _mode;
391 class SGAnimation::RemoveTextureAttributeVisitor :
392 public SGStateAttributeVisitor {
394 RemoveTextureAttributeVisitor(unsigned unit,
395 osg::StateAttribute::Type type) :
399 virtual void apply(osg::StateSet* stateSet)
403 while (stateSet->getTextureAttribute(_unit, _type)) {
404 stateSet->removeTextureAttribute(_unit, _type);
409 osg::StateAttribute::Type _type;
412 class SGAnimation::BinToInheritVisitor : public SGStateAttributeVisitor {
414 virtual void apply(osg::StateSet* stateSet)
418 stateSet->setRenderBinToInherit();
422 class SGAnimation::DrawableCloneVisitor : public osg::NodeVisitor {
424 DrawableCloneVisitor() :
425 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
427 void apply(osg::Geode& geode)
429 for (unsigned i = 0 ; i < geode.getNumDrawables(); ++i) {
430 osg::CopyOp copyOp(osg::CopyOp::DEEP_COPY_ALL &
431 ~osg::CopyOp::DEEP_COPY_TEXTURES);
432 geode.setDrawable(i, copyOp(geode.getDrawable(i)));
438 SGAnimation::SGAnimation(const SGPropertyNode* configNode,
439 SGPropertyNode* modelRoot) :
440 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
442 _configNode(configNode),
443 _modelRoot(modelRoot)
445 _name = configNode->getStringValue("name", "");
446 _enableHOT = configNode->getBoolValue("enable-hot", true);
447 _disableShadow = configNode->getBoolValue("disable-shadow", false);
448 std::vector<SGPropertyNode_ptr> objectNames =
449 configNode->getChildren("object-name");
450 for (unsigned i = 0; i < objectNames.size(); ++i)
451 _objectNames.push_back(objectNames[i]->getStringValue());
454 SGAnimation::~SGAnimation()
459 SG_LOG(SG_IO, SG_ALERT, "Could not find at least one of the following"
460 " objects for animation:\n");
461 std::list<std::string>::const_iterator i;
462 for (i = _objectNames.begin(); i != _objectNames.end(); ++i)
463 SG_LOG(SG_IO, SG_ALERT, *i << "\n");
467 SGAnimation::animate(osg::Node* node, const SGPropertyNode* configNode,
468 SGPropertyNode* modelRoot)
470 std::string type = configNode->getStringValue("type", "none");
471 if (type == "alpha-test") {
472 SGAlphaTestAnimation animInst(configNode, modelRoot);
473 animInst.apply(node);
474 } else if (type == "billboard") {
475 SGBillboardAnimation animInst(configNode, modelRoot);
476 animInst.apply(node);
477 } else if (type == "blend") {
478 SGBlendAnimation animInst(configNode, modelRoot);
479 animInst.apply(node);
480 } else if (type == "dist-scale") {
481 SGDistScaleAnimation animInst(configNode, modelRoot);
482 animInst.apply(node);
483 } else if (type == "flash") {
484 SGFlashAnimation animInst(configNode, modelRoot);
485 animInst.apply(node);
486 } else if (type == "material") {
487 SGMaterialAnimation animInst(configNode, modelRoot);
488 animInst.apply(node);
489 } else if (type == "noshadow") {
490 SGShadowAnimation animInst(configNode, modelRoot);
491 animInst.apply(node);
492 } else if (type == "pick") {
493 SGPickAnimation animInst(configNode, modelRoot);
494 animInst.apply(node);
495 } else if (type == "range") {
496 SGRangeAnimation animInst(configNode, modelRoot);
497 animInst.apply(node);
498 } else if (type == "rotate" || type == "spin") {
499 SGRotateAnimation animInst(configNode, modelRoot);
500 animInst.apply(node);
501 } else if (type == "scale") {
502 SGScaleAnimation animInst(configNode, modelRoot);
503 animInst.apply(node);
504 } else if (type == "select") {
505 SGSelectAnimation animInst(configNode, modelRoot);
506 animInst.apply(node);
507 } else if (type == "shader") {
508 SGShaderAnimation animInst(configNode, modelRoot);
509 animInst.apply(node);
510 } else if (type == "textranslate" || type == "texrotate" ||
511 type == "texmultiple") {
512 SGTexTransformAnimation animInst(configNode, modelRoot);
513 animInst.apply(node);
514 } else if (type == "timed") {
515 SGTimedAnimation animInst(configNode, modelRoot);
516 animInst.apply(node);
517 } else if (type == "translate") {
518 SGTranslateAnimation animInst(configNode, modelRoot);
519 animInst.apply(node);
520 } else if (type == "null" || type == "none" || type.empty()) {
521 SGGroupAnimation animInst(configNode, modelRoot);
522 animInst.apply(node);
531 SGAnimation::apply(osg::Node* node)
533 // duh what a special case ...
534 if (_objectNames.empty()) {
535 osg::Group* group = node->asGroup();
537 osg::ref_ptr<osg::Group> animationGroup;
538 installInGroup(std::string(), *group, animationGroup);
545 SGAnimation::install(osg::Node& node)
549 node.setNodeMask( SG_NODEMASK_TERRAIN_BIT | node.getNodeMask());
551 node.setNodeMask(~SG_NODEMASK_TERRAIN_BIT & node.getNodeMask());
553 node.setNodeMask( SG_NODEMASK_SHADOW_BIT | node.getNodeMask());
555 node.setNodeMask(~SG_NODEMASK_SHADOW_BIT & node.getNodeMask());
559 SGAnimation::createAnimationGroup(osg::Group& parent)
561 // default implementation, we do not need a new group
562 // for every animation type. Usually animations that just change
563 // the StateSet of some parts of the model
568 SGAnimation::apply(osg::Group& group)
570 // the trick is to first traverse the children and then
571 // possibly splice in a new group node if required.
572 // Else we end up in a recursive loop where we infinitly insert new
576 // Note that this algorithm preserves the order of the child objects
577 // like they appear in the object-name tags.
578 // The timed animations require this
579 osg::ref_ptr<osg::Group> animationGroup;
580 std::list<std::string>::const_iterator nameIt;
581 for (nameIt = _objectNames.begin(); nameIt != _objectNames.end(); ++nameIt)
582 installInGroup(*nameIt, group, animationGroup);
586 SGAnimation::installInGroup(const std::string& name, osg::Group& group,
587 osg::ref_ptr<osg::Group>& animationGroup)
589 int i = group.getNumChildren() - 1;
590 for (; 0 <= i; --i) {
591 osg::Node* child = group.getChild(i);
593 // Check if this one is already processed
594 if (std::find(_installedAnimations.begin(),
595 _installedAnimations.end(), child)
596 != _installedAnimations.end())
599 if (name.empty() || child->getName() == name) {
600 // fire the installation of the animation
603 // create a group node on demand
604 if (!animationGroup.valid()) {
605 animationGroup = createAnimationGroup(group);
606 // Animation type that does not require a new group,
607 // in this case we can stop and look for the next object
608 if (animationGroup.valid() && !_name.empty())
609 animationGroup->setName(_name);
611 if (animationGroup.valid()) {
612 animationGroup->addChild(child);
613 group.removeChild(i);
616 // store that we already have processed this child node
617 // We can hit this one twice if an animation references some
618 // part of a subtree twice
619 _installedAnimations.push_back(child);
625 SGAnimation::removeMode(osg::Node& node, osg::StateAttribute::GLMode mode)
627 RemoveModeVisitor visitor(mode);
628 node.accept(visitor);
632 SGAnimation::removeAttribute(osg::Node& node, osg::StateAttribute::Type type)
634 RemoveAttributeVisitor visitor(type);
635 node.accept(visitor);
639 SGAnimation::removeTextureMode(osg::Node& node, unsigned unit,
640 osg::StateAttribute::GLMode mode)
642 RemoveTextureModeVisitor visitor(unit, mode);
643 node.accept(visitor);
647 SGAnimation::removeTextureAttribute(osg::Node& node, unsigned unit,
648 osg::StateAttribute::Type type)
650 RemoveTextureAttributeVisitor visitor(unit, type);
651 node.accept(visitor);
655 SGAnimation::setRenderBinToInherit(osg::Node& node)
657 BinToInheritVisitor visitor;
658 node.accept(visitor);
662 SGAnimation::cloneDrawables(osg::Node& node)
664 DrawableCloneVisitor visitor;
665 node.accept(visitor);
669 SGAnimation::getCondition() const
671 const SGPropertyNode* conditionNode = _configNode->getChild("condition");
674 return sgReadCondition(_modelRoot, conditionNode);
679 ////////////////////////////////////////////////////////////////////////
680 // Implementation of null animation
681 ////////////////////////////////////////////////////////////////////////
683 // Ok, that is to build a subgraph from different other
684 // graph nodes. I guess that this stems from the time where modellers
685 // could not build hierarchical trees ...
686 SGGroupAnimation::SGGroupAnimation(const SGPropertyNode* configNode,
687 SGPropertyNode* modelRoot):
688 SGAnimation(configNode, modelRoot)
693 SGGroupAnimation::createAnimationGroup(osg::Group& parent)
695 osg::Group* group = new osg::Group;
696 parent.addChild(group);
701 ////////////////////////////////////////////////////////////////////////
702 // Implementation of translate animation
703 ////////////////////////////////////////////////////////////////////////
705 class SGTranslateAnimation::Transform : public osg::Transform {
710 { setReferenceFrame(RELATIVE_RF); }
711 void setAxis(const SGVec3d& axis)
712 { _axis = axis; dirtyBound(); }
713 void setValue(double value)
714 { _value = value; dirtyBound(); }
715 virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
716 osg::NodeVisitor* nv) const
718 assert(_referenceFrame == RELATIVE_RF);
720 set_translation(tmp, _value, _axis);
724 virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
725 osg::NodeVisitor* nv) const
727 assert(_referenceFrame == RELATIVE_RF);
729 set_translation(tmp, -_value, _axis);
730 matrix.postMult(tmp);
738 class SGTranslateAnimation::UpdateCallback : public osg::NodeCallback {
740 UpdateCallback(SGCondition const* condition,
741 SGDoubleValue const* animationValue) :
742 _condition(condition),
743 _animationValue(animationValue)
745 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
747 if (!_condition || _condition->test()) {
748 SGTranslateAnimation::Transform* transform;
749 transform = static_cast<SGTranslateAnimation::Transform*>(node);
750 transform->setValue(_animationValue->getValue());
755 SGSharedPtr<SGCondition const> _condition;
756 SGSharedPtr<SGDoubleValue const> _animationValue;
759 SGTranslateAnimation::SGTranslateAnimation(const SGPropertyNode* configNode,
760 SGPropertyNode* modelRoot) :
761 SGAnimation(configNode, modelRoot)
763 _condition = getCondition();
764 _animationValue = read_value(configNode, modelRoot, "-m",
765 -SGLimitsd::max(), SGLimitsd::max());
766 _axis[0] = configNode->getDoubleValue("axis/x", 0);
767 _axis[1] = configNode->getDoubleValue("axis/y", 0);
768 _axis[2] = configNode->getDoubleValue("axis/z", 0);
769 if (8*SGLimitsd::min() < norm(_axis))
770 _axis = normalize(_axis);
772 _initialValue = configNode->getDoubleValue("starting-position-m", 0);
773 _initialValue *= configNode->getDoubleValue("factor", 1);
774 _initialValue += configNode->getDoubleValue("offset-m", 0);
778 SGTranslateAnimation::createAnimationGroup(osg::Group& parent)
780 Transform* transform = new Transform;
781 transform->setName("translate animation");
782 if (_animationValue) {
783 UpdateCallback* uc = new UpdateCallback(_condition, _animationValue);
784 transform->setUpdateCallback(uc);
786 transform->setAxis(_axis);
787 transform->setValue(_initialValue);
788 parent.addChild(transform);
793 ////////////////////////////////////////////////////////////////////////
794 // Implementation of rotate/spin animation
795 ////////////////////////////////////////////////////////////////////////
797 class SGRotateAnimation::Transform : public osg::Transform {
800 { setReferenceFrame(RELATIVE_RF); }
801 void setCenter(const SGVec3d& center)
802 { _center = center; dirtyBound(); }
803 void setAxis(const SGVec3d& axis)
804 { _axis = axis; dirtyBound(); }
805 void setAngle(double angle)
807 double getAngle() const
809 virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
810 osg::NodeVisitor* nv) const
812 // This is the fast path, optimize a bit
813 assert(_referenceFrame == RELATIVE_RF);
816 set_rotation(tmp, _angle, _center, _axis);
820 virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
821 osg::NodeVisitor* nv) const
823 assert(_referenceFrame == RELATIVE_RF);
826 set_rotation(tmp, -_angle, _center, _axis);
827 matrix.postMult(tmp);
830 virtual osg::BoundingSphere computeBound() const
832 osg::BoundingSphere bs = osg::Group::computeBound();
833 osg::BoundingSphere centerbs(_center.osg(), bs.radius());
834 centerbs.expandBy(bs);
844 class SGRotateAnimation::UpdateCallback : public osg::NodeCallback {
846 UpdateCallback(SGCondition const* condition,
847 SGDoubleValue const* animationValue) :
848 _condition(condition),
849 _animationValue(animationValue)
851 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
853 if (!_condition || _condition->test()) {
854 SGRotateAnimation::Transform* transform;
855 transform = static_cast<SGRotateAnimation::Transform*>(node);
856 transform->setAngle(_animationValue->getValue());
861 SGSharedPtr<SGCondition const> _condition;
862 SGSharedPtr<SGDoubleValue const> _animationValue;
865 class SGRotateAnimation::SpinUpdateCallback : public osg::NodeCallback {
867 SpinUpdateCallback(SGCondition const* condition,
868 SGDoubleValue const* animationValue) :
869 _condition(condition),
870 _animationValue(animationValue),
873 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
875 if (!_condition || _condition->test()) {
876 SGRotateAnimation::Transform* transform;
877 transform = static_cast<SGRotateAnimation::Transform*>(node);
879 double t = nv->getFrameStamp()->getReferenceTime();
884 double velocity_rpms = _animationValue->getValue()/60;
885 double angle = transform->getAngle();
886 angle += dt*velocity_rpms*360;
887 angle -= 360*floor(angle/360);
888 transform->setAngle(angle);
893 SGSharedPtr<SGCondition const> _condition;
894 SGSharedPtr<SGDoubleValue const> _animationValue;
898 SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode, SGPropertyNode* modelRoot) :
899 SGAnimation(configNode, modelRoot)
901 std::string type = configNode->getStringValue("type", "");
902 _isSpin = (type == "spin");
904 _condition = getCondition();
905 _animationValue = read_value(configNode, modelRoot, "-deg",
906 -SGLimitsd::max(), SGLimitsd::max());
907 _initialValue = configNode->getDoubleValue("starting-position-deg", 0);
908 _initialValue *= configNode->getDoubleValue("factor", 1);
909 _initialValue += configNode->getDoubleValue("offset-deg", 0);
911 _center = SGVec3d::zeros();
912 if (configNode->hasValue("axis/x1-m")) {
914 v1[0] = configNode->getDoubleValue("axis/x1-m", 0);
915 v1[1] = configNode->getDoubleValue("axis/y1-m", 0);
916 v1[2] = configNode->getDoubleValue("axis/z1-m", 0);
917 v2[0] = configNode->getDoubleValue("axis/x2-m", 0);
918 v2[1] = configNode->getDoubleValue("axis/y2-m", 0);
919 v2[2] = configNode->getDoubleValue("axis/z2-m", 0);
920 _center = 0.5*(v1+v2);
923 _axis[0] = configNode->getDoubleValue("axis/x", 0);
924 _axis[1] = configNode->getDoubleValue("axis/y", 0);
925 _axis[2] = configNode->getDoubleValue("axis/z", 0);
927 if (8*SGLimitsd::min() < norm(_axis))
928 _axis = normalize(_axis);
930 _center[0] = configNode->getDoubleValue("center/x-m", _center[0]);
931 _center[1] = configNode->getDoubleValue("center/y-m", _center[1]);
932 _center[2] = configNode->getDoubleValue("center/z-m", _center[2]);
936 SGRotateAnimation::createAnimationGroup(osg::Group& parent)
938 Transform* transform = new Transform;
939 transform->setName("rotate animation");
941 SpinUpdateCallback* uc;
942 uc = new SpinUpdateCallback(_condition, _animationValue);
943 transform->setUpdateCallback(uc);
944 } else if (_animationValue) {
945 UpdateCallback* uc = new UpdateCallback(_condition, _animationValue);
946 transform->setUpdateCallback(uc);
948 transform->setCenter(_center);
949 transform->setAxis(_axis);
950 transform->setAngle(_initialValue);
951 parent.addChild(transform);
956 ////////////////////////////////////////////////////////////////////////
957 // Implementation of scale animation
958 ////////////////////////////////////////////////////////////////////////
960 class SGScaleAnimation::Transform : public osg::Transform {
964 _scaleFactor(1, 1, 1),
967 setReferenceFrame(RELATIVE_RF);
969 void setCenter(const SGVec3d& center)
974 void setScaleFactor(const SGVec3d& scaleFactor)
976 if (_boundScale < normI(scaleFactor))
978 _scaleFactor = scaleFactor;
980 void setScaleFactor(double scaleFactor)
982 if (_boundScale < fabs(scaleFactor))
984 _scaleFactor = SGVec3d(scaleFactor, scaleFactor, scaleFactor);
986 virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
987 osg::NodeVisitor* nv) const
989 assert(_referenceFrame == RELATIVE_RF);
990 osg::Matrix transform;
991 transform(0,0) = _scaleFactor[0];
992 transform(1,1) = _scaleFactor[1];
993 transform(2,2) = _scaleFactor[2];
994 transform(3,0) = _center[0]*(1 - _scaleFactor[0]);
995 transform(3,1) = _center[1]*(1 - _scaleFactor[1]);
996 transform(3,2) = _center[2]*(1 - _scaleFactor[2]);
997 matrix.preMult(transform);
1000 virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
1001 osg::NodeVisitor* nv) const
1003 assert(_referenceFrame == RELATIVE_RF);
1004 if (fabs(_scaleFactor[0]) < SGLimitsd::min())
1006 if (fabs(_scaleFactor[1]) < SGLimitsd::min())
1008 if (fabs(_scaleFactor[2]) < SGLimitsd::min())
1010 SGVec3d rScaleFactor(1/_scaleFactor[0],
1013 osg::Matrix transform;
1014 transform(0,0) = rScaleFactor[0];
1015 transform(1,1) = rScaleFactor[1];
1016 transform(2,2) = rScaleFactor[2];
1017 transform(3,0) = _center[0]*(1 - rScaleFactor[0]);
1018 transform(3,1) = _center[1]*(1 - rScaleFactor[1]);
1019 transform(3,2) = _center[2]*(1 - rScaleFactor[2]);
1020 matrix.postMult(transform);
1023 virtual osg::BoundingSphere computeBound() const
1025 osg::BoundingSphere bs = osg::Group::computeBound();
1026 _boundScale = normI(_scaleFactor);
1027 bs.radius() *= _boundScale;
1033 SGVec3d _scaleFactor;
1034 mutable double _boundScale;
1037 class SGScaleAnimation::UpdateCallback : public osg::NodeCallback {
1039 UpdateCallback(const SGCondition* condition,
1040 SGSharedPtr<const SGDoubleValue> animationValue[3]) :
1041 _condition(condition)
1043 _animationValue[0] = animationValue[0];
1044 _animationValue[1] = animationValue[1];
1045 _animationValue[2] = animationValue[2];
1047 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
1049 if (!_condition || _condition->test()) {
1050 SGScaleAnimation::Transform* transform;
1051 transform = static_cast<SGScaleAnimation::Transform*>(node);
1052 SGVec3d scale(_animationValue[0]->getValue(),
1053 _animationValue[1]->getValue(),
1054 _animationValue[2]->getValue());
1055 transform->setScaleFactor(scale);
1060 SGSharedPtr<SGCondition const> _condition;
1061 SGSharedPtr<SGDoubleValue const> _animationValue[3];
1064 SGScaleAnimation::SGScaleAnimation(const SGPropertyNode* configNode,
1065 SGPropertyNode* modelRoot) :
1066 SGAnimation(configNode, modelRoot)
1068 _condition = getCondition();
1070 // default offset/factor for all directions
1071 double offset = configNode->getDoubleValue("offset", 1);
1072 double factor = configNode->getDoubleValue("factor", 1);
1074 std::string inputPropertyName;
1075 inputPropertyName = configNode->getStringValue("property", "");
1076 if (!inputPropertyName.empty()) {
1077 SGPropertyNode* inputProperty;
1078 inputProperty = modelRoot->getNode(inputPropertyName.c_str(), true);
1079 SGInterpTable* interpTable = read_interpolation_table(configNode);
1081 SGInterpTableValue* value;
1082 value = new SGInterpTableValue(inputProperty, interpTable);
1083 _animationValue[0] = value;
1084 _animationValue[1] = value;
1085 _animationValue[2] = value;
1086 } else if (configNode->getBoolValue("use-personality", false)) {
1087 SGPersScaleOffsetValue* value;
1088 value = new SGPersScaleOffsetValue(inputProperty, configNode,
1089 "x-factor", "x-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 SGPersScaleOffsetValue(inputProperty, configNode,
1095 "y-factor", "y-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 SGPersScaleOffsetValue(inputProperty, configNode,
1101 "z-factor", "z-offset",
1103 value->setMin(configNode->getDoubleValue("z-min", 0));
1104 value->setMax(configNode->getDoubleValue("z-max", SGLimitsd::max()));
1105 _animationValue[2] = value;
1107 SGScaleOffsetValue* value = new SGScaleOffsetValue(inputProperty);
1108 value->setScale(configNode->getDoubleValue("x-factor", factor));
1109 value->setOffset(configNode->getDoubleValue("x-offset", offset));
1110 value->setMin(configNode->getDoubleValue("x-min", 0));
1111 value->setMax(configNode->getDoubleValue("x-max", SGLimitsd::max()));
1112 _animationValue[0] = value;
1113 value = new SGScaleOffsetValue(inputProperty);
1114 value->setScale(configNode->getDoubleValue("y-factor", factor));
1115 value->setOffset(configNode->getDoubleValue("y-offset", offset));
1116 value->setMin(configNode->getDoubleValue("y-min", 0));
1117 value->setMax(configNode->getDoubleValue("y-max", SGLimitsd::max()));
1118 _animationValue[1] = value;
1119 value = new SGScaleOffsetValue(inputProperty);
1120 value->setScale(configNode->getDoubleValue("z-factor", factor));
1121 value->setOffset(configNode->getDoubleValue("z-offset", offset));
1122 value->setMin(configNode->getDoubleValue("z-min", 0));
1123 value->setMax(configNode->getDoubleValue("z-max", SGLimitsd::max()));
1124 _animationValue[2] = value;
1127 _initialValue[0] = configNode->getDoubleValue("x-starting-scale", 1);
1128 _initialValue[0] *= configNode->getDoubleValue("x-factor", factor);
1129 _initialValue[0] += configNode->getDoubleValue("x-offset", offset);
1130 _initialValue[1] = configNode->getDoubleValue("y-starting-scale", 1);
1131 _initialValue[1] *= configNode->getDoubleValue("y-factor", factor);
1132 _initialValue[1] += configNode->getDoubleValue("y-offset", offset);
1133 _initialValue[2] = configNode->getDoubleValue("z-starting-scale", 1);
1134 _initialValue[2] *= configNode->getDoubleValue("z-factor", factor);
1135 _initialValue[2] += configNode->getDoubleValue("z-offset", offset);
1136 _center[0] = configNode->getDoubleValue("center/x-m", 0);
1137 _center[1] = configNode->getDoubleValue("center/y-m", 0);
1138 _center[2] = configNode->getDoubleValue("center/z-m", 0);
1142 SGScaleAnimation::createAnimationGroup(osg::Group& parent)
1144 Transform* transform = new Transform;
1145 transform->setName("scale animation");
1146 transform->setCenter(_center);
1147 transform->setScaleFactor(_initialValue);
1148 UpdateCallback* uc = new UpdateCallback(_condition, _animationValue);
1149 transform->setUpdateCallback(uc);
1150 parent.addChild(transform);
1155 ////////////////////////////////////////////////////////////////////////
1156 // Implementation of dist scale animation
1157 ////////////////////////////////////////////////////////////////////////
1159 class SGDistScaleAnimation::Transform : public osg::Transform {
1161 Transform(const SGPropertyNode* configNode)
1163 setName(configNode->getStringValue("name", "dist scale animation"));
1164 setReferenceFrame(RELATIVE_RF);
1165 getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
1166 _factor = configNode->getFloatValue("factor", 1);
1167 _offset = configNode->getFloatValue("offset", 0);
1168 _min_v = configNode->getFloatValue("min", SGLimitsf::epsilon());
1169 _max_v = configNode->getFloatValue("max", SGLimitsf::max());
1170 _table = read_interpolation_table(configNode);
1171 _center[0] = configNode->getFloatValue("center/x-m", 0);
1172 _center[1] = configNode->getFloatValue("center/y-m", 0);
1173 _center[2] = configNode->getFloatValue("center/z-m", 0);
1175 virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
1176 osg::NodeVisitor* nv) const
1178 osg::Matrix transform;
1179 double scale_factor = computeScaleFactor(nv);
1180 transform(0,0) = scale_factor;
1181 transform(1,1) = scale_factor;
1182 transform(2,2) = scale_factor;
1183 transform(3,0) = _center[0]*(1 - scale_factor);
1184 transform(3,1) = _center[1]*(1 - scale_factor);
1185 transform(3,2) = _center[2]*(1 - scale_factor);
1186 matrix.preMult(transform);
1190 virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
1191 osg::NodeVisitor* nv) const
1193 double scale_factor = computeScaleFactor(nv);
1194 if (fabs(scale_factor) <= SGLimits<double>::min())
1196 osg::Matrix transform;
1197 double rScaleFactor = 1/scale_factor;
1198 transform(0,0) = rScaleFactor;
1199 transform(1,1) = rScaleFactor;
1200 transform(2,2) = rScaleFactor;
1201 transform(3,0) = _center[0]*(1 - rScaleFactor);
1202 transform(3,1) = _center[1]*(1 - rScaleFactor);
1203 transform(3,2) = _center[2]*(1 - rScaleFactor);
1204 matrix.postMult(transform);
1209 double computeScaleFactor(osg::NodeVisitor* nv) const
1214 double scale_factor = (_center.osg() - nv->getEyePoint()).length();
1216 scale_factor = _factor * scale_factor + _offset;
1218 scale_factor = _table->interpolate( scale_factor );
1220 if (scale_factor < _min_v)
1221 scale_factor = _min_v;
1222 if (scale_factor > _max_v)
1223 scale_factor = _max_v;
1225 return scale_factor;
1228 SGSharedPtr<SGInterpTable> _table;
1237 SGDistScaleAnimation::SGDistScaleAnimation(const SGPropertyNode* configNode,
1238 SGPropertyNode* modelRoot) :
1239 SGAnimation(configNode, modelRoot)
1244 SGDistScaleAnimation::createAnimationGroup(osg::Group& parent)
1246 Transform* transform = new Transform(getConfig());
1247 parent.addChild(transform);
1252 ////////////////////////////////////////////////////////////////////////
1253 // Implementation of flash animation
1254 ////////////////////////////////////////////////////////////////////////
1256 class SGFlashAnimation::Transform : public osg::Transform {
1258 Transform(const SGPropertyNode* configNode)
1260 setReferenceFrame(RELATIVE_RF);
1261 setName(configNode->getStringValue("name", "flash animation"));
1262 getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
1264 _axis[0] = configNode->getFloatValue("axis/x", 0);
1265 _axis[1] = configNode->getFloatValue("axis/y", 0);
1266 _axis[2] = configNode->getFloatValue("axis/z", 1);
1269 _center[0] = configNode->getFloatValue("center/x-m", 0);
1270 _center[1] = configNode->getFloatValue("center/y-m", 0);
1271 _center[2] = configNode->getFloatValue("center/z-m", 0);
1273 _offset = configNode->getFloatValue("offset", 0);
1274 _factor = configNode->getFloatValue("factor", 1);
1275 _power = configNode->getFloatValue("power", 1);
1276 _two_sides = configNode->getBoolValue("two-sides", false);
1278 _min_v = configNode->getFloatValue("min", SGLimitsf::epsilon());
1279 _max_v = configNode->getFloatValue("max", 1);
1281 virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
1282 osg::NodeVisitor* nv) const
1284 osg::Matrix transform;
1285 double scale_factor = computeScaleFactor(nv);
1286 transform(0,0) = scale_factor;
1287 transform(1,1) = scale_factor;
1288 transform(2,2) = scale_factor;
1289 transform(3,0) = _center[0]*(1 - scale_factor);
1290 transform(3,1) = _center[1]*(1 - scale_factor);
1291 transform(3,2) = _center[2]*(1 - scale_factor);
1292 matrix.preMult(transform);
1296 virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
1297 osg::NodeVisitor* nv) const
1299 double scale_factor = computeScaleFactor(nv);
1300 if (fabs(scale_factor) <= SGLimits<double>::min())
1302 osg::Matrix transform;
1303 double rScaleFactor = 1/scale_factor;
1304 transform(0,0) = rScaleFactor;
1305 transform(1,1) = rScaleFactor;
1306 transform(2,2) = rScaleFactor;
1307 transform(3,0) = _center[0]*(1 - rScaleFactor);
1308 transform(3,1) = _center[1]*(1 - rScaleFactor);
1309 transform(3,2) = _center[2]*(1 - rScaleFactor);
1310 matrix.postMult(transform);
1315 double computeScaleFactor(osg::NodeVisitor* nv) const
1320 osg::Vec3 localEyeToCenter = nv->getEyePoint() - _center;
1321 localEyeToCenter.normalize();
1323 double cos_angle = localEyeToCenter*_axis;
1324 double scale_factor = 0;
1325 if ( _two_sides && cos_angle < 0 )
1326 scale_factor = _factor * pow( -cos_angle, _power ) + _offset;
1327 else if ( cos_angle > 0 )
1328 scale_factor = _factor * pow( cos_angle, _power ) + _offset;
1330 if ( scale_factor < _min_v )
1331 scale_factor = _min_v;
1332 if ( scale_factor > _max_v )
1333 scale_factor = _max_v;
1335 return scale_factor;
1338 virtual osg::BoundingSphere computeBound() const
1340 // avoid being culled away by small feature culling
1341 osg::BoundingSphere bs = osg::Group::computeBound();
1342 bs.radius() *= _max_v;
1349 double _power, _factor, _offset, _min_v, _max_v;
1354 SGFlashAnimation::SGFlashAnimation(const SGPropertyNode* configNode,
1355 SGPropertyNode* modelRoot) :
1356 SGAnimation(configNode, modelRoot)
1361 SGFlashAnimation::createAnimationGroup(osg::Group& parent)
1363 Transform* transform = new Transform(getConfig());
1364 parent.addChild(transform);
1369 ////////////////////////////////////////////////////////////////////////
1370 // Implementation of flash animation
1371 ////////////////////////////////////////////////////////////////////////
1373 class SGBillboardAnimation::Transform : public osg::Transform {
1375 Transform(const SGPropertyNode* configNode) :
1376 _spherical(configNode->getBoolValue("spherical", true))
1378 setReferenceFrame(RELATIVE_RF);
1379 setName(configNode->getStringValue("name", "billboard animation"));
1381 virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,
1382 osg::NodeVisitor* nv) const
1384 // More or less taken from plibs ssgCutout
1386 matrix(0,0) = 1; matrix(0,1) = 0; matrix(0,2) = 0;
1387 matrix(1,0) = 0; matrix(1,1) = 0; matrix(1,2) = -1;
1388 matrix(2,0) = 0; matrix(2,1) = 1; matrix(2,2) = 0;
1390 osg::Vec3 zAxis(matrix(2, 0), matrix(2, 1), matrix(2, 2));
1391 osg::Vec3 xAxis = osg::Vec3(0, 0, -1)^zAxis;
1392 osg::Vec3 yAxis = zAxis^xAxis;
1398 matrix(0,0) = xAxis[0]; matrix(0,1) = xAxis[1]; matrix(0,2) = xAxis[2];
1399 matrix(1,0) = yAxis[0]; matrix(1,1) = yAxis[1]; matrix(1,2) = yAxis[2];
1400 matrix(2,0) = zAxis[0]; matrix(2,1) = zAxis[1]; matrix(2,2) = zAxis[2];
1405 virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,
1406 osg::NodeVisitor* nv) const
1408 // Hmm, don't yet know how to get that back ...
1417 SGBillboardAnimation::SGBillboardAnimation(const SGPropertyNode* configNode,
1418 SGPropertyNode* modelRoot) :
1419 SGAnimation(configNode, modelRoot)
1424 SGBillboardAnimation::createAnimationGroup(osg::Group& parent)
1426 Transform* transform = new Transform(getConfig());
1427 parent.addChild(transform);
1432 ////////////////////////////////////////////////////////////////////////
1433 // Implementation of a range animation
1434 ////////////////////////////////////////////////////////////////////////
1436 class SGRangeAnimation::UpdateCallback : public osg::NodeCallback {
1438 UpdateCallback(const SGCondition* condition,
1439 const SGDoubleValue* minAnimationValue,
1440 const SGDoubleValue* maxAnimationValue,
1441 double minValue, double maxValue) :
1442 _condition(condition),
1443 _minAnimationValue(minAnimationValue),
1444 _maxAnimationValue(maxAnimationValue),
1445 _minStaticValue(minValue),
1446 _maxStaticValue(maxValue)
1448 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
1450 osg::LOD* lod = static_cast<osg::LOD*>(node);
1451 if (!_condition || _condition->test()) {
1453 if (_minAnimationValue)
1454 minRange = _minAnimationValue->getValue();
1456 minRange = _minStaticValue;
1458 if (_maxAnimationValue)
1459 maxRange = _maxAnimationValue->getValue();
1461 maxRange = _maxStaticValue;
1462 lod->setRange(0, minRange, maxRange);
1464 lod->setRange(0, 0, SGLimitsf::max());
1470 SGSharedPtr<const SGCondition> _condition;
1471 SGSharedPtr<const SGDoubleValue> _minAnimationValue;
1472 SGSharedPtr<const SGDoubleValue> _maxAnimationValue;
1473 double _minStaticValue;
1474 double _maxStaticValue;
1477 SGRangeAnimation::SGRangeAnimation(const SGPropertyNode* configNode,
1478 SGPropertyNode* modelRoot) :
1479 SGAnimation(configNode, modelRoot)
1481 _condition = getCondition();
1483 std::string inputPropertyName;
1484 inputPropertyName = configNode->getStringValue("min-property", "");
1485 if (!inputPropertyName.empty()) {
1486 SGPropertyNode* inputProperty;
1487 inputProperty = modelRoot->getNode(inputPropertyName.c_str(), true);
1488 SGScaleOffsetValue* value = new SGScaleOffsetValue(inputProperty);
1489 value->setScale(configNode->getDoubleValue("min-factor", 1));
1490 _minAnimationValue = value;
1492 inputPropertyName = configNode->getStringValue("max-property", "");
1493 if (!inputPropertyName.empty()) {
1494 SGPropertyNode* inputProperty;
1495 inputProperty = modelRoot->getNode(inputPropertyName.c_str(), true);
1496 SGScaleOffsetValue* value = new SGScaleOffsetValue(inputProperty);
1497 value->setScale(configNode->getDoubleValue("max-factor", 1));
1498 _maxAnimationValue = value;
1501 _initialValue[0] = configNode->getDoubleValue("min-m", 0);
1502 _initialValue[0] *= configNode->getDoubleValue("min-factor", 1);
1503 _initialValue[1] = configNode->getDoubleValue("max-m", SGLimitsf::max());
1504 _initialValue[1] *= configNode->getDoubleValue("max-factor", 1);
1508 SGRangeAnimation::createAnimationGroup(osg::Group& parent)
1510 osg::Group* group = new osg::Group;
1511 group->setName("range animation group");
1513 osg::LOD* lod = new osg::LOD;
1514 lod->setName("range animation node");
1515 parent.addChild(lod);
1517 lod->addChild(group, _initialValue[0], _initialValue[1]);
1518 lod->setCenterMode(osg::LOD::USE_BOUNDING_SPHERE_CENTER);
1519 lod->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT);
1520 if (_minAnimationValue || _maxAnimationValue || _condition) {
1522 uc = new UpdateCallback(_condition, _minAnimationValue, _maxAnimationValue,
1523 _initialValue[0], _initialValue[1]);
1524 lod->setUpdateCallback(uc);
1530 ////////////////////////////////////////////////////////////////////////
1531 // Implementation of a select animation
1532 ////////////////////////////////////////////////////////////////////////
1534 class SGSelectAnimation::UpdateCallback : public osg::NodeCallback {
1536 UpdateCallback(const SGCondition* condition) :
1537 _condition(condition)
1539 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
1541 osg::Switch* sw = static_cast<osg::Switch*>(node);
1542 if (_condition->test())
1543 sw->setAllChildrenOn();
1545 sw->setAllChildrenOff();
1550 SGSharedPtr<SGCondition const> _condition;
1553 SGSelectAnimation::SGSelectAnimation(const SGPropertyNode* configNode,
1554 SGPropertyNode* modelRoot) :
1555 SGAnimation(configNode, modelRoot)
1560 SGSelectAnimation::createAnimationGroup(osg::Group& parent)
1562 // if no condition given, this is a noop.
1563 SGSharedPtr<SGCondition const> condition = getCondition();
1564 // trick, gets deleted with all its 'animated' children
1565 // when the animation installer returns
1567 return new osg::Group;
1569 osg::Switch* sw = new osg::Switch;
1570 sw->setName("select animation node");
1571 sw->setUpdateCallback(new UpdateCallback(condition));
1572 parent.addChild(sw);
1578 ////////////////////////////////////////////////////////////////////////
1579 // Implementation of alpha test animation
1580 ////////////////////////////////////////////////////////////////////////
1582 SGAlphaTestAnimation::SGAlphaTestAnimation(const SGPropertyNode* configNode,
1583 SGPropertyNode* modelRoot) :
1584 SGAnimation(configNode, modelRoot)
1589 SGAlphaTestAnimation::install(osg::Node& node)
1591 SGAnimation::install(node);
1593 cloneDrawables(node);
1594 removeMode(node, GL_ALPHA_TEST);
1595 removeAttribute(node, osg::StateAttribute::ALPHAFUNC);
1597 osg::StateSet* stateSet = node.getOrCreateStateSet();
1598 osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
1599 alphaFunc->setFunction(osg::AlphaFunc::GREATER);
1600 float alphaClamp = getConfig()->getFloatValue("alpha-factor", 0);
1601 alphaFunc->setReferenceValue(alphaClamp);
1602 stateSet->setAttribute(alphaFunc);
1603 stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
1608 //////////////////////////////////////////////////////////////////////
1609 // Blend animation installer
1610 //////////////////////////////////////////////////////////////////////
1612 class SGBlendAnimation::BlendVisitor : public osg::NodeVisitor {
1614 BlendVisitor(float blend) :
1615 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
1617 { setVisitorType(osg::NodeVisitor::NODE_VISITOR); }
1618 virtual void apply(osg::Node& node)
1620 updateStateSet(node.getStateSet());
1623 virtual void apply(osg::Geode& node)
1625 apply((osg::Node&)node);
1626 unsigned nDrawables = node.getNumDrawables();
1627 for (unsigned i = 0; i < nDrawables; ++i) {
1628 osg::Drawable* drawable = node.getDrawable(i);
1629 updateStateSet(drawable->getStateSet());
1630 osg::Geometry* geometry = drawable->asGeometry();
1633 osg::Array* array = geometry->getColorArray();
1636 osg::Vec4Array* vec4Array = dynamic_cast<osg::Vec4Array*>(array);
1639 geometry->dirtyDisplayList();
1641 for (unsigned k = 0; k < vec4Array->size(); ++k) {
1642 (*vec4Array)[k][3] = _blend;
1646 void updateStateSet(osg::StateSet* stateSet)
1650 osg::StateAttribute* stateAttribute;
1651 stateAttribute = stateSet->getAttribute(osg::StateAttribute::MATERIAL);
1652 if (!stateAttribute)
1654 osg::Material* material = dynamic_cast<osg::Material*>(stateAttribute);
1657 material->setAlpha(osg::Material::FRONT_AND_BACK, _blend);
1659 stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
1660 stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
1662 stateSet->setRenderingHint(osg::StateSet::DEFAULT_BIN);
1669 class SGBlendAnimation::UpdateCallback : public osg::NodeCallback {
1671 UpdateCallback(const SGPropertyNode* configNode, const SGDoubleValue* v) :
1675 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
1677 double blend = _animationValue->getValue();
1678 if (blend != _prev_value) {
1679 _prev_value = blend;
1680 BlendVisitor visitor(1-blend);
1681 node->accept(visitor);
1687 SGSharedPtr<SGDoubleValue const> _animationValue;
1691 SGBlendAnimation::SGBlendAnimation(const SGPropertyNode* configNode,
1692 SGPropertyNode* modelRoot)
1693 : SGAnimation(configNode, modelRoot),
1694 _animationValue(read_value(configNode, modelRoot, "", 0, 1))
1699 SGBlendAnimation::createAnimationGroup(osg::Group& parent)
1701 if (!_animationValue)
1704 osg::Group* group = new osg::Switch;
1705 group->setName("blend animation node");
1706 group->setUpdateCallback(new UpdateCallback(getConfig(), _animationValue));
1707 parent.addChild(group);
1712 SGBlendAnimation::install(osg::Node& node)
1714 SGAnimation::install(node);
1715 // make sure we do not change common geometries,
1716 // that also creates new display lists for these subgeometries.
1717 cloneDrawables(node);
1721 //////////////////////////////////////////////////////////////////////
1722 // Timed animation installer
1723 //////////////////////////////////////////////////////////////////////
1727 class SGTimedAnimation::UpdateCallback : public osg::NodeCallback {
1729 UpdateCallback(const SGPropertyNode* configNode) :
1732 _duration_sec(configNode->getDoubleValue("duration-sec", 1)),
1733 _last_time_sec(SGLimitsd::max()),
1734 _use_personality(configNode->getBoolValue("use-personality", false))
1736 std::vector<SGSharedPtr<SGPropertyNode> > nodes;
1737 nodes = configNode->getChildren("branch-duration-sec");
1738 for (size_t i = 0; i < nodes.size(); ++i) {
1739 unsigned ind = nodes[ i ]->getIndex();
1740 while ( ind >= _durations.size() ) {
1741 _durations.push_back(DurationSpec(_duration_sec));
1743 SGPropertyNode_ptr rNode = nodes[i]->getChild("random");
1745 _durations[ind] = DurationSpec(nodes[ i ]->getDoubleValue());
1747 _durations[ind] = DurationSpec(rNode->getDoubleValue( "min", 0),
1748 rNode->getDoubleValue( "max", 1));
1752 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
1754 assert(dynamic_cast<osg::Switch*>(node));
1755 osg::Switch* sw = static_cast<osg::Switch*>(node);
1757 unsigned nChildren = sw->getNumChildren();
1759 // blow up the durations vector to the required size
1760 while (_durations.size() < nChildren) {
1761 _durations.push_back(_duration_sec);
1763 // make sure the current index is an duration that really exists
1764 _current_index = _current_index % nChildren;
1766 // update the time and compute the current systems time value
1767 double t = nv->getFrameStamp()->getReferenceTime();
1768 if (_last_time_sec == SGLimitsd::max()) {
1771 double dt = t - _last_time_sec;
1772 if (_use_personality)
1773 dt *= 1 + 0.2*(0.5 - sg_random());
1778 double currentDuration = _durations[_current_index].get();
1779 while (currentDuration < _reminder) {
1780 _reminder -= currentDuration;
1781 _current_index = (_current_index + 1) % nChildren;
1782 currentDuration = _durations[_current_index].get();
1785 sw->setSingleChildOn(_current_index);
1791 struct DurationSpec {
1792 DurationSpec(double t) :
1793 minTime(SGMiscd::max(0.01, t)),
1794 maxTime(SGMiscd::max(0.01, t))
1796 DurationSpec(double t0, double t1) :
1797 minTime(SGMiscd::max(0.01, t0)),
1798 maxTime(SGMiscd::max(0.01, t1))
1801 { return minTime + sg_random()*(maxTime - minTime); }
1805 std::vector<DurationSpec> _durations;
1806 unsigned _current_index;
1808 double _duration_sec;
1809 double _last_time_sec;
1810 bool _use_personality;
1814 SGTimedAnimation::SGTimedAnimation(const SGPropertyNode* configNode,
1815 SGPropertyNode* modelRoot)
1816 : SGAnimation(configNode, modelRoot)
1821 SGTimedAnimation::createAnimationGroup(osg::Group& parent)
1823 osg::Switch* sw = new osg::Switch;
1824 sw->setName("timed animation node");
1825 sw->setUpdateCallback(new UpdateCallback(getConfig()));
1826 parent.addChild(sw);
1831 ////////////////////////////////////////////////////////////////////////
1832 // dynamically switch on/off shadows
1833 ////////////////////////////////////////////////////////////////////////
1835 class SGShadowAnimation::UpdateCallback : public osg::NodeCallback {
1837 UpdateCallback(const SGCondition* condition) :
1838 _condition(condition)
1840 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
1842 if (_condition->test())
1843 node->setNodeMask( SG_NODEMASK_SHADOW_BIT | node->getNodeMask());
1845 node->setNodeMask(~SG_NODEMASK_SHADOW_BIT & node->getNodeMask());
1850 SGSharedPtr<const SGCondition> _condition;
1853 SGShadowAnimation::SGShadowAnimation(const SGPropertyNode* configNode,
1854 SGPropertyNode* modelRoot) :
1855 SGAnimation(configNode, modelRoot)
1860 SGShadowAnimation::createAnimationGroup(osg::Group& parent)
1862 SGSharedPtr<SGCondition const> condition = getCondition();
1866 osg::Group* group = new osg::Group;
1867 group->setName("shadow animation");
1868 group->setUpdateCallback(new UpdateCallback(condition));
1869 parent.addChild(group);
1874 ////////////////////////////////////////////////////////////////////////
1875 // Implementation of SGTexTransformAnimation
1876 ////////////////////////////////////////////////////////////////////////
1878 class SGTexTransformAnimation::Transform : public SGReferenced {
1883 virtual ~Transform()
1885 void setValue(double value)
1887 virtual void transform(osg::Matrix&) = 0;
1892 class SGTexTransformAnimation::Translation :
1893 public SGTexTransformAnimation::Transform {
1895 Translation(const SGVec3d& axis) :
1898 void setValue(double value)
1900 virtual void transform(osg::Matrix& matrix)
1903 set_translation(tmp, _value, _axis);
1904 matrix.preMult(tmp);
1910 class SGTexTransformAnimation::Rotation :
1911 public SGTexTransformAnimation::Transform {
1913 Rotation(const SGVec3d& axis, const SGVec3d& center) :
1917 virtual void transform(osg::Matrix& matrix)
1920 set_rotation(tmp, _value, _center, _axis);
1921 matrix.preMult(tmp);
1928 class SGTexTransformAnimation::UpdateCallback :
1929 public osg::StateAttribute::Callback {
1931 UpdateCallback(const SGCondition* condition) :
1932 _condition(condition)
1934 virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor*)
1936 if (!_condition || _condition->test()) {
1937 TransformList::const_iterator i;
1938 for (i = _transforms.begin(); i != _transforms.end(); ++i)
1939 i->transform->setValue(i->value->getValue());
1941 assert(dynamic_cast<osg::TexMat*>(sa));
1942 osg::TexMat* texMat = static_cast<osg::TexMat*>(sa);
1943 texMat->getMatrix().makeIdentity();
1944 TransformList::const_iterator i;
1945 for (i = _transforms.begin(); i != _transforms.end(); ++i)
1946 i->transform->transform(texMat->getMatrix());
1948 void appendTransform(Transform* transform, SGDoubleValue* value)
1950 Entry entry = { transform, value };
1951 transform->transform(_matrix);
1952 _transforms.push_back(entry);
1957 SGSharedPtr<Transform> transform;
1958 SGSharedPtr<const SGDoubleValue> value;
1960 typedef std::vector<Entry> TransformList;
1961 TransformList _transforms;
1962 SGSharedPtr<const SGCondition> _condition;
1963 osg::Matrix _matrix;
1966 SGTexTransformAnimation::SGTexTransformAnimation(const SGPropertyNode* configNode,
1967 SGPropertyNode* modelRoot) :
1968 SGAnimation(configNode, modelRoot)
1973 SGTexTransformAnimation::createAnimationGroup(osg::Group& parent)
1975 osg::Group* group = new osg::Group;
1976 group->setName("texture transform group");
1977 osg::StateSet* stateSet = group->getOrCreateStateSet();
1978 osg::TexMat* texMat = new osg::TexMat;
1979 UpdateCallback* updateCallback = new UpdateCallback(getCondition());
1980 // interpret the configs ...
1981 std::string type = getType();
1983 if (type == "textranslate") {
1984 appendTexTranslate(getConfig(), updateCallback);
1985 } else if (type == "texrotate") {
1986 appendTexRotate(getConfig(), updateCallback);
1987 } else if (type == "texmultiple") {
1988 std::vector<SGSharedPtr<SGPropertyNode> > transformConfigs;
1989 transformConfigs = getConfig()->getChildren("transform");
1990 for (unsigned i = 0; i < transformConfigs.size(); ++i) {
1991 std::string subtype = transformConfigs[i]->getStringValue("subtype", "");
1992 if (subtype == "textranslate")
1993 appendTexTranslate(transformConfigs[i], updateCallback);
1994 else if (subtype == "texrotate")
1995 appendTexRotate(transformConfigs[i], updateCallback);
1997 SG_LOG(SG_INPUT, SG_ALERT,
1998 "Ignoring unknown texture transform subtype");
2001 SG_LOG(SG_INPUT, SG_ALERT, "Ignoring unknown texture transform type");
2004 texMat->setUpdateCallback(updateCallback);
2005 stateSet->setTextureAttribute(0, texMat);
2006 parent.addChild(group);
2011 SGTexTransformAnimation::appendTexTranslate(const SGPropertyNode* config,
2012 UpdateCallback* updateCallback)
2014 std::string propertyName = config->getStringValue("property", "/null");
2015 SGPropertyNode* inputNode;
2016 inputNode = getModelRoot()->getNode(propertyName.c_str(), true);
2018 SGDoubleValue* animationValue;
2019 SGInterpTable* table = read_interpolation_table(config);
2021 SGTexTableValue* value;
2022 value = new SGTexTableValue(inputNode, table);
2023 value->setStep(config->getDoubleValue("step", 0));
2024 value->setScroll(config->getDoubleValue("scroll", 0));
2025 animationValue = value;
2027 SGTexScaleOffsetValue* value;
2028 value = new SGTexScaleOffsetValue(inputNode);
2029 value->setScale(config->getDoubleValue("factor", 1));
2030 value->setOffset(config->getDoubleValue("offset", 0));
2031 value->setStep(config->getDoubleValue("step", 0));
2032 value->setScroll(config->getDoubleValue("scroll", 0));
2033 value->setMin(config->getDoubleValue("min", -SGLimitsd::max()));
2034 value->setMax(config->getDoubleValue("max", SGLimitsd::max()));
2035 animationValue = value;
2037 SGVec3d axis(config->getDoubleValue("axis/x", 0),
2038 config->getDoubleValue("axis/y", 0),
2039 config->getDoubleValue("axis/z", 0));
2040 Translation* translation;
2041 translation = new Translation(normalize(axis));
2042 translation->setValue(config->getDoubleValue("starting-position", 0));
2043 updateCallback->appendTransform(translation, animationValue);
2047 SGTexTransformAnimation::appendTexRotate(const SGPropertyNode* config,
2048 UpdateCallback* updateCallback)
2050 std::string propertyName = config->getStringValue("property", "/null");
2051 SGPropertyNode* inputNode;
2052 inputNode = getModelRoot()->getNode(propertyName.c_str(), true);
2054 SGDoubleValue* animationValue;
2055 SGInterpTable* table = read_interpolation_table(config);
2057 SGTexTableValue* value;
2058 value = new SGTexTableValue(inputNode, table);
2059 value->setStep(config->getDoubleValue("step", 0));
2060 value->setScroll(config->getDoubleValue("scroll", 0));
2061 animationValue = value;
2063 SGTexScaleOffsetValue* value;
2064 value = new SGTexScaleOffsetValue(inputNode);
2065 value->setScale(config->getDoubleValue("factor", 1));
2066 value->setOffset(config->getDoubleValue("offset-deg", 0));
2067 value->setStep(config->getDoubleValue("step", 0));
2068 value->setScroll(config->getDoubleValue("scroll", 0));
2069 value->setMin(config->getDoubleValue("min-deg", -SGLimitsd::max()));
2070 value->setMax(config->getDoubleValue("max-deg", SGLimitsd::max()));
2071 animationValue = value;
2073 SGVec3d axis(config->getDoubleValue("axis/x", 0),
2074 config->getDoubleValue("axis/y", 0),
2075 config->getDoubleValue("axis/z", 0));
2076 SGVec3d center(config->getDoubleValue("center/x", 0),
2077 config->getDoubleValue("center/y", 0),
2078 config->getDoubleValue("center/z", 0));
2080 rotation = new Rotation(normalize(axis), center);
2081 rotation->setValue(config->getDoubleValue("starting-position-deg", 0));
2082 updateCallback->appendTransform(rotation, animationValue);
2086 ////////////////////////////////////////////////////////////////////////
2087 // Implementation of SGPickAnimation
2088 ////////////////////////////////////////////////////////////////////////
2090 class SGPickAnimation::PickCallback : public SGPickCallback {
2092 PickCallback(const SGPropertyNode* configNode,
2093 SGPropertyNode* modelRoot) :
2094 _repeatable(configNode->getBoolValue("repeatable", false)),
2095 _repeatInterval(configNode->getDoubleValue("interval-sec", 0.1))
2097 SG_LOG(SG_INPUT, SG_DEBUG, "Reading all bindings");
2098 std::vector<SGPropertyNode_ptr> bindings;
2099 bindings = configNode->getChildren("binding");
2100 for (unsigned int i = 0; i < bindings.size(); ++i) {
2101 _bindingsDown.push_back(new SGBinding(bindings[i], modelRoot));
2104 const SGPropertyNode* upNode = configNode->getChild("mod-up");
2107 bindings = upNode->getChildren("binding");
2108 for (unsigned int i = 0; i < bindings.size(); ++i) {
2109 _bindingsUp.push_back(new SGBinding(bindings[i], modelRoot));
2112 virtual bool buttonPressed(int button, const Info&)
2114 SGBindingList::const_iterator i;
2115 for (i = _bindingsDown.begin(); i != _bindingsDown.end(); ++i)
2120 virtual void buttonReleased(void)
2122 SGBindingList::const_iterator i;
2123 for (i = _bindingsUp.begin(); i != _bindingsUp.end(); ++i)
2126 virtual void update(double dt)
2132 while (_repeatInterval < _repeatTime) {
2133 _repeatTime -= _repeatInterval;
2134 SGBindingList::const_iterator i;
2135 for (i = _bindingsDown.begin(); i != _bindingsDown.end(); ++i)
2140 SGBindingList _bindingsDown;
2141 SGBindingList _bindingsUp;
2143 double _repeatInterval;
2147 SGPickAnimation::SGPickAnimation(const SGPropertyNode* configNode,
2148 SGPropertyNode* modelRoot) :
2149 SGAnimation(configNode, modelRoot)
2154 SGPickAnimation::createAnimationGroup(osg::Group& parent)
2156 osg::Group* commonGroup = new osg::Group;
2158 // Contains the normal geometry that is interactive
2159 osg::Group* normalGroup = new osg::Group;
2160 normalGroup->addChild(commonGroup);
2161 SGSceneUserData* ud = SGSceneUserData::getOrCreateSceneUserData(normalGroup);
2162 ud->setPickCallback(new PickCallback(getConfig(), getModelRoot()));
2164 // Used to render the geometry with just yellow edges
2165 osg::Group* highlightGroup = new osg::Group;
2166 highlightGroup->setNodeMask(SG_NODEMASK_PICK_BIT);
2167 highlightGroup->addChild(commonGroup);
2169 // prepare a state set that paints the edges of this object yellow
2170 osg::StateSet* stateSet = highlightGroup->getOrCreateStateSet();
2171 stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
2173 osg::PolygonOffset* polygonOffset = new osg::PolygonOffset;
2174 polygonOffset->setFactor(-1);
2175 polygonOffset->setUnits(-1);
2176 stateSet->setAttribute(polygonOffset, osg::StateAttribute::OVERRIDE);
2177 stateSet->setMode(GL_POLYGON_OFFSET_LINE, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
2179 osg::PolygonMode* polygonMode = new osg::PolygonMode;
2180 polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
2181 osg::PolygonMode::LINE);
2182 stateSet->setAttribute(polygonMode, osg::StateAttribute::OVERRIDE);
2184 osg::Material* material = new osg::Material;
2185 material->setColorMode(osg::Material::OFF);
2186 material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1, 1, 0, 1));
2187 material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1, 1, 0, 1));
2188 material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1, 1, 0, 1));
2189 material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, 0));
2190 stateSet->setAttribute(material, osg::StateAttribute::OVERRIDE);
2192 parent.addChild(normalGroup);
2193 parent.addChild(highlightGroup);