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:
parent
8f48515b80
commit
8f46f2cac8
@ -1163,6 +1163,12 @@
|
||||
<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">
|
||||
|
@ -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;
|
||||
|
||||
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;
|
||||
|
||||
// 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);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
TextureUpdateVisitor(const FilePathList& pathList) : _pathList(pathList) {}
|
||||
virtual void apply(Node& node)
|
||||
{
|
||||
StateSet* stateSet = cloneStateSet(node.getStateSet());
|
||||
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)
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
73
simgear/scene/util/NodeAndDrawableVisitor.cxx
Normal file
73
simgear/scene/util/NodeAndDrawableVisitor.cxx
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
51
simgear/scene/util/NodeAndDrawableVisitor.hxx
Normal file
51
simgear/scene/util/NodeAndDrawableVisitor.hxx
Normal file
@ -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
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void Reshape(int w, int h);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user