<File
RelativePath="..\..\simgear\scene\util\SGUpdateVisitor.hxx">
</File>
+ <File
+ RelativePath="..\..\simgear\scene\util\SplicingVisitor.cxx">
+ </File>
+ <File
+ RelativePath="..\..\simgear\scene\util\SplicingVisitor.hxx">
+ </File>
<File
RelativePath="..\..\simgear\scene\util\StateAttributeFactory.cxx">
</File>
RelativePath="..\..\simgear\scene\util\SGUpdateVisitor.hxx"
>
</File>
+ <File
+ RelativePath="..\..\simgear\scene\util\SplicingVisitor.cxx"
+ >
+ </File>
+ <File
+ RelativePath="..\..\simgear\scene\util\SplicingVisitor.hxx"
+ >
+ </File>
<File
RelativePath="..\..\simgear\scene\util\StateAttributeFactory.cxx"
>
PrimitiveUtils.hxx \
QuadTreeBuilder.hxx \
RenderConstants.hxx \
+ SplicingVisitor.hxx \
StateAttributeFactory.hxx \
VectorArrayAdapter.hxx
SGTextureStateAttributeVisitor.cxx \
NodeAndDrawableVisitor.cxx \
PrimitiveUtils.cxx \
+ SplicingVisitor.cxx \
StateAttributeFactory.cxx \
QuadTreeBuilder.cxx
--- /dev/null
+#include "SplicingVisitor.hxx"
+
+namespace simgear
+{
+using namespace osg;
+
+SplicingVisitor::SplicingVisitor()
+ : NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN)
+{
+ _childStack.push_back(NodeList());
+}
+
+void SplicingVisitor::reset()
+{
+ _childStack.clear();
+ NodeVisitor::reset();
+}
+
+NodeList SplicingVisitor::traverse(Node& node)
+{
+ NodeList result;
+ _childStack.push_back(NodeList());
+ NodeVisitor::traverse(node);
+ result = _childStack.back();
+ _childStack.pop_back();
+ return result;
+}
+void SplicingVisitor::apply(Node& node)
+{
+ NodeVisitor::traverse(node);
+ pushNode(&node);
+}
+
+void SplicingVisitor::apply(Group& node)
+{
+ if (pushNode(getNewNode(node)))
+ return;
+ pushResultNode(&node, &node, traverse(node));
+}
+
+Group* SplicingVisitor::pushResultNode(Group* node, Group* newNode,
+ const NodeList& children)
+{
+ ref_ptr<Group> result;
+ if (node == newNode) {
+ result = copyIfNeeded(*node, children);
+ } else {
+ result = newNode;
+ for (NodeList::const_iterator itr = children.begin(), end = children.end();
+ itr != end;
+ ++itr)
+ result->addChild(itr->get());
+ }
+ _childStack.back().push_back(result);
+ recordNewNode(node, result);
+ return result;
+}
+
+Node* SplicingVisitor::pushResultNode(Node* node, Node* newNode)
+{
+ _childStack.back().push_back(newNode);
+ recordNewNode(node, newNode);
+ return newNode;
+}
+
+Node* SplicingVisitor::pushNode(Node* node)
+{
+ if (node)
+ _childStack.back().push_back(node);
+ return node;
+}
+
+Node* SplicingVisitor::getResult()
+{
+ NodeList& top = _childStack.at(0);
+ if (top.empty()) {
+ return 0;
+ } else if (top.size() == 1) {
+ return top[0].get();
+ } else {
+ Group* result = new Group;
+ for (NodeList::iterator itr = top.begin(), end = top.end();
+ itr != end;
+ ++itr)
+ result->addChild(itr->get());
+ return result;
+ }
+}
+
+Node* SplicingVisitor::getNewNode(osg::Node* node)
+{
+ ref_ptr<Node> tmpPtr(node);
+ NodeMap::iterator itr;
+ try {
+ itr = _visited.find(tmpPtr);
+ }
+ catch (...) {
+ tmpPtr.release();
+ throw;
+ }
+ if (itr == _visited.end())
+ return 0;
+ else
+ return itr->second.get();
+}
+
+bool SplicingVisitor::recordNewNode(osg::Node* oldNode, osg::Node* newNode)
+{
+ ref_ptr<Node> oldTmp(oldNode);
+ ref_ptr<Node> newTmp(newNode);
+ return _visited.insert(std::make_pair(oldTmp, newTmp)).second;
+}
+}
--- /dev/null
+#ifndef SIMGEAR_SPLICINGVISITOR_HXX
+#define SIMGEAR_SPLICINGVISITOR_HXX 1
+
+#include <cstddef>
+#include <map>
+#include <vector>
+#include <osg/NodeVisitor>
+#include <osg/Group>
+
+namespace simgear
+{
+class SplicingVisitor : public osg::NodeVisitor
+{
+public:
+ META_NodeVisitor(simgear,SplicingVisitor);
+ SplicingVisitor();
+ virtual ~SplicingVisitor() {}
+ virtual void reset();
+ osg::NodeList traverse(osg::Node& node);
+ using osg::NodeVisitor::apply;
+ virtual void apply(osg::Node& node);
+ virtual void apply(osg::Group& node);
+ template<typename T>
+ static T* copyIfNeeded(T& node, const osg::NodeList& children);
+ template<typename T>
+ static T* copy(T& node, const osg::NodeList& children);
+ /**
+ * Push the result of processing this node.
+ *
+ * If the child list is not equal to the node's current children,
+ * make a copy of the node. Record the (possibly new) node which
+ * should be the returned result if the node is visited again.
+ */
+ osg::Group* pushResultNode(osg::Group* node, osg::Group* newNode,
+ const osg::NodeList& children);
+ /**
+ * Push the result of processing this node.
+ *
+ * Record the (possibly new) node which should be the returned
+ * result if the node is visited again.
+ */
+ osg::Node* pushResultNode(osg::Node* node, osg::Node* newNode);
+ /**
+ * Push some node onto the list of result nodes.
+ */
+ osg::Node* pushNode(osg::Node* node);
+ osg::Node* getResult();
+ osg::Node* getNewNode(osg::Node& node)
+ {
+ return getNewNode(&node);
+ }
+ osg::Node* getNewNode(osg::Node* node);
+ bool recordNewNode(osg::Node* oldNode, osg::Node* newNode);
+ osg::NodeList& getResults() { return _childStack.back(); }
+protected:
+ std::vector<osg::NodeList> _childStack;
+ typedef std::map<osg::ref_ptr<osg::Node>, osg::ref_ptr<osg::Node> > NodeMap;
+ NodeMap _visited;
+};
+
+template<typename T>
+T* SplicingVisitor::copyIfNeeded(T& node, const osg::NodeList& children)
+{
+ bool copyNeeded = false;
+ if (node.getNumChildren() == children.size()) {
+ for (std::size_t i = 0; i < children.size(); ++i)
+ if (node.getChild(i) != children[i].get()) {
+ copyNeeded = true;
+ break;
+ }
+ } else {
+ copyNeeded = true;
+ }
+ if (copyNeeded)
+ return copy(node, children);
+ else
+ return &node;
+}
+
+template<typename T>
+T* SplicingVisitor::copy(T& node, const osg::NodeList& children)
+{
+ T* result = osg::clone(&node, osg::CopyOp::SHALLOW_COPY);
+ result->removeChildren(0, result->getNumChildren());
+ for (osg::NodeList::const_iterator itr = children.begin(),
+ end = children.end();
+ itr != end;
+ ++itr)
+ result->addChild(itr->get());
+ return result;
+}
+}
+#endif