]> git.mxchange.org Git - simgear.git/commitdiff
Rewrite livery texture replacement to copy StateSet objects
authortimoore <timoore>
Wed, 23 Apr 2008 18:13:50 +0000 (18:13 +0000)
committertimoore <timoore>
Wed, 23 Apr 2008 18:13:50 +0000 (18:13 +0000)
Also, add a NodeAndDrawableVisitor that descends into osg::Drawable.

That motivation for this is that it's a bad idea to modify state sets
that the osgDB::SharedStateManager might be keeping.

projects/VC7.1/SimGear.vcproj
simgear/scene/model/ModelRegistry.cxx
simgear/scene/util/Makefile.am
simgear/scene/util/NodeAndDrawableVisitor.cxx [new file with mode: 0644]
simgear/scene/util/NodeAndDrawableVisitor.hxx [new file with mode: 0644]
simgear/screen/TestRenderTexture.cpp

index f9c17d427e9c7f2b0ff514077cfbccaeefd15311..96ddc4ce06af57adbd4bdf95803c044a3d5104f0 100755 (executable)
                        <File
                                RelativePath="..\..\simgear\scene\util\StateAttributeFactory.hxx">
                        </File>
+                       <File
+                               RelativePath="..\..\simgear\scene\util\NodeAndDrawableVisitor.cxx">
+                       </File>
+                       <File
+                               RelativePath="..\..\simgear\scene\util\NodeAndDrawableVisitor.cxx.hxx">
+                       </File>
                </Filter>
                <File
                        RelativePath="..\..\simgear\simgear_config.h-msvc71">
index 5d123109d6fd02b2bd55f15c962e2845d9a67b01..a1f49f2a911d9e51013c7935d75ec59bc9f0c057 100644 (file)
@@ -19,6 +19,8 @@
 #include "ModelRegistry.hxx"
 
 #include <algorithm>
+#include <utility>
+#include <vector>
 
 #include <OpenThreads/ScopedLock>
 
@@ -41,6 +43,7 @@
 #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>
@@ -76,71 +79,94 @@ private:
   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)
@@ -352,8 +378,9 @@ osg::Node* DefaultCopyPolicy::copy(osg::Node* model, const string& fileName,
     res->addObserver(databaseReference);
 
     // Update liveries
-    SGTextureUpdateVisitor liveryUpdate(opt->getDatabasePathList());
+    TextureUpdateVisitor liveryUpdate(opt->getDatabasePathList());
     res->accept(liveryUpdate);
+
     return res;
 }
 
index 121900a5dc9ad0019f89084030444d248a8c8e30..28af3fdc8121e2e8ba9a49563e3d6a7c819248db 100644 (file)
@@ -14,6 +14,7 @@ include_HEADERS = \
        SGStateAttributeVisitor.hxx \
        SGTextureStateAttributeVisitor.hxx \
        SGUpdateVisitor.hxx \
+       NodeAndDrawableVisitor.hxx \
        QuadTreeBuilder.hxx \
        RenderConstants.hxx \
        StateAttributeFactory.hxx \
@@ -26,6 +27,7 @@ libsgutil_a_SOURCES = \
        SGSceneUserData.cxx \
        SGStateAttributeVisitor.cxx \
        SGTextureStateAttributeVisitor.cxx \
+       NodeAndDrawableVisitor.cxx \
        StateAttributeFactory.cxx \
        QuadTreeBuilder.cxx
 
diff --git a/simgear/scene/util/NodeAndDrawableVisitor.cxx b/simgear/scene/util/NodeAndDrawableVisitor.cxx
new file mode 100644 (file)
index 0000000..257171c
--- /dev/null
@@ -0,0 +1,73 @@
+/* -*-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);
+    }
+}
+}
diff --git a/simgear/scene/util/NodeAndDrawableVisitor.hxx b/simgear/scene/util/NodeAndDrawableVisitor.hxx
new file mode 100644 (file)
index 0000000..cb780d9
--- /dev/null
@@ -0,0 +1,51 @@
+/* -*-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
index 490e41e93a4bb8f53675739b411204d7d7620054..2c7fc236d2022680fc90781a615bcd0e75f26b96 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <assert.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 void Reshape(int w, int h);