#include "ModelRegistry.hxx"
#include <algorithm>
+#include <utility>
+#include <vector>
#include <OpenThreads/ScopedLock>
#include <simgear/scene/util/SGSceneFeatures.hxx>
#include <simgear/scene/util/SGStateAttributeVisitor.hxx>
#include <simgear/scene/util/SGTextureStateAttributeVisitor.hxx>
+#include <simgear/scene/util/NodeAndDrawableVisitor.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/props/props.hxx>
ref_ptr<Referenced> mReferenced;
};
-// Visitor for
-class SGTextureUpdateVisitor : public SGTextureStateAttributeVisitor {
+// Change the StateSets of a model to hold different textures based on
+// a livery path.
+class TextureUpdateVisitor : public NodeAndDrawableVisitor {
public:
- SGTextureUpdateVisitor(const FilePathList& pathList) :
- mPathList(pathList)
- { }
- Texture2D* textureReplace(int unit,
- StateSet::RefAttributePair& refAttr)
- {
- Texture2D* texture;
- texture = dynamic_cast<Texture2D*>(refAttr.first.get());
- if (!texture)
- return 0;
-
- ref_ptr<Image> image = texture->getImage(0);
- if (!image)
- return 0;
-
- // The currently loaded file name
- string fullFilePath = image->getFileName();
- // The short name
- string fileName = getSimpleFileName(fullFilePath);
- // The name that should be found with the current database path
- string fullLiveryFile = findFileInPath(fileName, mPathList);
- // If it is empty or they are identical then there is nothing to do
- if (fullLiveryFile.empty() || fullLiveryFile == fullFilePath)
- return 0;
-
- image = readImageFile(fullLiveryFile);
- if (!image)
- return 0;
+ TextureUpdateVisitor(const FilePathList& pathList) : _pathList(pathList) {}
+ virtual void apply(Node& node)
+ {
+ StateSet* stateSet = cloneStateSet(node.getStateSet());
+ if (stateSet)
+ node.setStateSet(stateSet);
+ traverse(node);
+ }
- CopyOp copyOp(CopyOp::DEEP_COPY_ALL & ~CopyOp::DEEP_COPY_IMAGES);
- texture = static_cast<Texture2D*>(copyOp(texture));
- if (!texture)
- return 0;
- texture->setImage(image.get());
- return texture;
- }
- virtual void apply(StateSet* stateSet)
- {
- if (!stateSet)
- return;
+ virtual void apply(Drawable& drawable)
+ {
+ StateSet* stateSet = cloneStateSet(drawable.getStateSet());
+ if (stateSet)
+ drawable.setStateSet(stateSet);
+ }
+ // Copied whole from Mathias' earlier SGTextureUpdateVisitor
+protected:
+ Texture2D* textureReplace(int unit, const StateAttribute* attr)
+ {
+ const Texture2D* texture = dynamic_cast<const Texture2D*>(attr);
- // get a copy that we can safely modify the statesets values.
- StateSet::TextureAttributeList attrList;
- attrList = stateSet->getTextureAttributeList();
- for (unsigned unit = 0; unit < attrList.size(); ++unit) {
- StateSet::AttributeList::iterator i = attrList[unit].begin();
- while (i != attrList[unit].end()) {
- Texture2D* texture = textureReplace(unit, i->second);
- if (texture) {
- stateSet->removeTextureAttribute(unit, i->second.first.get());
- stateSet->setTextureAttribute(unit, texture, i->second.second);
- stateSet->setTextureMode(unit, GL_TEXTURE_2D, StateAttribute::ON);
+ if (!texture)
+ return 0;
+
+ const Image* image = texture->getImage(0);
+ if (!image)
+ return 0;
+
+ // The currently loaded file name
+ const string& fullFilePath = image->getFileName();
+ // The short name
+ string fileName = getSimpleFileName(fullFilePath);
+ // The name that should be found with the current database path
+ string fullLiveryFile = findFileInPath(fileName, _pathList);
+ // If it is empty or they are identical then there is nothing to do
+ if (fullLiveryFile.empty() || fullLiveryFile == fullFilePath)
+ return 0;
+
+ Image* newImage = readImageFile(fullLiveryFile);
+ if (!newImage)
+ return 0;
+
+ CopyOp copyOp(CopyOp::DEEP_COPY_ALL & ~CopyOp::DEEP_COPY_IMAGES);
+ Texture2D* newTexture = static_cast<Texture2D*>(copyOp(texture));
+ if (!newTexture) {
+ return 0;
+ } else {
+ newTexture->setImage(newImage);
+ return newTexture;
}
- ++i;
- }
}
- }
-
+ StateSet* cloneStateSet(const StateSet* stateSet)
+ {
+ typedef pair<int, Texture2D*> Tex2D;
+ vector<Tex2D> newTextures;
+ StateSet* result = 0;
+
+ if (!stateSet)
+ return 0;
+ int numUnits = stateSet->getTextureAttributeList().size();
+ if (numUnits > 0) {
+ for (int i = 0; i < numUnits; ++i) {
+ const StateAttribute* attr
+ = stateSet->getTextureAttribute(i, StateAttribute::TEXTURE);
+ Texture2D* newTexture = textureReplace(i, attr);
+ if (newTexture)
+ newTextures.push_back(Tex2D(i, newTexture));
+ }
+ if (!newTextures.empty()) {
+ result = static_cast<StateSet*>(stateSet->clone(CopyOp()));
+ for (vector<Tex2D>::iterator i = newTextures.begin();
+ i != newTextures.end();
+ ++i) {
+ result->setTextureAttribute(i->first, i->second);
+ }
+ }
+ }
+ return result;
+ }
private:
- FilePathList mPathList;
+ FilePathList _pathList;
};
+
class SGTexCompressionVisitor : public SGTextureStateAttributeVisitor {
public:
virtual void apply(int, StateSet::RefAttributePair& refAttr)
res->addObserver(databaseReference);
// Update liveries
- SGTextureUpdateVisitor liveryUpdate(opt->getDatabasePathList());
+ TextureUpdateVisitor liveryUpdate(opt->getDatabasePathList());
res->accept(liveryUpdate);
+
return res;
}
--- /dev/null
+/* -*-c++-*-
+ *
+ * Copyright (C) 2008 Tim Moore
+ *
+ * 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.
+ *
+ */
+
+#include <osg/Drawable>
+#include <osg/Geode>
+
+#include "NodeAndDrawableVisitor.hxx"
+
+namespace simgear
+{
+using namespace osg;
+
+NodeAndDrawableVisitor::NodeAndDrawableVisitor(NodeVisitor::TraversalMode tm) :
+ NodeVisitor(tm)
+{
+}
+
+NodeAndDrawableVisitor::NodeAndDrawableVisitor(NodeVisitor::VisitorType type,
+ NodeVisitor::TraversalMode tm) :
+ NodeVisitor(type, tm)
+{
+}
+
+NodeAndDrawableVisitor::~NodeAndDrawableVisitor()
+{
+}
+
+void NodeAndDrawableVisitor::apply(Node& node)
+{
+ traverse(node);
+}
+
+void NodeAndDrawableVisitor::apply(Drawable& Drawable)
+{
+}
+
+void NodeAndDrawableVisitor::traverse(Node& node)
+{
+ TraversalMode tm = getTraversalMode();
+ if (tm == TRAVERSE_NONE) {
+ return;
+ } else if (tm == TRAVERSE_PARENTS) {
+ NodeVisitor::traverse(node);
+ return;
+ }
+ Geode* geode = dynamic_cast<Geode*>(&node);
+ if (geode) {
+ unsigned numDrawables = geode->getNumDrawables();
+ for (unsigned i = 0; i < numDrawables; ++i)
+ apply(*geode->getDrawable(i));
+ } else {
+ NodeVisitor::traverse(node);
+ }
+}
+}
--- /dev/null
+/* -*-c++-*-
+ *
+ * Copyright (C) 2008 Tim Moore
+ *
+ * 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 SIMGEAR_NODEANDDRAWABLEVISITOR_HXX
+#define SIMGEAR_NODEANDDRAWABLEVISITOR_HXX 1
+
+#include <osg/Drawable>
+#include <osg/NodeVisitor>
+
+namespace simgear
+{
+/** A node visitor that descends into Drawables too.
+ */
+class NodeAndDrawableVisitor : public osg::NodeVisitor
+{
+public:
+ NodeAndDrawableVisitor(osg::NodeVisitor::TraversalMode tm = osg::NodeVisitor::TRAVERSE_NONE);
+ NodeAndDrawableVisitor(osg::NodeVisitor::VisitorType type,
+ osg::NodeVisitor::TraversalMode tm = osg::NodeVisitor::TRAVERSE_NONE);
+ virtual ~NodeAndDrawableVisitor();
+ using osg::NodeVisitor::apply;
+ virtual void apply(osg::Node& node);
+ /** Visit a Drawable node. Note that you cannot write an apply()
+ method with an argument that is a subclass of Drawable and expect
+ it to be called, because this visitor can't add the double dispatch
+ machinery of NodeVisitor to the existing OSG Drawable subclasses.
+ */
+ virtual void apply(osg::Drawable& drawable);
+ // hides NodeVisitor::traverse
+ void traverse(osg::Node& node);
+};
+
+}
+#endif