+class SGAnimation::RemoveModeVisitor : public SGStateAttributeVisitor {
+public:
+ RemoveModeVisitor(osg::StateAttribute::GLMode mode) :
+ _mode(mode)
+ { }
+ virtual void apply(osg::StateSet* stateSet)
+ {
+ if (!stateSet)
+ return;
+ stateSet->removeMode(_mode);
+ }
+private:
+ osg::StateAttribute::GLMode _mode;
+};
+
+class SGAnimation::RemoveAttributeVisitor : public SGStateAttributeVisitor {
+public:
+ RemoveAttributeVisitor(osg::StateAttribute::Type type) :
+ _type(type)
+ { }
+ virtual void apply(osg::StateSet* stateSet)
+ {
+ if (!stateSet)
+ return;
+ while (stateSet->getAttribute(_type)) {
+ stateSet->removeAttribute(_type);
+ }
+ }
+private:
+ osg::StateAttribute::Type _type;
+};
+
+class SGAnimation::RemoveTextureModeVisitor : public SGStateAttributeVisitor {
+public:
+ RemoveTextureModeVisitor(unsigned unit, osg::StateAttribute::GLMode mode) :
+ _unit(unit),
+ _mode(mode)
+ { }
+ virtual void apply(osg::StateSet* stateSet)
+ {
+ if (!stateSet)
+ return;
+ stateSet->removeTextureMode(_unit, _mode);
+ }
+private:
+ unsigned _unit;
+ osg::StateAttribute::GLMode _mode;
+};
+
+class SGAnimation::RemoveTextureAttributeVisitor :
+ public SGStateAttributeVisitor {
+public:
+ RemoveTextureAttributeVisitor(unsigned unit,
+ osg::StateAttribute::Type type) :
+ _unit(unit),
+ _type(type)
+ { }
+ virtual void apply(osg::StateSet* stateSet)
+ {
+ if (!stateSet)
+ return;
+ while (stateSet->getTextureAttribute(_unit, _type)) {
+ stateSet->removeTextureAttribute(_unit, _type);
+ }
+ }
+private:
+ unsigned _unit;
+ osg::StateAttribute::Type _type;
+};
+
+class SGAnimation::BinToInheritVisitor : public SGStateAttributeVisitor {
+public:
+ virtual void apply(osg::StateSet* stateSet)
+ {
+ if (!stateSet)
+ return;
+ stateSet->setRenderBinToInherit();
+ }
+};
+
+class SGAnimation::DrawableCloneVisitor : public osg::NodeVisitor {
+public:
+ DrawableCloneVisitor() :
+ osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
+ {}
+ void apply(osg::Geode& geode)
+ {
+ for (unsigned i = 0 ; i < geode.getNumDrawables(); ++i) {
+ osg::CopyOp copyOp(osg::CopyOp::DEEP_COPY_ALL &
+ ~osg::CopyOp::DEEP_COPY_TEXTURES);
+ geode.setDrawable(i, copyOp(geode.getDrawable(i)));
+ }
+ }
+};
+
+namespace
+{
+// Set all drawables to not use display lists. OSG will use
+// glDrawArrays instead.
+struct DoDrawArraysVisitor : public osg::NodeVisitor {
+ DoDrawArraysVisitor() :
+ osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
+ {}
+ void apply(osg::Geode& geode)
+ {
+ using namespace osg;
+ using namespace std;
+
+ for (int i = 0; i < (int)geode.getNumDrawables(); ++i)
+ geode.getDrawable(i)->setUseDisplayList(false);
+ }
+};
+}
+
+SGAnimation::SGAnimation(const SGPropertyNode* configNode,
+ SGPropertyNode* modelRoot) :
+ osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
+ _found(false),
+ _configNode(configNode),
+ _modelRoot(modelRoot)
+{
+ _name = configNode->getStringValue("name", "");
+ _enableHOT = configNode->getBoolValue("enable-hot", true);
+ _disableShadow = configNode->getBoolValue("disable-shadow", false);
+ std::vector<SGPropertyNode_ptr> objectNames =
+ configNode->getChildren("object-name");
+ for (unsigned i = 0; i < objectNames.size(); ++i)
+ _objectNames.push_back(objectNames[i]->getStringValue());
+}
+
+SGAnimation::~SGAnimation()
+{
+ if (_found)
+ return;
+
+ SG_LOG(SG_IO, SG_ALERT, "Could not find at least one of the following"
+ " objects for animation:\n");
+ std::list<std::string>::const_iterator i;
+ for (i = _objectNames.begin(); i != _objectNames.end(); ++i)
+ SG_LOG(SG_IO, SG_ALERT, *i << "\n");
+}
+
+bool
+SGAnimation::animate(osg::Node* node, const SGPropertyNode* configNode,
+ SGPropertyNode* modelRoot,
+ const osgDB::ReaderWriter::Options* options)
+{
+ std::string type = configNode->getStringValue("type", "none");
+ if (type == "alpha-test") {
+ SGAlphaTestAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else if (type == "billboard") {
+ SGBillboardAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else if (type == "blend") {
+ SGBlendAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else if (type == "dist-scale") {
+ SGDistScaleAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else if (type == "flash") {
+ SGFlashAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else if (type == "interaction") {
+ SGInteractionAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else if (type == "material") {
+ SGMaterialAnimation animInst(configNode, modelRoot, options);
+ animInst.apply(node);
+ } else if (type == "noshadow") {
+ SGShadowAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else if (type == "pick") {
+ SGPickAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else if (type == "range") {
+ SGRangeAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else if (type == "rotate" || type == "spin") {
+ SGRotateAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else if (type == "scale") {
+ SGScaleAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else if (type == "select") {
+ SGSelectAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else if (type == "shader") {
+ SGShaderAnimation animInst(configNode, modelRoot, options);
+ animInst.apply(node);
+ } else if (type == "textranslate" || type == "texrotate" ||
+ type == "texmultiple") {
+ SGTexTransformAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else if (type == "timed") {
+ SGTimedAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else if (type == "translate") {
+ SGTranslateAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else if (type == "null" || type == "none" || type.empty()) {
+ SGGroupAnimation animInst(configNode, modelRoot);
+ animInst.apply(node);
+ } else
+ return false;
+
+ return true;
+}
+
+
+void
+SGAnimation::apply(osg::Node* node)
+{
+ // duh what a special case ...
+ if (_objectNames.empty()) {
+ osg::Group* group = node->asGroup();
+ if (group) {
+ osg::ref_ptr<osg::Group> animationGroup;
+ installInGroup(std::string(), *group, animationGroup);
+ }
+ } else
+ node->accept(*this);
+}
+
+void
+SGAnimation::install(osg::Node& node)
+{
+ _found = true;
+ if (_enableHOT)
+ node.setNodeMask( SG_NODEMASK_TERRAIN_BIT | node.getNodeMask());
+ else
+ node.setNodeMask(~SG_NODEMASK_TERRAIN_BIT & node.getNodeMask());
+ if (!_disableShadow)
+ node.setNodeMask( SG_NODEMASK_CASTSHADOW_BIT | node.getNodeMask());
+ else
+ node.setNodeMask(~SG_NODEMASK_CASTSHADOW_BIT & node.getNodeMask());
+}
+
+osg::Group*
+SGAnimation::createAnimationGroup(osg::Group& parent)
+{
+ // default implementation, we do not need a new group
+ // for every animation type. Usually animations that just change
+ // the StateSet of some parts of the model
+ return 0;
+}