Thanks to Robert and Paul, I created the attached application to do the 
terrain database conversion.  Perhaps it will be of some use to someone else.

Using this application, my paged database of 655936 kB was converted to a 
non-paged database of 415288 kB.

Of course, I decided to take it a step further and perform texture conversions 
as well.  I wanted to convert the .dds texture files to .jpg.  This code is 
stubbed in; however, it does not work.  I thought I could simply call 
osgDB::writeImageFile.  Unfortunately, the individual image format writer 
plugins do not appear to handle converting from different pixel formats or 
packing.  Does OSG contain code for converting osg::Image between different 
pixel formats?  Am I missing an easier option?

Thanks,
Justin

On Wednesday 26 November 2008 09:26:40 KSpam wrote:
> I have a paged terrain database that I would like to convert to a non-paged
> model.  Ideally, I would like to remove all level-of-detail switching and
> only keep the highest level of detail.
>
> How might I go about doing this?
#include <osg/Texture2D>
#include <osgDB/FileNameUtils>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>

#include <iostream>
#include <string>

//----------------------------------------------------------------------------
class ConvertTextureFileFormatVisitor : public osg::NodeVisitor
{
public:
    struct ConvertCallback : public osg::Referenced
    {
        virtual bool convertImage(osg::Image& image) = 0;
    };

    ConvertTextureFileFormatVisitor
        (
        ConvertCallback* convertCallback
        )
        : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
        , m_ConvertCallback(convertCallback)
    {
    }

    virtual void apply
        (
        osg::Node& node
        )
    {
        if (node.getStateSet())
        {
            apply(*node.getStateSet());
        }
        traverse(node);
    }

    virtual void apply
        (
        osg::Geode& node
        )
    {
        if (node.getStateSet())
        {
            apply(*node.getStateSet());
        }

        const unsigned int numDrawables = node.getNumDrawables();
        for (unsigned int i = 0; i < numDrawables; ++i)
        {
            osg::ref_ptr<osg::Drawable> drawable = node.getDrawable(i);
            if (drawable.valid() && drawable->getStateSet())
            {
                apply(*(drawable->getStateSet()));
            }
        }

        traverse(node);
    }

    virtual void apply
        (
        osg::StateSet& stateSet
        )
    {
        // Search for any Texture2D object attributes
        for (unsigned int i = 0; i < stateSet.getTextureAttributeList().size(); ++i)
        {
            osg::ref_ptr<osg::Texture2D> texture2D = dynamic_cast<osg::Texture2D*>(stateSet.getTextureAttribute(i, osg::StateAttribute::TEXTURE));
            if (texture2D.valid())
            {
                osg::ref_ptr<osg::Image> image = texture2D->getImage();
                if (image.valid() && image->valid())
                {
                    m_ConvertCallback->convertImage(*image);
                }
            }
        }
    }

protected:
    osg::ref_ptr<ConvertCallback> m_ConvertCallback;
};

//----------------------------------------------------------------------------
struct MyConvertCallback : public ConvertTextureFileFormatVisitor::ConvertCallback
{
public:
    MyConvertCallback
        (
        const std::string& srcDir,
        const std::string& dstDir,
        const std::string& desiredExtension
        )
        : m_SrcDir(srcDir)
        , m_DstDir(dstDir)
        , m_DesiredExtension(desiredExtension)
    {
    }

    virtual bool convertImage(osg::Image& image)
    {
        const std::string& fileName = image.getFileName();
        if ((m_SrcDir != m_DstDir) || (osgDB::getFileExtension(fileName) != m_DesiredExtension))
        {
            std::string srcFileName = fileName;
            if (!m_SrcDir.empty())
            {
                srcFileName = osgDB::concatPaths(m_SrcDir, srcFileName);
            }

            std::string dstFileName = osgDB::getNameLessExtension(fileName) + "." + m_DesiredExtension;
            image.setFileName(dstFileName);
            if (!m_DstDir.empty())
            {
                dstFileName = osgDB::concatPaths(m_DstDir, dstFileName);
            }

            std::cout << "    Converting " << srcFileName << " to " << dstFileName << std::endl;
            if (!osgDB::writeImageFile(image, dstFileName))
            {
                std::cerr << "ERROR : Failure while writing \"" << dstFileName << "\"!" << std::endl;
            }
        }

        return true;
    }

protected:
    std::string m_SrcDir;
    std::string m_DstDir;
    std::string m_DesiredExtension;
};

//----------------------------------------------------------------------------
class HighestResolutionPagedLODTransformationVisitor : public osg::NodeVisitor
{
public:
    struct ReadCallback : public osg::Referenced
    {
        virtual osg::Node* readNodeFile(const std::string& fileName) = 0;
    };

    HighestResolutionPagedLODTransformationVisitor
        (
        )
        : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
    {
    }

    void setReadCallback
        (
        ReadCallback* rc
        )
    {
        m_ReadCallback = rc;
    }

    ReadCallback* getReadCallback
        (
        )
    {
        return m_ReadCallback.get();
    }

    virtual void apply
        (
        osg::PagedLOD& node
        )
    {
        const unsigned int numFileNames = node.getNumFileNames();
        if (numFileNames > 0)
        {
            const unsigned int numChildren = node.getNumChildren();
            osg::ref_ptr<osg::Node> highestResChild;
            if (numFileNames != numChildren)
            {
                const std::string& fileName =
                    node.getDatabasePath() + node.getFileName(numFileNames - 1);
                if (m_ReadCallback.valid())
                {
                    highestResChild = m_ReadCallback->readNodeFile(fileName);
                }
                else
                {
                    highestResChild = osgDB::readNodeFile(fileName);
                }
            }
            else if (numChildren > 0)
            {
                highestResChild = node.getChild(numChildren - 1);
            }

            if (highestResChild.valid())
            {
                highestResChild->accept(*this);

                osg::Node::ParentList parentList = node.getParents();
                if (parentList.empty())
                {
                    // This PagedLOD node does not have parents; therefore,
                    // it must be a root node.
                    node.removeChildren(0, numChildren);
                    node.addChild(highestResChild.get());
                    node.setFileName(0, "");
                    node.setRange(0, 0.0, 10000000000.0);
                }
                else
                {
                    // Swap out the PagedLOD node for the highestResChild node
                    osg::Node::ParentList::iterator ii = parentList.begin();
                    osg::Node::ParentList::iterator ie = parentList.end();
                    for (; ii != ie; ++ii)
                    {
                        (*ii)->replaceChild(&node, highestResChild.get());
                    }
                }
            }
        }
    }

protected:
    osg::ref_ptr<ReadCallback> m_ReadCallback;
};

//----------------------------------------------------------------------------
class MyReadCallback : public HighestResolutionPagedLODTransformationVisitor::ReadCallback
{
public:
    MyReadCallback
        (
        )
        : m_NumSubtilesProcessed(0)
    {
    }

    unsigned int numSubtilesProcessed
        (
        ) const
    {
        return m_NumSubtilesProcessed;
    }

    virtual osg::Node* readNodeFile
        (
        const std::string& fileName
        )
    {
        ++m_NumSubtilesProcessed;
        std::cout << "    " << m_NumSubtilesProcessed << ": Reading subtile " << fileName << std::endl;
        return osgDB::readNodeFile(fileName);
    }

protected:
    unsigned int m_NumSubtilesProcessed;
};

//----------------------------------------------------------------------------
int main
    (
    int   argc,
    char* argv[]
    )
{
    if ((argc < 2) || (argc > 3))
    {
        std::cout << "Usage : " << argv[0] << " infile outfile" << std::endl;
        return 1;
    }

    const std::string infile  = argv[1];
    const std::string outfile = (argc == 3) ? argv[2] : "converted.osg";

    std::cout << "Reading " << infile << std::endl;
    osg::ref_ptr<osg::Node> root = osgDB::readNodeFile(infile);
    if (!root)
    {
        std::cerr << "ERROR : Failure while reading \"" << infile << "\"!" << std::endl;
        return 2;
    }

    {
        std::cout << "Transforming to the highest resolution PagedLOD ..." << std::endl;
        HighestResolutionPagedLODTransformationVisitor visitor;
        osg::ref_ptr<MyReadCallback> readCallback = new MyReadCallback();
        visitor.setReadCallback(readCallback.get());
        root->accept(visitor);
        std::cout << "Number of subtiles processed = " << readCallback->numSubtilesProcessed() << std::endl;
    }

    {
        std::cout << "Converting texture file formats ..." << std::endl;
        const std::string srcDir = osgDB::getFilePath(infile);
        const std::string dstDir = osgDB::getFilePath(outfile);
        ConvertTextureFileFormatVisitor visitor(new MyConvertCallback(srcDir, dstDir, "jpg"));
        root->accept(visitor);
    }

    std::cout << "Writing " << outfile << std::endl;
    if (!osgDB::writeNodeFile(*root, outfile))
    {
        std::cerr << "ERROR : Failure while writing \"" << outfile << "\"!" << std::endl;
        return 2;
    }

    return 0;
}
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Reply via email to