From 77517b15fd13eeb111114eda7824a7141d3c6ed3 Mon Sep 17 00:00:00 2001 From: Richard Harrison Date: Wed, 10 May 2017 09:32:24 +0200 Subject: [PATCH] Allow animations to take an object as the centre and axis. Applicable to / works with rotate, translate and knob. Once the axis object-name has been used it will be hidden, however it still can be used for object-name animations. The hiding of the axis object is a useful guide as to what is left to be wired up to animations. This allows the follow to work (on a combined ASI / Mach instrument). rotate asi-needle ... airspeed-asi-axis rotate asi-mach-scale ... airspeed-asi-axis --- .../scene/model/SGInteractionAnimation.cxx | 5 +- .../scene/model/SGInteractionAnimation.hxx | 3 +- simgear/scene/model/SGLightAnimation.cxx | 14 +- simgear/scene/model/SGMaterialAnimation.cxx | 12 +- simgear/scene/model/SGMaterialAnimation.hxx | 4 +- simgear/scene/model/SGPickAnimation.cxx | 30 +- simgear/scene/model/SGPickAnimation.hxx | 11 +- simgear/scene/model/SGReaderWriterXML.cxx | 13 +- simgear/scene/model/SGTrackToAnimation.cxx | 14 +- simgear/scene/model/SGTrackToAnimation.hxx | 4 +- simgear/scene/model/animation.cxx | 541 ++++++++++++------ simgear/scene/model/animation.hxx | 64 +-- simgear/scene/model/shadanim.cxx | 11 +- simgear/scene/util/CMakeLists.txt | 1 + simgear/scene/util/SGReaderWriterOptions.hxx | 1 + simgear/scene/util/SGTransientModelData.hxx | 98 ++++ 16 files changed, 550 insertions(+), 276 deletions(-) create mode 100644 simgear/scene/util/SGTransientModelData.hxx diff --git a/simgear/scene/model/SGInteractionAnimation.cxx b/simgear/scene/model/SGInteractionAnimation.cxx index e6af9862..116325c3 100644 --- a/simgear/scene/model/SGInteractionAnimation.cxx +++ b/simgear/scene/model/SGInteractionAnimation.cxx @@ -122,9 +122,8 @@ private: std::vector _lineSegments; }; -SGInteractionAnimation::SGInteractionAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - SGAnimation(configNode, modelRoot) +SGInteractionAnimation::SGInteractionAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData) { } diff --git a/simgear/scene/model/SGInteractionAnimation.hxx b/simgear/scene/model/SGInteractionAnimation.hxx index 3b3ab6ec..31bb3ebd 100644 --- a/simgear/scene/model/SGInteractionAnimation.hxx +++ b/simgear/scene/model/SGInteractionAnimation.hxx @@ -22,8 +22,7 @@ class SGInteractionAnimation : public SGAnimation { public: - SGInteractionAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGInteractionAnimation(simgear::SGTransientModelData &modelData); virtual void install(osg::Node& node); private: class LineCollector; diff --git a/simgear/scene/model/SGLightAnimation.cxx b/simgear/scene/model/SGLightAnimation.cxx index b049c15d..95b15409 100644 --- a/simgear/scene/model/SGLightAnimation.cxx +++ b/simgear/scene/model/SGLightAnimation.cxx @@ -93,12 +93,8 @@ public: double _prev_value; }; -SGLightAnimation::SGLightAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot, - const osgDB::Options* options, - const std::string &path, int i) : - SGAnimation(configNode, modelRoot), - _options(options) +SGLightAnimation::SGLightAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData), _options(modelData.getOptions()) { _light_type = getConfig()->getStringValue("light-type"); _position = SGVec3d( getConfig()->getDoubleValue("position/x"), getConfig()->getDoubleValue("position/y"), getConfig()->getDoubleValue("position/z") ); @@ -113,11 +109,11 @@ SGLightAnimation::SGLightAnimation(const SGPropertyNode* configNode, _cutoff = getConfig()->getDoubleValue("cutoff"); _near = getConfig()->getDoubleValue("near-m"); _far = getConfig()->getDoubleValue("far-m"); - _key = path + ";" + boost::lexical_cast( i ); + _key = modelData.getPath() + ";" + boost::lexical_cast(modelData.getIndex() ); - SGConstPropertyNode_ptr dim_factor = configNode->getChild("dim-factor"); + SGConstPropertyNode_ptr dim_factor = modelData.getConfigNode()->getChild("dim-factor"); if (dim_factor.valid()) { - _animationValue = read_value(dim_factor, modelRoot, "", 0, 1); + _animationValue = read_value(dim_factor, modelData.getModelRoot(), "", 0, 1); } } diff --git a/simgear/scene/model/SGMaterialAnimation.cxx b/simgear/scene/model/SGMaterialAnimation.cxx index 9f7bb733..065631e2 100644 --- a/simgear/scene/model/SGMaterialAnimation.cxx +++ b/simgear/scene/model/SGMaterialAnimation.cxx @@ -416,15 +416,11 @@ private: } // namespace -SGMaterialAnimation::SGMaterialAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot, - const osgDB::Options* - options, const string &path) : - SGAnimation(configNode, modelRoot), - texturePathList(options->getDatabasePathList()) +SGMaterialAnimation::SGMaterialAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData), texturePathList(modelData.getOptions()->getDatabasePathList()) { - if (configNode->hasChild("global")) - SG_LOG(SG_IO, SG_ALERT, path << + if (modelData.getConfigNode()->hasChild("global")) + SG_LOG(SG_IO, SG_ALERT, modelData.getPath() << ": Use of in material animation is " "no longer supported."); } diff --git a/simgear/scene/model/SGMaterialAnimation.hxx b/simgear/scene/model/SGMaterialAnimation.hxx index bb62e83b..60093102 100644 --- a/simgear/scene/model/SGMaterialAnimation.hxx +++ b/simgear/scene/model/SGMaterialAnimation.hxx @@ -21,9 +21,7 @@ class SGMaterialAnimation : public SGAnimation { public: - SGMaterialAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot, - const osgDB::Options* options,const std::string &path); + SGMaterialAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); virtual void install(osg::Node& node); static SGPropertyNode_ptr makeEffectProperties(const SGPropertyNode* animProp); diff --git a/simgear/scene/model/SGPickAnimation.cxx b/simgear/scene/model/SGPickAnimation.cxx index 59e9d9c4..fdec3316 100644 --- a/simgear/scene/model/SGPickAnimation.cxx +++ b/simgear/scene/model/SGPickAnimation.cxx @@ -301,12 +301,10 @@ private: /////////////////////////////////////////////////////////////////////////////// -SGPickAnimation::SGPickAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - SGAnimation(configNode, modelRoot) +SGPickAnimation::SGPickAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData) { - std::vector names = - configNode->getChildren("proxy-name"); + std::vector names = modelData.getConfigNode()->getChildren("proxy-name"); for (unsigned i = 0; i < names.size(); ++i) { _proxyNames.push_back(names[i]->getStringValue()); } @@ -373,12 +371,12 @@ osg::StateSet* sharedHighlightStateSet() } void -SGPickAnimation::apply(osg::Group& group) +SGPickAnimation::apply(simgear::SGTransientModelData &modelData) { if (_objectNames.empty() && _proxyNames.empty()) { return; } - + osg::Group& group = *modelData.getNode()->asGroup(); group.traverse(*this); // iterate over all group children @@ -738,16 +736,15 @@ private: }; -SGKnobAnimation::SGKnobAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - SGPickAnimation(configNode, modelRoot) +SGKnobAnimation::SGKnobAnimation(simgear::SGTransientModelData &modelData) : + SGPickAnimation(modelData) { - SGSharedPtr value = read_value(configNode, modelRoot, "-deg", + SGSharedPtr value = read_value(modelData.getConfigNode(), modelData.getModelRoot(), "-deg", -SGLimitsd::max(), SGLimitsd::max()); _animationValue = value->simplify(); - readRotationCenterAndAxis(_center, _axis); + readRotationCenterAndAxis(modelData.getNode(), _center, _axis, modelData); } osg::Group* @@ -807,15 +804,14 @@ private: }; -SGSliderAnimation::SGSliderAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - SGPickAnimation(configNode, modelRoot) +SGSliderAnimation::SGSliderAnimation(simgear::SGTransientModelData &modelData) : + SGPickAnimation(modelData) { - SGSharedPtr value = read_value(configNode, modelRoot, "-m", + SGSharedPtr value = read_value(modelData.getConfigNode(), modelData.getModelRoot(), "-m", -SGLimitsd::max(), SGLimitsd::max()); _animationValue = value->simplify(); - _axis = readTranslateAxis(configNode); + _axis = readTranslateAxis(modelData.getConfigNode()); } osg::Group* diff --git a/simgear/scene/model/SGPickAnimation.hxx b/simgear/scene/model/SGPickAnimation.hxx index 9770d2d9..ab2ae770 100644 --- a/simgear/scene/model/SGPickAnimation.hxx +++ b/simgear/scene/model/SGPickAnimation.hxx @@ -35,11 +35,10 @@ class SGSceneUserData; class SGPickAnimation : public SGAnimation { public: - SGPickAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGPickAnimation(simgear::SGTransientModelData &modelData); // override so we can treat object-name specially - virtual void apply(osg::Group& group); + virtual void apply(simgear::SGTransientModelData &modelData); void apply(osg::Node* node); protected: @@ -59,8 +58,7 @@ private: class SGKnobAnimation : public SGPickAnimation { public: - SGKnobAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGKnobAnimation(simgear::SGTransientModelData &modelData); /** * by default mouse wheel up corresponds to increment (CW) @@ -101,8 +99,7 @@ private: class SGSliderAnimation : public SGPickAnimation { public: - SGSliderAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGSliderAnimation(simgear::SGTransientModelData &modelData); protected: diff --git a/simgear/scene/model/SGReaderWriterXML.cxx b/simgear/scene/model/SGReaderWriterXML.cxx index bbbade47..e46e6921 100644 --- a/simgear/scene/model/SGReaderWriterXML.cxx +++ b/simgear/scene/model/SGReaderWriterXML.cxx @@ -266,7 +266,7 @@ sgLoad3DModel_internal(const SGPath& path, osg::ref_ptr options; options = SGReaderWriterOptions::copyOrCreate(dbOptions); - + SGPath modelpath(path); SGPath texturepath(path); SGPath modelDir(modelpath.dir()); @@ -525,6 +525,8 @@ sgLoad3DModel_internal(const SGPath& path, group = static_cast(modelWithEffects.get()); } + simgear::SGTransientModelData modelData(group.get(), prop_root, options.get(), path.local8BitStr()); + for (unsigned i = 0; i < animation_nodes.size(); ++i) { if (previewMode && animation_nodes[i]->hasChild("nopreview")) { PropertyList names(animation_nodes[i]->getChildren("object-name")); @@ -533,10 +535,13 @@ sgLoad3DModel_internal(const SGPath& path, } // of object-names in the animation continue; } - + /* + * Setup the model data for the node currently being animated. + */ + modelData.LoadAnimationValuesForElement(animation_nodes[i], i); + /// OSGFIXME: duh, why not only model????? - SGAnimation::animate(group.get(), animation_nodes[i], prop_root, - options.get(), path.local8BitStr(), i); + SGAnimation::animate(modelData); } if (!needTransform && group->getNumChildren() < 2) { diff --git a/simgear/scene/model/SGTrackToAnimation.cxx b/simgear/scene/model/SGTrackToAnimation.cxx index f01fe691..2705a566 100644 --- a/simgear/scene/model/SGTrackToAnimation.cxx +++ b/simgear/scene/model/SGTrackToAnimation.cxx @@ -373,25 +373,23 @@ class SGTrackToAnimation::UpdateCallback: }; //------------------------------------------------------------------------------ -SGTrackToAnimation::SGTrackToAnimation( osg::Node* node, - const SGPropertyNode* configNode, - SGPropertyNode* modelRoot ): - SGAnimation(configNode, modelRoot), +SGTrackToAnimation::SGTrackToAnimation(simgear::SGTransientModelData &modelData): + SGAnimation(modelData), _target_group(0), _slave_group(0) { - std::string target = configNode->getStringValue("target-name"); + std::string target = modelData.getConfigNode()->getStringValue("target-name"); FindGroupVisitor target_finder(target); - node->accept(target_finder); + modelData.getNode()->accept(target_finder); if( !(_target_group = target_finder.getGroup()) ) log(SG_ALERT, "target not found: '" + target + '\''); - std::string slave = configNode->getStringValue("slave-name"); + std::string slave = modelData.getConfigNode()->getStringValue("slave-name"); if( !slave.empty() ) { FindGroupVisitor slave_finder(slave); - node->accept(slave_finder); + modelData.getNode()->accept(slave_finder); _slave_group = slave_finder.getGroup(); } } diff --git a/simgear/scene/model/SGTrackToAnimation.hxx b/simgear/scene/model/SGTrackToAnimation.hxx index 96445dec..d61b4533 100644 --- a/simgear/scene/model/SGTrackToAnimation.hxx +++ b/simgear/scene/model/SGTrackToAnimation.hxx @@ -34,9 +34,7 @@ class SGTrackToAnimation: public SGAnimation { public: - SGTrackToAnimation( osg::Node* node, - const SGPropertyNode* configNode, - SGPropertyNode* modelRoot ); + SGTrackToAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); diff --git a/simgear/scene/model/animation.cxx b/simgear/scene/model/animation.cxx index 7bb6cf45..7f5cf327 100644 --- a/simgear/scene/model/animation.cxx +++ b/simgear/scene/model/animation.cxx @@ -34,6 +34,10 @@ #include #include #include +#include + +#include +#include #include #include @@ -46,6 +50,8 @@ #include #include #include +#include +#include #include "vg/vgu.h" @@ -71,6 +77,99 @@ using namespace simgear; // Static utility functions. //////////////////////////////////////////////////////////////////////// + +/* + * collect line segments from nodes within the hierarchy. +*/ +class LineCollector : public osg::NodeVisitor { + struct LineCollector_LinePrimitiveFunctor { + LineCollector_LinePrimitiveFunctor() : _lineCollector(0) { } + void operator() (const osg::Vec3&, bool) { } + void operator() (const osg::Vec3& v1, const osg::Vec3& v2, bool) + { + if (_lineCollector) _lineCollector->addLine(v1, v2); + } + void operator() (const osg::Vec3&, const osg::Vec3&, const osg::Vec3&, bool) { } + void operator() (const osg::Vec3&, const osg::Vec3&, const osg::Vec3&, const osg::Vec3&, bool) { } + LineCollector* _lineCollector; + }; + +public: + LineCollector() : osg::NodeVisitor(osg::NodeVisitor::NODE_VISITOR, osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) { } + + virtual void apply(osg::Geode& geode) + { + osg::TemplatePrimitiveFunctor pf; + pf._lineCollector = this; + for (unsigned i = 0; i < geode.getNumDrawables(); ++i) { + geode.getDrawable(i)->accept(pf); + } + } + + virtual void apply(osg::Node& node) + { + traverse(node); + } + + virtual void apply(osg::Transform& transform) + { + osg::Matrix matrix = _matrix; + if (transform.computeLocalToWorldMatrix(_matrix, this)) + traverse(transform); + _matrix = matrix; + } + + const std::vector& getLineSegments() const + { + return _lineSegments; + } + + void addLine(const osg::Vec3& v1, const osg::Vec3& v2) + { + // Trick to get the ends in the right order. + // Use the x axis in the original coordinate system. Choose the + // most negative x-axis as the one pointing forward + SGVec3f tv1(toSG(_matrix.preMult(v1))); + SGVec3f tv2(toSG(_matrix.preMult(v2))); + if (tv1[0] > tv2[0]) + _lineSegments.push_back(SGLineSegmentf(tv1, tv2)); + else + _lineSegments.push_back(SGLineSegmentf(tv2, tv1)); + } + + void addBVHElements(osg::Node& node, simgear::BVHLineGeometry::Type type) + { + if (_lineSegments.empty()) + return; + + SGSceneUserData* userData; + userData = SGSceneUserData::getOrCreateSceneUserData(&node); + + simgear::BVHNode* bvNode = userData->getBVHNode(); + if (!bvNode && _lineSegments.size() == 1) { + simgear::BVHLineGeometry* bvLine; + bvLine = new simgear::BVHLineGeometry(_lineSegments.front(), type); + userData->setBVHNode(bvLine); + return; + } + + simgear::BVHGroup* group = new simgear::BVHGroup; + if (bvNode) + group->addChild(bvNode); + + for (unsigned i = 0; i < _lineSegments.size(); ++i) { + simgear::BVHLineGeometry* bvLine; + bvLine = new simgear::BVHLineGeometry(_lineSegments[i], type); + group->addChild(bvLine); + } + userData->setBVHNode(group); + } + +private: + osg::Matrix _matrix; + std::vector _lineSegments; +}; + /** * Set up the transform matrix for a translation. */ @@ -325,17 +424,16 @@ struct DoDrawArraysVisitor : public osg::NodeVisitor { }; } -SGAnimation::SGAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : +SGAnimation::SGAnimation(simgear::SGTransientModelData &modelData) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _found(false), - _configNode(configNode), - _modelRoot(modelRoot) + _configNode(modelData.getConfigNode()), + _modelRoot(modelData.getModelRoot()) { - _name = configNode->getStringValue("name", ""); - _enableHOT = configNode->getBoolValue("enable-hot", true); + _name = modelData.getConfigNode()->getStringValue("name", ""); + _enableHOT = modelData.getConfigNode()->getBoolValue("enable-hot", true); std::vector objectNames = - configNode->getChildren("object-name"); + modelData.getConfigNode()->getChildren("object-name"); for (unsigned i = 0; i < objectNames.size(); ++i) _objectNames.push_back(objectNames[i]->getStringValue()); } @@ -363,79 +461,76 @@ SGAnimation::~SGAnimation() } bool -SGAnimation::animate(osg::Node* node, const SGPropertyNode* configNode, - SGPropertyNode* modelRoot, - const osgDB::Options* options, - const std::string &path, int i) +SGAnimation::animate(simgear::SGTransientModelData &modelData) { - std::string type = configNode->getStringValue("type", "none"); + std::string type = modelData.getConfigNode()->getStringValue("type", "none"); if (type == "alpha-test") { - SGAlphaTestAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGAlphaTestAnimation anim(modelData); + anim.apply(modelData); } else if (type == "billboard") { - SGBillboardAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGBillboardAnimation anim(modelData); + anim.apply(modelData); } else if (type == "blend") { - SGBlendAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGBlendAnimation anim(modelData); + anim.apply(modelData); } else if (type == "dist-scale") { - SGDistScaleAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGDistScaleAnimation anim(modelData); + anim.apply(modelData); } else if (type == "flash") { - SGFlashAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGFlashAnimation anim(modelData); + anim.apply(modelData); } else if (type == "interaction") { - SGInteractionAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGInteractionAnimation anim(modelData); + anim.apply(modelData); } else if (type == "material") { - SGMaterialAnimation animInst(configNode, modelRoot, options, path); - animInst.apply(node); + SGMaterialAnimation anim(modelData); + anim.apply(modelData); } else if (type == "noshadow") { - SGShadowAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGShadowAnimation anim(modelData); + anim.apply(modelData); } else if (type == "pick") { - SGPickAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGPickAnimation anim(modelData); + anim.apply(modelData); } else if (type == "knob") { - SGKnobAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGKnobAnimation anim(modelData); + anim.apply(modelData); } else if (type == "slider") { - SGSliderAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGSliderAnimation anim(modelData); + anim.apply(modelData); } else if (type == "range") { - SGRangeAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGRangeAnimation anim(modelData); + anim.apply(modelData); } else if (type == "rotate" || type == "spin") { - SGRotateAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGRotateAnimation anim(modelData); + anim.apply(modelData); } else if (type == "scale") { - SGScaleAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGScaleAnimation anim(modelData); + anim.apply(modelData); } else if (type == "select") { - SGSelectAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGSelectAnimation anim(modelData); + anim.apply(modelData); } else if (type == "shader") { - SGShaderAnimation animInst(configNode, modelRoot, options); - animInst.apply(node); + SGShaderAnimation anim(modelData); + anim.apply(modelData); } else if (type == "textranslate" || type == "texrotate" || type == "textrapezoid" || type == "texmultiple") { - SGTexTransformAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGTexTransformAnimation anim(modelData); + anim.apply(modelData); } else if (type == "timed") { - SGTimedAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGTimedAnimation anim(modelData); + anim.apply(modelData); } else if (type == "locked-track") { - SGTrackToAnimation animInst(node, configNode, modelRoot); - animInst.apply(node); + SGTrackToAnimation anim(modelData); + anim.apply(modelData); } else if (type == "translate") { - SGTranslateAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGTranslateAnimation anim(modelData); + anim.apply(modelData); } else if (type == "light") { - SGLightAnimation animInst(configNode, modelRoot, options, path, i); - animInst.apply(node); + SGLightAnimation anim(modelData); + anim.apply(modelData); } else if (type == "null" || type == "none" || type.empty()) { - SGGroupAnimation animInst(configNode, modelRoot); - animInst.apply(node); + SGGroupAnimation anim(modelData); + anim.apply(modelData); } else return false; @@ -479,19 +574,25 @@ SGAnimation::createAnimationGroup(osg::Group& parent) void SGAnimation::apply(osg::Group& group) { - // the trick is to first traverse the children and then - // possibly splice in a new group node if required. - // Else we end up in a recursive loop where we infinitly insert new - // groups in between - traverse(group); + // the trick is to first traverse the children and then + // possibly splice in a new group node if required. + // Else we end up in a recursive loop where we infinitly insert new + // groups in between + traverse(group); - // Note that this algorithm preserves the order of the child objects - // like they appear in the object-name tags. - // The timed animations require this - osg::ref_ptr animationGroup; - std::list::const_iterator nameIt; - for (nameIt = _objectNames.begin(); nameIt != _objectNames.end(); ++nameIt) - installInGroup(*nameIt, group, animationGroup); + // Note that this algorithm preserves the order of the child objects + // like they appear in the object-name tags. + // The timed animations require this + osg::ref_ptr animationGroup; + std::list::const_iterator nameIt; + for (nameIt = _objectNames.begin(); nameIt != _objectNames.end(); ++nameIt) + installInGroup(*nameIt, group, animationGroup); +} + +void +SGAnimation::apply(simgear::SGTransientModelData &modelData) +{ + apply(modelData.getNode()); } void @@ -553,13 +654,138 @@ SGVec3d SGAnimation::readVec3( const std::string& name, { return readVec3(*_configNode, name, suffix, def); } +/** +* Visitor to find a group by its name. +*/ +class FindGroupVisitor : + public osg::NodeVisitor +{ +public: + FindGroupVisitor(const std::string& name) : + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), + _name(name), + _group(0) + { + if (name.empty()) + SG_LOG(SG_IO, SG_WARN, "FindGroupVisitor: empty name provided"); + } + + osg::Group* getGroup() const + { + return _group; + } + + virtual void apply(osg::Group& group) + { + if (_name != group.getName()) + return traverse(group); + + if (!_group) + _group = &group; + + // Different paths can exists for example with a picking animation (pick + // render group) + else if (_group != &group) + SG_LOG + ( + SG_IO, + SG_WARN, + "FindGroupVisitor: name not unique '" << _name << "'" + ); + } + +protected: + + std::string _name; + osg::Group *_group; +}; + +/* + * If an object is specified in the axis tag it is assumed to be a single line segment with two vertices. + * This function will take action when axis has an object-name tag and the corresponding object + * can be found within the hierarchy. + */ +bool SGAnimation::setCenterAndAxisFromObject(osg::Node *rootNode, SGVec3d& center, SGVec3d &axis, simgear::SGTransientModelData &modelData) const +{ + if (_configNode->hasValue("axis/object-name")) + { + std::string axis_object_name = _configNode->getStringValue("axis/object-name"); + + if (!axis_object_name.empty()) + { + /* + * First search the currently loaded cache map to see if this axis object has already been located. + * If we find it, we use it. + */ + const SGLineSegment *axisSegment = modelData.getAxisDefinition(axis_object_name); + if (!axisSegment) + { + /* + * Find the object by name + */ + FindGroupVisitor axis_object_name_finder(axis_object_name); + rootNode->accept(axis_object_name_finder); + osg::Group *object_group = axis_object_name_finder.getGroup(); + + if (object_group) + { + /* + * we have found the object group (for the axis). This should be two vertices + * Now process this (with the line collector) to get the vertices. + * Once we have that we can then calculate the center and the affected axes. + */ + object_group->setNodeMask(0xffffffff); + LineCollector lineCollector; + object_group->accept(lineCollector); + std::vector segs = lineCollector.getLineSegments(); + + if (!segs.empty()) + { + /* + * Store the axis definition in the map; as once hidden it will not be possible + * to locate it again (and in any case it will be quicker to do it this way) + * This makes the axis/center static; there could be a use case for making this + * dynamic (and rebuilding the transforms), in which case this would need to + * do something different with the object; possibly storing a reference to the node + * so it can be extracted for dynamic processing. + */ + SGLineSegmentd segd(*(segs.begin())); + axisSegment = modelData.addAxisDefinition(axis_object_name,segd); + /* + * Hide the axis object. This also helps the modeller to know which axis animations are unassigned. + */ + object_group->setNodeMask(0); + } + else + SG_LOG(SG_INPUT, SG_ALERT, "Could find a valid line segment for animation: " << axis_object_name); + } + else + SG_LOG(SG_INPUT, SG_ALERT, "Could not find at least one of the following objects for axis animation: " << axis_object_name); + } + if (axisSegment) + { + center = 0.5*(axisSegment->getStart() + axisSegment->getEnd()); + axis = axisSegment->getEnd() - axisSegment->getStart(); + return true; + } + } + } + return false; +} //------------------------------------------------------------------------------ // factored out to share with SGKnobAnimation -void SGAnimation::readRotationCenterAndAxis( SGVec3d& center, - SGVec3d& axis ) const +void SGAnimation::readRotationCenterAndAxis(osg::Node *_rootNode, SGVec3d& center, + SGVec3d& axis, simgear::SGTransientModelData &modelData) const { center = SGVec3d::zeros(); + if (setCenterAndAxisFromObject(_rootNode, center, axis, modelData)) + { + if (8 * SGLimitsd::min() < norm(axis)) + axis = normalize(axis); + return; + } + if( _configNode->hasValue("axis/x1-m") ) { SGVec3d v1 = readVec3("axis", "1-m"), // axis/[xyz]1-m @@ -663,9 +889,8 @@ SGAnimation::getCondition() const // Ok, that is to build a subgraph from different other // graph nodes. I guess that this stems from the time where modellers // could not build hierarchical trees ... -SGGroupAnimation::SGGroupAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot): - SGAnimation(configNode, modelRoot) +SGGroupAnimation::SGGroupAnimation(simgear::SGTransientModelData &modelData): + SGAnimation(modelData) { } @@ -705,13 +930,12 @@ public: SGSharedPtr _animationValue; }; -SGTranslateAnimation::SGTranslateAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - SGAnimation(configNode, modelRoot) +SGTranslateAnimation::SGTranslateAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData) { _condition = getCondition(); SGSharedPtr value; - value = read_value(configNode, modelRoot, "-m", + value = read_value(modelData.getConfigNode(), modelData.getModelRoot(), "-m", -SGLimitsd::max(), SGLimitsd::max()); _animationValue = value->simplify(); if (_animationValue) @@ -719,7 +943,9 @@ SGTranslateAnimation::SGTranslateAnimation(const SGPropertyNode* configNode, else _initialValue = 0; - _axis = readTranslateAxis(configNode); + SGVec3d _center; + if (modelData.getNode() && !setCenterAndAxisFromObject(modelData.getNode(), _center, _axis, modelData)) + _axis = readTranslateAxis(modelData.getConfigNode()); } osg::Group* @@ -932,16 +1158,15 @@ SGVec3d readTranslateAxis(const SGPropertyNode* configNode) return axis; } -SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - SGAnimation(configNode, modelRoot) +SGRotateAnimation::SGRotateAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData) { - std::string type = configNode->getStringValue("type", ""); + std::string type = modelData.getConfigNode()->getStringValue("type", ""); _isSpin = (type == "spin"); _condition = getCondition(); SGSharedPtr value; - value = read_value(configNode, modelRoot, "-deg", + value = read_value(modelData.getConfigNode(), modelData.getModelRoot(), "-deg", -SGLimitsd::max(), SGLimitsd::max()); _animationValue = value->simplify(); if (_animationValue) @@ -949,7 +1174,7 @@ SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode, else _initialValue = 0; - readRotationCenterAndAxis(_center, _axis); + readRotationCenterAndAxis(modelData.getNode(), _center, _axis, modelData); } osg::Group* @@ -1012,92 +1237,91 @@ public: SGSharedPtr _animationValue[3]; }; -SGScaleAnimation::SGScaleAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - SGAnimation(configNode, modelRoot) +SGScaleAnimation::SGScaleAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData) { _condition = getCondition(); // default offset/factor for all directions - double offset = configNode->getDoubleValue("offset", 0); - double factor = configNode->getDoubleValue("factor", 1); + double offset = modelData.getConfigNode()->getDoubleValue("offset", 0); + double factor = modelData.getConfigNode()->getDoubleValue("factor", 1); SGSharedPtr inPropExpr; std::string inputPropertyName; - inputPropertyName = configNode->getStringValue("property", ""); + inputPropertyName = modelData.getConfigNode()->getStringValue("property", ""); if (inputPropertyName.empty()) { inPropExpr = new SGConstExpression(0); } else { SGPropertyNode* inputProperty; - inputProperty = modelRoot->getNode(inputPropertyName, true); + inputProperty = modelData.getModelRoot()->getNode(inputPropertyName, true); inPropExpr = new SGPropertyExpression(inputProperty); } - SGInterpTable* interpTable = read_interpolation_table(configNode); + SGInterpTable* interpTable = read_interpolation_table(modelData.getConfigNode()); if (interpTable) { SGSharedPtr value; value = new SGInterpTableExpression(inPropExpr, interpTable); _animationValue[0] = value->simplify(); _animationValue[1] = value->simplify(); _animationValue[2] = value->simplify(); - } else if (configNode->getBoolValue("use-personality", false)) { + } else if (modelData.getConfigNode()->getBoolValue("use-personality", false)) { SGSharedPtr value; - value = new SGPersonalityScaleOffsetExpression(inPropExpr, configNode, + value = new SGPersonalityScaleOffsetExpression(inPropExpr, modelData.getConfigNode(), "x-factor", "x-offset", factor, offset); - double minClip = configNode->getDoubleValue("x-min", 0); - double maxClip = configNode->getDoubleValue("x-max", SGLimitsd::max()); + double minClip = modelData.getConfigNode()->getDoubleValue("x-min", 0); + double maxClip = modelData.getConfigNode()->getDoubleValue("x-max", SGLimitsd::max()); value = new SGClipExpression(value, minClip, maxClip); _animationValue[0] = value->simplify(); - value = new SGPersonalityScaleOffsetExpression(inPropExpr, configNode, + value = new SGPersonalityScaleOffsetExpression(inPropExpr, modelData.getConfigNode(), "y-factor", "y-offset", factor, offset); - minClip = configNode->getDoubleValue("y-min", 0); - maxClip = configNode->getDoubleValue("y-max", SGLimitsd::max()); + minClip = modelData.getConfigNode()->getDoubleValue("y-min", 0); + maxClip = modelData.getConfigNode()->getDoubleValue("y-max", SGLimitsd::max()); value = new SGClipExpression(value, minClip, maxClip); _animationValue[1] = value->simplify(); - value = new SGPersonalityScaleOffsetExpression(inPropExpr, configNode, + value = new SGPersonalityScaleOffsetExpression(inPropExpr, modelData.getConfigNode(), "z-factor", "z-offset", factor, offset); - minClip = configNode->getDoubleValue("z-min", 0); - maxClip = configNode->getDoubleValue("z-max", SGLimitsd::max()); + minClip = modelData.getConfigNode()->getDoubleValue("z-min", 0); + maxClip = modelData.getConfigNode()->getDoubleValue("z-max", SGLimitsd::max()); value = new SGClipExpression(value, minClip, maxClip); _animationValue[2] = value->simplify(); } else { SGSharedPtr value; - value = read_factor_offset(configNode, inPropExpr, "x-factor", "x-offset"); - double minClip = configNode->getDoubleValue("x-min", 0); - double maxClip = configNode->getDoubleValue("x-max", SGLimitsd::max()); + value = read_factor_offset(modelData.getConfigNode(), inPropExpr, "x-factor", "x-offset"); + double minClip = modelData.getConfigNode()->getDoubleValue("x-min", 0); + double maxClip = modelData.getConfigNode()->getDoubleValue("x-max", SGLimitsd::max()); value = new SGClipExpression(value, minClip, maxClip); _animationValue[0] = value->simplify(); - value = read_factor_offset(configNode, inPropExpr, "y-factor", "y-offset"); - minClip = configNode->getDoubleValue("y-min", 0); - maxClip = configNode->getDoubleValue("y-max", SGLimitsd::max()); + value = read_factor_offset(modelData.getConfigNode(), inPropExpr, "y-factor", "y-offset"); + minClip = modelData.getConfigNode()->getDoubleValue("y-min", 0); + maxClip = modelData.getConfigNode()->getDoubleValue("y-max", SGLimitsd::max()); value = new SGClipExpression(value, minClip, maxClip); _animationValue[1] = value->simplify(); - value = read_factor_offset(configNode, inPropExpr, "z-factor", "z-offset"); - minClip = configNode->getDoubleValue("z-min", 0); - maxClip = configNode->getDoubleValue("z-max", SGLimitsd::max()); + value = read_factor_offset(modelData.getConfigNode(), inPropExpr, "z-factor", "z-offset"); + minClip = modelData.getConfigNode()->getDoubleValue("z-min", 0); + maxClip = modelData.getConfigNode()->getDoubleValue("z-max", SGLimitsd::max()); value = new SGClipExpression(value, minClip, maxClip); _animationValue[2] = value->simplify(); } - _initialValue[0] = configNode->getDoubleValue("x-starting-scale", 1); - _initialValue[0] *= configNode->getDoubleValue("x-factor", factor); - _initialValue[0] += configNode->getDoubleValue("x-offset", offset); - _initialValue[1] = configNode->getDoubleValue("y-starting-scale", 1); - _initialValue[1] *= configNode->getDoubleValue("y-factor", factor); - _initialValue[1] += configNode->getDoubleValue("y-offset", offset); - _initialValue[2] = configNode->getDoubleValue("z-starting-scale", 1); - _initialValue[2] *= configNode->getDoubleValue("z-factor", factor); - _initialValue[2] += configNode->getDoubleValue("z-offset", offset); - _center[0] = configNode->getDoubleValue("center/x-m", 0); - _center[1] = configNode->getDoubleValue("center/y-m", 0); - _center[2] = configNode->getDoubleValue("center/z-m", 0); + _initialValue[0] = modelData.getConfigNode()->getDoubleValue("x-starting-scale", 1); + _initialValue[0] *= modelData.getConfigNode()->getDoubleValue("x-factor", factor); + _initialValue[0] += modelData.getConfigNode()->getDoubleValue("x-offset", offset); + _initialValue[1] = modelData.getConfigNode()->getDoubleValue("y-starting-scale", 1); + _initialValue[1] *= modelData.getConfigNode()->getDoubleValue("y-factor", factor); + _initialValue[1] += modelData.getConfigNode()->getDoubleValue("y-offset", offset); + _initialValue[2] = modelData.getConfigNode()->getDoubleValue("z-starting-scale", 1); + _initialValue[2] *= modelData.getConfigNode()->getDoubleValue("z-factor", factor); + _initialValue[2] += modelData.getConfigNode()->getDoubleValue("z-offset", offset); + _center[0] = modelData.getConfigNode()->getDoubleValue("center/x-m", 0); + _center[1] = modelData.getConfigNode()->getDoubleValue("center/y-m", 0); + _center[2] = modelData.getConfigNode()->getDoubleValue("center/z-m", 0); } osg::Group* @@ -1234,9 +1458,8 @@ private: }; -SGDistScaleAnimation::SGDistScaleAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - SGAnimation(configNode, modelRoot) +SGDistScaleAnimation::SGDistScaleAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData) { } @@ -1390,9 +1613,8 @@ private: }; -SGFlashAnimation::SGFlashAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - SGAnimation(configNode, modelRoot) +SGFlashAnimation::SGFlashAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData) { } @@ -1475,9 +1697,8 @@ private: }; -SGBillboardAnimation::SGBillboardAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - SGAnimation(configNode, modelRoot) +SGBillboardAnimation::SGBillboardAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData) { } @@ -1548,39 +1769,38 @@ private: double _maxStaticValue; }; -SGRangeAnimation::SGRangeAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - SGAnimation(configNode, modelRoot) +SGRangeAnimation::SGRangeAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData) { _condition = getCondition(); std::string inputPropertyName; - inputPropertyName = configNode->getStringValue("min-property", ""); + inputPropertyName = modelData.getConfigNode()->getStringValue("min-property", ""); if (!inputPropertyName.empty()) { SGPropertyNode* inputProperty; - inputProperty = modelRoot->getNode(inputPropertyName, true); + inputProperty = modelData.getModelRoot()->getNode(inputPropertyName, true); SGSharedPtr value; value = new SGPropertyExpression(inputProperty); - value = read_factor_offset(configNode, value, "min-factor", "min-offset"); + value = read_factor_offset(modelData.getConfigNode(), value, "min-factor", "min-offset"); _minAnimationValue = value->simplify(); } - inputPropertyName = configNode->getStringValue("max-property", ""); + inputPropertyName = modelData.getConfigNode()->getStringValue("max-property", ""); if (!inputPropertyName.empty()) { SGPropertyNode* inputProperty; - inputProperty = modelRoot->getNode(inputPropertyName.c_str(), true); + inputProperty = modelData.getModelRoot()->getNode(inputPropertyName.c_str(), true); SGSharedPtr value; value = new SGPropertyExpression(inputProperty); - value = read_factor_offset(configNode, value, "max-factor", "max-offset"); + value = read_factor_offset(modelData.getConfigNode(), value, "max-factor", "max-offset"); _maxAnimationValue = value->simplify(); } - _initialValue[0] = configNode->getDoubleValue("min-m", 0); - _initialValue[0] *= configNode->getDoubleValue("min-factor", 1); - _initialValue[1] = configNode->getDoubleValue("max-m", SGLimitsf::max()); - _initialValue[1] *= configNode->getDoubleValue("max-factor", 1); + _initialValue[0] = modelData.getConfigNode()->getDoubleValue("min-m", 0); + _initialValue[0] *= modelData.getConfigNode()->getDoubleValue("min-factor", 1); + _initialValue[1] = modelData.getConfigNode()->getDoubleValue("max-m", SGLimitsf::max()); + _initialValue[1] *= modelData.getConfigNode()->getDoubleValue("max-factor", 1); } osg::Group* @@ -1610,9 +1830,8 @@ SGRangeAnimation::createAnimationGroup(osg::Group& parent) // Implementation of a select animation //////////////////////////////////////////////////////////////////////// -SGSelectAnimation::SGSelectAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - SGAnimation(configNode, modelRoot) +SGSelectAnimation::SGSelectAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData) { } @@ -1640,9 +1859,8 @@ SGSelectAnimation::createAnimationGroup(osg::Group& parent) // Implementation of alpha test animation //////////////////////////////////////////////////////////////////////// -SGAlphaTestAnimation::SGAlphaTestAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - SGAnimation(configNode, modelRoot) +SGAlphaTestAnimation::SGAlphaTestAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData) { } @@ -1793,10 +2011,8 @@ public: }; -SGBlendAnimation::SGBlendAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) - : SGAnimation(configNode, modelRoot), - _animationValue(read_value(configNode, modelRoot, "", 0, 1)) +SGBlendAnimation::SGBlendAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData), _animationValue(read_value(modelData.getConfigNode(), modelData.getModelRoot(), "", 0, 1)) { } @@ -1919,9 +2135,8 @@ private: }; -SGTimedAnimation::SGTimedAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) - : SGAnimation(configNode, modelRoot) +SGTimedAnimation::SGTimedAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData) { } @@ -1960,9 +2175,8 @@ private: SGSharedPtr _condition; }; -SGShadowAnimation::SGShadowAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - SGAnimation(configNode, modelRoot) +SGShadowAnimation::SGShadowAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData) { } @@ -2130,9 +2344,8 @@ private: osg::Matrix _matrix; }; -SGTexTransformAnimation::SGTexTransformAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - SGAnimation(configNode, modelRoot) +SGTexTransformAnimation::SGTexTransformAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData) { } diff --git a/simgear/scene/model/animation.hxx b/simgear/scene/model/animation.hxx index 1a093247..e00db1ad 100644 --- a/simgear/scene/model/animation.hxx +++ b/simgear/scene/model/animation.hxx @@ -22,6 +22,7 @@ #include #include #include +#include // Has anyone done anything *really* stupid, like making min and max macros? #ifdef min @@ -42,21 +43,19 @@ SGVec3d readTranslateAxis(const SGPropertyNode* configNode); */ class SGAnimation : protected osg::NodeVisitor { public: - SGAnimation(const SGPropertyNode* configNode, SGPropertyNode* modelRoot); + SGAnimation(simgear::SGTransientModelData &modelData); virtual ~SGAnimation(); - static bool animate(osg::Node* node, const SGPropertyNode* configNode, - SGPropertyNode* modelRoot, - const osgDB::Options* options, - const std::string &path, int i); + static bool animate(simgear::SGTransientModelData &modelData); protected: void apply(osg::Node* node); + virtual void apply(osg::Group& group); virtual void install(osg::Node& node); virtual osg::Group* createAnimationGroup(osg::Group& parent); - virtual void apply(osg::Group& group); + virtual void apply(simgear::SGTransientModelData &modelData); /** * Read a 3d vector from the configuration property node. @@ -77,7 +76,8 @@ protected: const std::string& suffix = "", const SGVec3d& def = SGVec3d::zeros() ) const; - void readRotationCenterAndAxis(SGVec3d& center, SGVec3d& axis) const; + void readRotationCenterAndAxis(osg::Node *rootNode, SGVec3d& center, SGVec3d& axis, simgear::SGTransientModelData &modelData) const; + bool setCenterAndAxisFromObject(osg::Node *rootNode, SGVec3d& center, SGVec3d &axis, simgear::SGTransientModelData &modelData) const; SGExpressiond* readOffsetValue(const char* tag_name) const; @@ -128,7 +128,7 @@ private: class SGGroupAnimation : public SGAnimation { public: - SGGroupAnimation(const SGPropertyNode*, SGPropertyNode*); + SGGroupAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); }; @@ -139,8 +139,7 @@ public: class SGTranslateAnimation : public SGAnimation { public: - SGTranslateAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGTranslateAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); private: class UpdateCallback; @@ -157,8 +156,7 @@ private: class SGRotateAnimation : public SGAnimation { public: - SGRotateAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGRotateAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); private: SGSharedPtr _condition; @@ -176,8 +174,7 @@ private: class SGScaleAnimation : public SGAnimation { public: - SGScaleAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGScaleAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); private: class UpdateCallback; @@ -194,8 +191,7 @@ private: class SGDistScaleAnimation : public SGAnimation { public: - SGDistScaleAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGDistScaleAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); class Transform; }; @@ -207,8 +203,7 @@ public: class SGFlashAnimation : public SGAnimation { public: - SGFlashAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGFlashAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); public: class Transform; @@ -221,8 +216,7 @@ public: class SGBillboardAnimation : public SGAnimation { public: - SGBillboardAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGBillboardAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); class Transform; }; @@ -234,8 +228,7 @@ public: class SGRangeAnimation : public SGAnimation { public: - SGRangeAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGRangeAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); private: class UpdateCallback; @@ -252,8 +245,7 @@ private: class SGSelectAnimation : public SGAnimation { public: - SGSelectAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGSelectAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); }; @@ -264,8 +256,7 @@ public: class SGAlphaTestAnimation : public SGAnimation { public: - SGAlphaTestAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGAlphaTestAnimation(simgear::SGTransientModelData &modelData); virtual void install(osg::Node& node); }; @@ -276,8 +267,7 @@ public: class SGBlendAnimation : public SGAnimation { public: - SGBlendAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGBlendAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); virtual void install(osg::Node& node); private: @@ -293,8 +283,7 @@ private: class SGTimedAnimation : public SGAnimation { public: - SGTimedAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGTimedAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); private: class UpdateCallback; @@ -307,8 +296,7 @@ private: class SGShadowAnimation : public SGAnimation { public: - SGShadowAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGShadowAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); private: class UpdateCallback; @@ -321,8 +309,7 @@ private: class SGTexTransformAnimation : public SGAnimation { public: - SGTexTransformAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); + SGTexTransformAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); private: class Transform; @@ -349,9 +336,7 @@ private: class SGShaderAnimation : public SGAnimation { public: - SGShaderAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot, - const osgDB::Options* options); + SGShaderAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); private: class UpdateCallback; @@ -364,10 +349,7 @@ private: class SGLightAnimation : public SGAnimation { public: - SGLightAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot, - const osgDB::Options* options, - const std::string &path, int i); + SGLightAnimation(simgear::SGTransientModelData &modelData); virtual osg::Group* createAnimationGroup(osg::Group& parent); virtual void install(osg::Node& node); private: diff --git a/simgear/scene/model/shadanim.cxx b/simgear/scene/model/shadanim.cxx index ea1f1c26..f53b244e 100644 --- a/simgear/scene/model/shadanim.cxx +++ b/simgear/scene/model/shadanim.cxx @@ -185,15 +185,12 @@ static void create_specular_highlights(osg::Node *node) #endif -SGShaderAnimation::SGShaderAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot, - const osgDB::Options* - options) : - SGAnimation(configNode, modelRoot) +SGShaderAnimation::SGShaderAnimation(simgear::SGTransientModelData &modelData) : + SGAnimation(modelData) { - const SGPropertyNode* node = configNode->getChild("texture"); + const SGPropertyNode* node = modelData.getConfigNode()->getChild("texture"); if (node) - _effect_texture = SGLoadTexture2D(node->getStringValue(), options); + _effect_texture = SGLoadTexture2D(node->getStringValue(), modelData.getOptions()); } namespace { diff --git a/simgear/scene/util/CMakeLists.txt b/simgear/scene/util/CMakeLists.txt index 9dec4115..dd135077 100644 --- a/simgear/scene/util/CMakeLists.txt +++ b/simgear/scene/util/CMakeLists.txt @@ -23,6 +23,7 @@ set(HEADERS SGSceneUserData.hxx SGStateAttributeVisitor.hxx SGTextureStateAttributeVisitor.hxx + SGTransientModelData.hxx SGUpdateVisitor.hxx SplicingVisitor.hxx StateAttributeFactory.hxx diff --git a/simgear/scene/util/SGReaderWriterOptions.hxx b/simgear/scene/util/SGReaderWriterOptions.hxx index 10e12732..2760df90 100644 --- a/simgear/scene/util/SGReaderWriterOptions.hxx +++ b/simgear/scene/util/SGReaderWriterOptions.hxx @@ -151,6 +151,7 @@ private: osg::Node *(*_load_panel)(SGPropertyNode *); osg::ref_ptr _model_data; + bool _instantiateEffects; bool _instantiateMaterialEffects; string _materialName; diff --git a/simgear/scene/util/SGTransientModelData.hxx b/simgear/scene/util/SGTransientModelData.hxx new file mode 100644 index 00000000..678edfed --- /dev/null +++ b/simgear/scene/util/SGTransientModelData.hxx @@ -0,0 +1,98 @@ +// Copyright (C) 2017 Richard Harrison rjh@zaretto.com +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef SGTRANSIENTMODELDATA_HXX +#define SGTRANSIENTMODELDATA_HXX 1 +#include + +namespace simgear +{ + typedef std::map> SGAxisDefinitionMap; + + /* + * Transient data that is used with a given context for any given model. + * Currently used during the model load to provide a consistent set of data when creating the animations. + * - provides a map to allow reuse of axis definitions + * Expected possible future expansion for improvements to model light animations. + * - typical usage for the SGAnimation::animate() call would be to create one of these like this + * simgear::SGTransientModelData modelData(group.get(), prop_root, options.get(), path.local8BitStr()); + * This will create the basic transient model data that doesn't change between invocations of animate() + * then to adapt the model data for an animation element use the LoadAnimationValuesForElement method, e.g. + * modelData.LoadAnimationValuesForElement(animation_nodes[i], i); + */ + class SGTransientModelData { + public: + // fully specified constructor. Probably not relevant as creating an object this specified implies setting up for an individual animation element, which will preclude + // the use of the axis definition cache between objects. + SGTransientModelData(osg::Node* _node, const SGPropertyNode* _configNode, SGPropertyNode* _modelRoot, osgDB::Options* _options, const std::string &_path, int _i) + : node(_node), configNode(_configNode), modelRoot(_modelRoot), options(_options), path(_path), index(_i) + {} + // usual form of construction - setup the elements that are constant, and specify the config node and index via LoadAnimationValuesForElement + SGTransientModelData(osg::Node* _node, SGPropertyNode* _modelRoot, osgDB::Options* _options, const std::string &_path) + : node(_node), configNode(nullptr), modelRoot(_modelRoot), options(_options), path(_path), index(0) + {} + + /* + * Loads the animation values required for a specific element. + */ + void LoadAnimationValuesForElement(const SGPropertyNode* _configNode, int _index) + { + configNode = _configNode; + index = _index; + } + + osg::Node* getNode() { return node; } + const SGPropertyNode* getConfigNode() { return configNode; } + SGPropertyNode* getModelRoot() { return modelRoot; } + const osgDB::Options* getOptions() { return options; } + const std::string &getPath() { return path; } + int getIndex() { return index; } + + /* + * Find an already located axis definition object line segment. Returns null if nothing found. + */ + const SGLineSegment *getAxisDefinition(const std::string axis_object_name) + { + SGAxisDefinitionMap::const_iterator axisDefinition = axisDefinitions.find(axis_object_name); + + if (axisDefinition != axisDefinitions.end()) + { + return &(axisDefinition->second); + } + return 0; + } + /* + * Add an axis definition line segment. Always returns the line segment that has been added. + */ + const SGLineSegment *addAxisDefinition(const std::string object_name, const SGLineSegment &line) + { + axisDefinitions[object_name] = line; + return getAxisDefinition(object_name); + } + + private: + osg::Node* node = nullptr; + const SGPropertyNode* configNode = nullptr; + SGPropertyNode* modelRoot = nullptr; + const osgDB::Options* options = nullptr; + const std::string path; + int index = 0; + SGAxisDefinitionMap axisDefinitions; + + }; +} +#endif