Rewrite livery texture replacement to copy StateSet objects

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.
This commit is contained in:
timoore
2008-04-23 18:13:50 +00:00
parent 8f48515b80
commit 8f46f2cac8
6 changed files with 220 additions and 60 deletions
+6
View File
@@ -1163,6 +1163,12 @@
<File <File
RelativePath="..\..\simgear\scene\util\StateAttributeFactory.hxx"> RelativePath="..\..\simgear\scene\util\StateAttributeFactory.hxx">
</File> </File>
<File
RelativePath="..\..\simgear\scene\util\NodeAndDrawableVisitor.cxx">
</File>
<File
RelativePath="..\..\simgear\scene\util\NodeAndDrawableVisitor.cxx.hxx">
</File>
</Filter> </Filter>
<File <File
RelativePath="..\..\simgear\simgear_config.h-msvc71"> RelativePath="..\..\simgear\simgear_config.h-msvc71">
+63 -36
View File
@@ -19,6 +19,8 @@
#include "ModelRegistry.hxx" #include "ModelRegistry.hxx"
#include <algorithm> #include <algorithm>
#include <utility>
#include <vector>
#include <OpenThreads/ScopedLock> #include <OpenThreads/ScopedLock>
@@ -41,6 +43,7 @@
#include <simgear/scene/util/SGSceneFeatures.hxx> #include <simgear/scene/util/SGSceneFeatures.hxx>
#include <simgear/scene/util/SGStateAttributeVisitor.hxx> #include <simgear/scene/util/SGStateAttributeVisitor.hxx>
#include <simgear/scene/util/SGTextureStateAttributeVisitor.hxx> #include <simgear/scene/util/SGTextureStateAttributeVisitor.hxx>
#include <simgear/scene/util/NodeAndDrawableVisitor.hxx>
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
#include <simgear/props/props.hxx> #include <simgear/props/props.hxx>
@@ -76,71 +79,94 @@ private:
ref_ptr<Referenced> mReferenced; ref_ptr<Referenced> mReferenced;
}; };
// Visitor for // Change the StateSets of a model to hold different textures based on
class SGTextureUpdateVisitor : public SGTextureStateAttributeVisitor { // a livery path.
class TextureUpdateVisitor : public NodeAndDrawableVisitor {
public: public:
SGTextureUpdateVisitor(const FilePathList& pathList) : TextureUpdateVisitor(const FilePathList& pathList) : _pathList(pathList) {}
mPathList(pathList) virtual void apply(Node& node)
{ }
Texture2D* textureReplace(int unit,
StateSet::RefAttributePair& refAttr)
{ {
Texture2D* texture; StateSet* stateSet = cloneStateSet(node.getStateSet());
texture = dynamic_cast<Texture2D*>(refAttr.first.get()); if (stateSet)
node.setStateSet(stateSet);
traverse(node);
}
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);
if (!texture) if (!texture)
return 0; return 0;
ref_ptr<Image> image = texture->getImage(0); const Image* image = texture->getImage(0);
if (!image) if (!image)
return 0; return 0;
// The currently loaded file name // The currently loaded file name
string fullFilePath = image->getFileName(); const string& fullFilePath = image->getFileName();
// The short name // The short name
string fileName = getSimpleFileName(fullFilePath); string fileName = getSimpleFileName(fullFilePath);
// The name that should be found with the current database path // The name that should be found with the current database path
string fullLiveryFile = findFileInPath(fileName, mPathList); string fullLiveryFile = findFileInPath(fileName, _pathList);
// If it is empty or they are identical then there is nothing to do // If it is empty or they are identical then there is nothing to do
if (fullLiveryFile.empty() || fullLiveryFile == fullFilePath) if (fullLiveryFile.empty() || fullLiveryFile == fullFilePath)
return 0; return 0;
image = readImageFile(fullLiveryFile); Image* newImage = readImageFile(fullLiveryFile);
if (!image) if (!newImage)
return 0; return 0;
CopyOp copyOp(CopyOp::DEEP_COPY_ALL & ~CopyOp::DEEP_COPY_IMAGES); CopyOp copyOp(CopyOp::DEEP_COPY_ALL & ~CopyOp::DEEP_COPY_IMAGES);
texture = static_cast<Texture2D*>(copyOp(texture)); Texture2D* newTexture = static_cast<Texture2D*>(copyOp(texture));
if (!texture) if (!newTexture) {
return 0; return 0;
texture->setImage(image.get()); } else {
return texture; newTexture->setImage(newImage);
return newTexture;
} }
virtual void apply(StateSet* stateSet) }
StateSet* cloneStateSet(const StateSet* stateSet)
{ {
typedef pair<int, Texture2D*> Tex2D;
vector<Tex2D> newTextures;
StateSet* result = 0;
if (!stateSet) if (!stateSet)
return; return 0;
int numUnits = stateSet->getTextureAttributeList().size();
// get a copy that we can safely modify the statesets values. if (numUnits > 0) {
StateSet::TextureAttributeList attrList; for (int i = 0; i < numUnits; ++i) {
attrList = stateSet->getTextureAttributeList(); const StateAttribute* attr
for (unsigned unit = 0; unit < attrList.size(); ++unit) { = stateSet->getTextureAttribute(i, StateAttribute::TEXTURE);
StateSet::AttributeList::iterator i = attrList[unit].begin(); Texture2D* newTexture = textureReplace(i, attr);
while (i != attrList[unit].end()) { if (newTexture)
Texture2D* texture = textureReplace(unit, i->second); newTextures.push_back(Tex2D(i, newTexture));
if (texture) {
stateSet->removeTextureAttribute(unit, i->second.first.get());
stateSet->setTextureAttribute(unit, texture, i->second.second);
stateSet->setTextureMode(unit, GL_TEXTURE_2D, StateAttribute::ON);
} }
++i; 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: private:
FilePathList mPathList; FilePathList _pathList;
}; };
class SGTexCompressionVisitor : public SGTextureStateAttributeVisitor { class SGTexCompressionVisitor : public SGTextureStateAttributeVisitor {
public: public:
virtual void apply(int, StateSet::RefAttributePair& refAttr) virtual void apply(int, StateSet::RefAttributePair& refAttr)
@@ -352,8 +378,9 @@ osg::Node* DefaultCopyPolicy::copy(osg::Node* model, const string& fileName,
res->addObserver(databaseReference); res->addObserver(databaseReference);
// Update liveries // Update liveries
SGTextureUpdateVisitor liveryUpdate(opt->getDatabasePathList()); TextureUpdateVisitor liveryUpdate(opt->getDatabasePathList());
res->accept(liveryUpdate); res->accept(liveryUpdate);
return res; return res;
} }
+2
View File
@@ -14,6 +14,7 @@ include_HEADERS = \
SGStateAttributeVisitor.hxx \ SGStateAttributeVisitor.hxx \
SGTextureStateAttributeVisitor.hxx \ SGTextureStateAttributeVisitor.hxx \
SGUpdateVisitor.hxx \ SGUpdateVisitor.hxx \
NodeAndDrawableVisitor.hxx \
QuadTreeBuilder.hxx \ QuadTreeBuilder.hxx \
RenderConstants.hxx \ RenderConstants.hxx \
StateAttributeFactory.hxx \ StateAttributeFactory.hxx \
@@ -26,6 +27,7 @@ libsgutil_a_SOURCES = \
SGSceneUserData.cxx \ SGSceneUserData.cxx \
SGStateAttributeVisitor.cxx \ SGStateAttributeVisitor.cxx \
SGTextureStateAttributeVisitor.cxx \ SGTextureStateAttributeVisitor.cxx \
NodeAndDrawableVisitor.cxx \
StateAttributeFactory.cxx \ StateAttributeFactory.cxx \
QuadTreeBuilder.cxx QuadTreeBuilder.cxx
@@ -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);
}
}
}
@@ -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
+1
View File
@@ -16,6 +16,7 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
void Reshape(int w, int h); void Reshape(int w, int h);