Fix new livery code
It turns out that the database pager causes the texture image to be unloaded after it is applied, so the image and its file name may not be available for doing the livery substitution. Ask a work around we set the name of the texture to its file name.
This commit is contained in:
@@ -79,11 +79,57 @@ private:
|
|||||||
ref_ptr<Referenced> mReferenced;
|
ref_ptr<Referenced> mReferenced;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Set the name of a Texture to the simple name of its image
|
||||||
|
// file. This can be used to do livery substitution after the image
|
||||||
|
// has been deallocated.
|
||||||
|
class TextureNameVisitor : public NodeAndDrawableVisitor {
|
||||||
|
public:
|
||||||
|
TextureNameVisitor(NodeVisitor::TraversalMode tm = NodeVisitor::TRAVERSE_ALL_CHILDREN) :
|
||||||
|
NodeAndDrawableVisitor(tm)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void apply(Node& node)
|
||||||
|
{
|
||||||
|
nameTextures(node.getStateSet());
|
||||||
|
traverse(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void apply(Drawable& drawable)
|
||||||
|
{
|
||||||
|
nameTextures(drawable.getStateSet());
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
void nameTextures(StateSet* stateSet)
|
||||||
|
{
|
||||||
|
if (!stateSet)
|
||||||
|
return;
|
||||||
|
int numUnits = stateSet->getTextureAttributeList().size();
|
||||||
|
for (int i = 0; i < numUnits; ++i) {
|
||||||
|
StateAttribute* attr
|
||||||
|
= stateSet->getTextureAttribute(i, StateAttribute::TEXTURE);
|
||||||
|
Texture2D* texture = dynamic_cast<Texture2D*>(attr);
|
||||||
|
if (!texture || !texture->getName().empty())
|
||||||
|
continue;
|
||||||
|
const Image *image = texture->getImage();
|
||||||
|
if (!image)
|
||||||
|
continue;
|
||||||
|
texture->setName(image->getFileName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Change the StateSets of a model to hold different textures based on
|
// Change the StateSets of a model to hold different textures based on
|
||||||
// a livery path.
|
// a livery path.
|
||||||
|
|
||||||
class TextureUpdateVisitor : public NodeAndDrawableVisitor {
|
class TextureUpdateVisitor : public NodeAndDrawableVisitor {
|
||||||
public:
|
public:
|
||||||
TextureUpdateVisitor(const FilePathList& pathList) : _pathList(pathList) {}
|
TextureUpdateVisitor(const FilePathList& pathList) :
|
||||||
|
NodeAndDrawableVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
||||||
|
_pathList(pathList)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
virtual void apply(Node& node)
|
virtual void apply(Node& node)
|
||||||
{
|
{
|
||||||
StateSet* stateSet = cloneStateSet(node.getStateSet());
|
StateSet* stateSet = cloneStateSet(node.getStateSet());
|
||||||
@@ -98,7 +144,7 @@ public:
|
|||||||
if (stateSet)
|
if (stateSet)
|
||||||
drawable.setStateSet(stateSet);
|
drawable.setStateSet(stateSet);
|
||||||
}
|
}
|
||||||
// Copied whole from Mathias' earlier SGTextureUpdateVisitor
|
// Copied from Mathias' earlier SGTextureUpdateVisitor
|
||||||
protected:
|
protected:
|
||||||
Texture2D* textureReplace(int unit, const StateAttribute* attr)
|
Texture2D* textureReplace(int unit, const StateAttribute* attr)
|
||||||
{
|
{
|
||||||
@@ -107,24 +153,27 @@ protected:
|
|||||||
if (!texture)
|
if (!texture)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const Image* image = texture->getImage(0);
|
const Image* image = texture->getImage();
|
||||||
if (!image)
|
const string* fullFilePath = 0;
|
||||||
return 0;
|
if (image) {
|
||||||
|
// The currently loaded file name
|
||||||
|
fullFilePath = &image->getFileName();
|
||||||
|
|
||||||
// The currently loaded file name
|
} else {
|
||||||
const string& fullFilePath = image->getFileName();
|
fullFilePath = &texture->getName();
|
||||||
|
}
|
||||||
// The short name
|
// The short name
|
||||||
string fileName = getSimpleFileName(fullFilePath);
|
string fileName = getSimpleFileName(*fullFilePath);
|
||||||
|
if (fileName.empty())
|
||||||
|
return 0;
|
||||||
// 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, _pathList);
|
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* newImage = readImageFile(fullLiveryFile);
|
Image* newImage = readImageFile(fullLiveryFile);
|
||||||
if (!newImage)
|
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);
|
||||||
Texture2D* newTexture = static_cast<Texture2D*>(copyOp(texture));
|
Texture2D* newTexture = static_cast<Texture2D*>(copyOp(texture));
|
||||||
if (!newTexture) {
|
if (!newTexture) {
|
||||||
@@ -134,6 +183,7 @@ protected:
|
|||||||
return newTexture;
|
return newTexture;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StateSet* cloneStateSet(const StateSet* stateSet)
|
StateSet* cloneStateSet(const StateSet* stateSet)
|
||||||
{
|
{
|
||||||
typedef pair<int, Texture2D*> Tex2D;
|
typedef pair<int, Texture2D*> Tex2D;
|
||||||
@@ -262,6 +312,14 @@ struct OptionsPusher {
|
|||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
Node* DefaultProcessPolicy::process(Node* node, const string& filename,
|
||||||
|
const ReaderWriter::Options* opt)
|
||||||
|
{
|
||||||
|
TextureNameVisitor nameVisitor;
|
||||||
|
node->accept(nameVisitor);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
ReaderWriter::ReadResult
|
ReaderWriter::ReadResult
|
||||||
ModelRegistry::readImage(const string& fileName,
|
ModelRegistry::readImage(const string& fileName,
|
||||||
const ReaderWriter::Options* opt)
|
const ReaderWriter::Options* opt)
|
||||||
|
|||||||
@@ -128,10 +128,7 @@ protected:
|
|||||||
struct DefaultProcessPolicy {
|
struct DefaultProcessPolicy {
|
||||||
DefaultProcessPolicy(const std::string& extension) {}
|
DefaultProcessPolicy(const std::string& extension) {}
|
||||||
osg::Node* process(osg::Node* node, const std::string& filename,
|
osg::Node* process(osg::Node* node, const std::string& filename,
|
||||||
const osgDB::ReaderWriter::Options* opt)
|
const osgDB::ReaderWriter::Options* opt);
|
||||||
{
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DefaultCachePolicy {
|
struct DefaultCachePolicy {
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ namespace simgear
|
|||||||
class NodeAndDrawableVisitor : public osg::NodeVisitor
|
class NodeAndDrawableVisitor : public osg::NodeVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NodeAndDrawableVisitor(osg::NodeVisitor::TraversalMode tm = osg::NodeVisitor::TRAVERSE_NONE);
|
NodeAndDrawableVisitor(osg::NodeVisitor::TraversalMode tm);
|
||||||
NodeAndDrawableVisitor(osg::NodeVisitor::VisitorType type,
|
NodeAndDrawableVisitor(osg::NodeVisitor::VisitorType type,
|
||||||
osg::NodeVisitor::TraversalMode tm = osg::NodeVisitor::TRAVERSE_NONE);
|
osg::NodeVisitor::TraversalMode tm);
|
||||||
virtual ~NodeAndDrawableVisitor();
|
virtual ~NodeAndDrawableVisitor();
|
||||||
using osg::NodeVisitor::apply;
|
using osg::NodeVisitor::apply;
|
||||||
virtual void apply(osg::Node& node);
|
virtual void apply(osg::Node& node);
|
||||||
|
|||||||
Reference in New Issue
Block a user