Kawicki, Ryan H | 30 Jul 20:06 2014
Picon

Fix Issue With TXP Plugin Removing Model Insets

There is an issue where the model insets of a terrex terrain are being removed during the loading process.  The issue is described below.

 

    - the issue here is that the plugin is removing group nodes if

      that group node only has one child.  becuase transforms are also

      group nodes, there were cases when the transform would have only

      one child under it and would cause it to remove the translation

      portion.  this would cause all the vertex data to be loaded around

      the last matrix operation, which in our case was the origin (0,0,0).

 

We work off of OSG 2.8.1 but see that this has not been addressed on latest yet.  I’ve tested this against 2.8.1 and have cleanly applied it to my local repository off of latest.

 

The following file is off of latest and I have included a patch file, git bundle, and the actual file needing changed.

 

Thanks.

 

Ryan H. Kawicki

 

Attachment (txp_fix_lost_insets.bundle): application/octet-stream, 13 KiB
Attachment (txp_fix_lost_insets.patch): application/octet-stream, 3417 bytes
#include <osg/Group>
#include <osg/Object>
#include <osg/Node>
#include <osg/Notify>
#include <osg/MatrixTransform>
#include <osg/BoundingSphere>
#include <osgDB/Registry>
#include <osgDB/FileUtils>
#include <osg/io_utils>

#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <string.h>

#include "ReaderWriterTXP.h"
#include "TXPNode.h"
#include "TXPArchive.h"
#include "TXPPagedLOD.h"
#include "TXPSeamLOD.h"
#include "TileMapper.h"

#define ReaderWriterTXPERROR(s) OSG_NOTICE << "txp::ReaderWriterTXP::" << (s) << " error: "

namespace
{
    char gbuf[2048];
}

using namespace txp;

int ReaderWriterTXP::_archiveId = 0;

osgDB::ReaderWriter::ReadResult ReaderWriterTXP::local_readNode(const std::string& file, const
osgDB::ReaderWriter::Options* options)
{

    std::string name = osgDB::getSimpleFileName(file);

    // We load archive.txp
    if (strncmp(name.c_str(),"archive",7)==0)
    {
        std::string fileName = osgDB::findDataFile( file, options );
        if ( fileName.empty() )
            return ReadResult::FILE_NOT_FOUND;

        osg::ref_ptr<TXPNode> txpNode = new TXPNode;
        txpNode->setArchiveName(fileName);
        if (options)
        {
            txpNode->setOptions(options->getOptionString());
        }

        //modified by Brad Anderegg on May-27-08
        //calling getArchive will create a new TXPArchive if the specified one does not exist
        //we will set our osgdb loader options on the archive and set the appropriate archive on
        //the txpNode.
        int id = ++_archiveId;
        osg::ref_ptr< TXPArchive > archive = createArchive(id,osgDB::getFilePath(fileName));

        if (archive != NULL)
        {
            archive->setId(id);

            if (options && options->getOptionString().find("loadMaterialsToStateSet")!=std::string::npos)
            {
               archive->SetMaterialAttributesToStateSetVar(true);
            }

            txpNode->loadArchive(archive.get());

            return txpNode.get();
        }
        else
        {
            return ReadResult::ERROR_IN_READING_FILE;
        }
    }

    // We load tileLOD_XxY_ID.txp
    else if (strncmp(name.c_str(),"tile",4)==0)
    {
        int x,y,lod;
        unsigned int id;
        sscanf(name.c_str(),"tile%d_%dx%d_%u",&lod,&x,&y,&id);
        osg::ref_ptr< TXPArchive > archive = getArchive(id,osgDB::getFilePath(file));
        if (archive == NULL)
            return ReadResult::ERROR_IN_READING_FILE;

        // The way this is done a 'tile' should only be created for lod 0 only,
        // something is wrong if this is no the case
        if(lod != 0)
        {
            ReaderWriterTXPERROR("ReaderWriterTXP::local_readNode()") << "paged 'tile' should be at lod 0" << std::endl;
            return ReadResult::ERROR_IN_READING_FILE;
        }

        trpgEndian endian = archive->GetEndian();
        archive->ReadSubArchive( 0, 0, endian);
        archive->ReadSubArchive( y, x, endian);

//    std::cout << "Attempted " << x << " " << y << std::endl;

        TXPArchive::TileInfo info;
        if (!archive->getTileInfo(x,y,lod,info))
            return ReadResult::ERROR_IN_READING_FILE;

        std::vector<TXPArchive::TileLocationInfo> childrenLoc;
        osg::ref_ptr<osg::Node> tileContent = getTileContent(info,x,y,lod,archive.get(), childrenLoc);

        tileContent->setName("TileContent");

        bool asChildren = false;
        std::string childrenInfoStr;

        int numLods = archive->getNumLODs();

        int majorVersion, minorVersion;
        archive->GetVersion(majorVersion, minorVersion);
        if(majorVersion ==2 && minorVersion >=1)
        {
            // Version 2.1 and over
            // The tile table only contains lod 0 and the children
            // info are stored in its parent. SO if we do not want
            // to be forced to reparse the parent we need to save that
            // info. For now we just add it to the node name

            if(childrenLoc.size() > 0)
            {
                asChildren = true;
                createChildrenLocationString(childrenLoc, childrenInfoStr);
            }
        }
        else
        {
            if (lod < (numLods-1)) asChildren = true;
        }

        if (asChildren)
        {
            char pagedLODfile[1024];
            sprintf(pagedLODfile,"%s\\subtiles%d_%dx%d_%d",
            archive->getDir(),
            lod,
            x,
            y,
            archive->getId());

            strcat(pagedLODfile, childrenInfoStr.c_str());
            strcat(pagedLODfile, ".txp");

            // there are tile sets which do not maintain the z extents in
            // the tile table.  This attempt to address the issue by using
            // the geometry bounding sphere.  The downside is that this is
            // not coupled to the generation and may result in runtime cracks
            if (info.center.z() == 0)
            {
                osg::BoundingSphere bSphere = tileContent->getBound();

                info.center.z() = bSphere.center().z();
                info.radius = bSphere.radius();
            }

            osg::ref_ptr<TXPPagedLOD> pagedLOD = new TXPPagedLOD;
            // note: use maximum(info.maxRange,1e7) as just maxRange would result in some corner tiles from being
culled out.
            pagedLOD->addChild(tileContent.get(),info.minRange,osg::maximum(info.maxRange,1e7));
            pagedLOD->setFileName(1,pagedLODfile);
            pagedLOD->setRange(1,0,info.minRange);
            pagedLOD->setCenter(info.center);
            pagedLOD->setRadius(info.radius);
            pagedLOD->setPriorityOffset(0,numLods-lod);
            pagedLOD->setPriorityScale(0,1.0f);
            pagedLOD->setNumChildrenThatCannotBeExpired(1);
            pagedLOD->setTileId(x,y,lod);

            const trpgHeader* header = archive->GetHeader();
            trpgHeader::trpgTileType tileType;
            header->GetTileOriginType(tileType);
            if(tileType == trpgHeader::TileLocal)
            {
                osg::Vec3d sw(info.bbox._min);
                pagedLOD->setCenter(info.center - sw);
            }

            return pagedLOD.get();
        }
        else
            return tileContent.get();
    }

    // For 2.0 and lower we load subtilesLOD_XxY_ID.txp
    // For 2.1 and over  we load subtilesLOD_XxY_ID_NBCHILD_{X_Y_FID_FOFFSET_ZMIN_ZMAX_X_Y_ADDR ....}.txp
    else if (strncmp(name.c_str(),"sub",3)==0)
    {
        int x,y,lod;
        unsigned int id;
        sscanf(name.c_str(),"subtiles%d_%dx%d_%u",&lod,&x,&y,&id);
        osg::ref_ptr< TXPArchive > archive = getArchive(id,osgDB::getFilePath(file));
        if (archive == NULL)
            return ReadResult::ERROR_IN_READING_FILE;

        int majorVersion, minorVersion;
        archive->GetVersion(majorVersion, minorVersion);

        std::vector<TXPArchive::TileLocationInfo> childrenLoc;

        osg::ref_ptr<osg::Group> subtiles = new osg::Group;

        int numLods = archive->getNumLODs();

        if(majorVersion == 2  && minorVersion >= 1)
        {
            int nbChild;

            sscanf(name.c_str(),"subtiles%d_%dx%d_%u_%d",&lod,&x,&y,&id, &nbChild);
            std::vector<TXPArchive::TileLocationInfo> locs;
            bool status = true;
            status = extractChildrenLocations(name, lod, locs, nbChild);
            if(majorVersion >= TRPG_NOMERGE_VERSION_MAJOR && minorVersion >=TRPG_NOMERGE_VERSION_MINOR && archive->GetHeader()->GetIsMaster())
            {
                for(int idx=0;idx<nbChild;idx++)
                {
                    //figure out the block row/col
                    int blockx,blocky;
                    unsigned int denom = (1 << locs[idx].lod); // this should work up to lod 31
                    blockx = locs[idx].x/denom;
                    blocky = locs[idx].y/denom;
                    locs[idx].addr.col = blockx;
                    locs[idx].addr.row = blocky;
                }
            }

            if(!status)
            {
                ReaderWriterTXPERROR("ReaderWriterTXP::local_readNode()") << "'subtile' filename children
parsing failed " << std::endl;
                return ReadResult::ERROR_IN_READING_FILE;
            }

            const trpgHeader* header = archive->GetHeader();
            trpgHeader::trpgTileType tileType;
            header->GetTileOriginType(tileType);

            TXPArchive::TileLocationInfo plInfo;
            plInfo.x = x;
            plInfo.y = y;
            plInfo.lod = lod;
            TXPArchive::TileInfo parentInfo;
            archive->getTileInfo(plInfo,parentInfo);

            for(int idx = 0; idx < nbChild; ++idx)
            {
                std::vector<TXPArchive::TileLocationInfo> childrenChildLoc;

                TXPArchive::TileLocationInfo& loc = locs[idx];

                TXPArchive::TileInfo info;
                if (!archive->getTileInfo(loc,info))
                    continue;

                osg::ref_ptr<osg::Node> tileContent = getTileContent(info, loc, archive.get(), childrenChildLoc);

                tileContent->setName("TileContent");

                if(childrenChildLoc.size() > 0)
                {
                    std::string childInfoStr;
                    createChildrenLocationString(childrenChildLoc, childInfoStr);

                    char pagedLODfile[1024];
                    sprintf(pagedLODfile,"%s\\subtiles%d_%dx%d_%d%s.txp",
                        archive->getDir(),
                        loc.lod,
                        loc.x,
                        loc.y,
                        archive->getId(),
                        childInfoStr.c_str());

                    // there are tile sets which do not maintain the z extents in
                    // the tile table.  This attempt to address the issue by using
                    // the geometry bounding sphere.  The downside is that this is
                    // not coupled to the generation and may result in runtime cracks
                    if (info.center.z() == 0)
                    {
                        osg::BoundingSphere bSphere = tileContent->getBound();

                        info.center.z() = bSphere.center().z();
                        info.radius = bSphere.radius();
                    }

                    osg::ref_ptr<TXPPagedLOD> pagedLOD = new TXPPagedLOD;
                            // note: use maximum(info.maxRange,1e7) as just maxRange would result in some corner tiles from being
culled out.
                    pagedLOD->addChild(tileContent.get(),info.minRange,osg::maximum(info.maxRange,1e7));
                    pagedLOD->setFileName(1,pagedLODfile);
                    pagedLOD->setRange(1,0,info.minRange);
                    pagedLOD->setCenter(info.center);
                    pagedLOD->setRadius(info.radius);
                    pagedLOD->setPriorityOffset(0,numLods - loc.lod);
                    pagedLOD->setPriorityScale(0,1.0f);
                    pagedLOD->setNumChildrenThatCannotBeExpired(1);
                    pagedLOD->setTileId(loc.x, loc.y, loc.lod);

                    if(tileType == trpgHeader::TileLocal)
                    {
                        osg::Vec3d center(info.center - parentInfo.bbox._min);
                        osg::Vec3d sw(info.bbox._min - parentInfo.bbox._min);
                        sw[2] = 0.0;
                        pagedLOD->setCenter(center - sw);
                        osg::Matrix offset;
                        offset.setTrans(sw);
                        osg::MatrixTransform *tform = new osg::MatrixTransform(offset);
                        tform->addChild(pagedLOD.get());
                        subtiles->addChild(tform);
                    }
                    else
                        subtiles->addChild(pagedLOD.get());
                        subtiles->setUserData(new TileIdentifier(loc.x, loc.y, loc.lod)); // is this really needed?
                }
                else
                {
                    subtiles->setUserData(new TileIdentifier(loc.x, loc.y, loc.lod));
                    if(tileType == trpgHeader::TileLocal)
                    {
                        osg::Vec3d center(info.center - parentInfo.bbox._min);
                        osg::Vec3d sw(info.bbox._min - parentInfo.bbox._min);
                        sw[2] = 0.0;
                        osg::Matrix offset;
                        offset.setTrans(sw);
                        osg::MatrixTransform *tform = new osg::MatrixTransform(offset);
                        tform->addChild(tileContent.get());
                        subtiles->addChild(tform);
                    }
                    else
                        subtiles->addChild(tileContent.get());
                }
            }
        }
        else
        {

            int sizeX, sizeY;
            archive->getLODSize(lod+1,sizeX,sizeY);

            const trpgHeader* header = archive->GetHeader();
            trpgHeader::trpgTileType tileType;
            header->GetTileOriginType(tileType);

            TXPArchive::TileInfo parentInfo;
            archive->getTileInfo(x,y,lod,parentInfo);

            for (int ix = 0; ix < 2; ix++)
            {
                for (int iy = 0; iy < 2; iy++)
                {
                    int tileX = x*2+ix;
                    int tileY = y*2+iy;
                    int tileLOD = lod+1;

                    TXPArchive::TileInfo info;
                    if (!archive->getTileInfo(tileX,tileY,tileLOD,info))
                    continue;

                    osg::ref_ptr<osg::Node> tileContent = getTileContent(info,tileX,tileY,tileLOD,archive.get(), childrenLoc);

                    tileContent->setName("TileContent");

                    if (tileLOD < (numLods-1))
                    {
                        char pagedLODfile[1024];
                        sprintf(pagedLODfile,"%s\\subtiles%d_%dx%d_%d.txp",
                            archive->getDir(),
                            tileLOD,
                            tileX,
                            tileY,
                            archive->getId());

                        // there are tile sets which do not maintain the z extents in
                        // the tile table.  This attempt to address the issue by using
                        // the geometry bounding sphere.  The downside is that this is
                        // not coupled to the generation and may result in runtime cracks
                        if (info.center.z() == 0)
                        {
                            osg::BoundingSphere bSphere = tileContent->getBound();

                            info.center.z() = bSphere.center().z();
                            info.radius = bSphere.radius();
                        }

                        osg::ref_ptr<TXPPagedLOD> pagedLOD = new TXPPagedLOD;
                                    // note: use maximum(info.maxRange,1e7) as just maxRange would result in some corner tiles from being
culled out.
                        pagedLOD->addChild(tileContent.get(),info.minRange,osg::maximum(info.maxRange,1e7));
                        pagedLOD->setFileName(1,pagedLODfile);
                        pagedLOD->setRange(1,0,info.minRange);
                        pagedLOD->setCenter(info.center);
                        pagedLOD->setRadius(info.radius);
                        pagedLOD->setPriorityOffset(0,numLods-lod);
                        pagedLOD->setPriorityScale(0,1.0f);
                        pagedLOD->setNumChildrenThatCannotBeExpired(1);
                        pagedLOD->setTileId(tileX,tileY,tileLOD);

                        if(tileType == trpgHeader::TileLocal)
                        {
                            osg::Vec3d center(info.center - parentInfo.bbox._min);
                            osg::Vec3d sw(info.bbox._min - parentInfo.bbox._min);
                            sw[2] = 0.0;
                            pagedLOD->setCenter(center - sw);
                            osg::Matrix offset;
                            offset.setTrans(sw);
                            osg::MatrixTransform *tform = new osg::MatrixTransform(offset);
                            tform->addChild(pagedLOD.get());
                            subtiles->addChild(tform);
                        }
                        else
                            subtiles->addChild(pagedLOD.get());
                    }
                    else
                    {
                        subtiles->setUserData(new TileIdentifier(tileX,tileY,tileLOD));
                        if(tileType == trpgHeader::TileLocal)
                        {
                            osg::Vec3d center(info.center - parentInfo.bbox._min);
                            osg::Vec3d sw(info.bbox._min - parentInfo.bbox._min);
                            sw[2] = 0.0;
                            osg::Matrix offset;
                            offset.setTrans(sw);
                            osg::MatrixTransform *tform = new osg::MatrixTransform(offset);
                            tform->addChild(tileContent.get());
                            subtiles->addChild(tform);
                        }
                        else
                            subtiles->addChild(tileContent.get());
                    }

                }
            }
        }

        //OSG_NOTICE << "Subtiles for " << x << " " << y << " " << lod << " lodaded" << std::endl;
        return subtiles.get();
    }

    return ReadResult::ERROR_IN_READING_FILE;
}

// If you change this then you have to change extractChildrenLocation()
void ReaderWriterTXP::createChildrenLocationString(const
std::vector<TXPArchive::TileLocationInfo>& locs, std::string& locString) const
{
    std::stringstream theLoc;

    if(locs.size() == 0)
    {
        theLoc << "_" << locs.size();
    }
    else
    {

        theLoc << "_" << locs.size() << "_" << "{" ;

        for(unsigned int idx = 0; idx < locs.size(); ++idx)
        {
            const TXPArchive::TileLocationInfo& loc = locs[idx];

            theLoc << loc.x
                   << "_"
                   << loc.y
                   << "_"
                   << loc.addr.file
                   << "_"
                   << loc.addr.offset
                   << "_"
                   << loc.zmin
                   << "_"
                   << loc.zmax;
            if(idx != locs.size() -1)
                theLoc << "_";
        }
    }

    theLoc << "}" << std::ends;

    locString = theLoc.str();
}
bool ReaderWriterTXP::extractChildrenLocations(const std::string& name, int parentLod,
std::vector<TXPArchive::TileLocationInfo>& locs, int nbChild) const
{
    locs.clear();

    if(nbChild == 0)
        return true;

    locs.resize(nbChild);

    // We look for '{', which should be the start of the list of {x,y,addr} children data
    // '}' should end the list.
    // We expect: X,Y,FID,FOFFSET,ZMIN,ZMAX
    std::string::size_type startOfList = name.find_last_of('{');
    if(startOfList == std::string::npos)
        return false;

    std::string::size_type endOfList = name.find_last_of('}');
    if(endOfList == std::string::npos)
        return false;

    // Extract the data
    strcpy(gbuf, name.substr(startOfList + 1, endOfList - startOfList - 1).c_str());
    char *token = strtok( gbuf, "_" );

    int nbTokenRead = 0;
    for(int idx = 0; idx < nbChild; idx++)
    {
        // X
        if(!token)
            break;
        locs[idx].x = atoi(token);
        nbTokenRead++;

        // Y
        token = strtok(0, "_");
        if(!token)
            break;
        locs[idx].y = atoi(token);
        nbTokenRead++;

        // FID
        token = strtok(0, "_");
        if(!token)
            break;
        locs[idx].addr.file = atoi(token);
        nbTokenRead++;

        // OFFSET
        token = strtok(0, "_");
        if(!token)
            break;
        locs[idx].addr.offset = atoi(token);
        nbTokenRead++;

        // ZMIN
        token = strtok(0, "_");
        if(!token)
            break;
        locs[idx].zmin = osg::asciiToFloat(token);
        nbTokenRead++;

        // ZMAX
        token = strtok(0, "_");
        if(!token)
            break;
        locs[idx].zmax = osg::asciiToFloat(token);
        nbTokenRead++;

        locs[idx].lod = parentLod+1;

        token = strtok(0, "_");
    }

    if(nbTokenRead != nbChild*6)
        return false;
    else
        return true;

}

std::string ReaderWriterTXP::getArchiveName(const std::string& dir)
{
#ifdef _WIN32
    const char _PATHD = '\\';
#elif defined(macintosh)
    const char _PATHD = ':';
#else
    const char _PATHD = '/';
#endif

    return dir+_PATHD+"archive.txp";
}

osg::ref_ptr< TXPArchive > ReaderWriterTXP::getArchive(int id, const std::string& dir)
{
    osg::ref_ptr< TXPArchive > archive = NULL;

    std::map< int,osg::ref_ptr<TXPArchive> >::iterator iter = _archives.find(id);

    if (iter != _archives.end())
    {
        archive = iter->second.get();
    }
    else
    {
        std::string archiveName = getArchiveName(dir);
        ReaderWriterTXPERROR("getArchive()") << "archive id " << id << " not found: \"" << archiveName << "\"" << std::endl;
    }
    return archive;
}

osg::ref_ptr< TXPArchive > ReaderWriterTXP::createArchive(int id, const std::string& dir)
{
    std::string archiveName = getArchiveName(dir);

    osg::ref_ptr< TXPArchive > archive = getArchive(id, dir);
    if (archive != NULL)
    {
        ReaderWriterTXPERROR("createArchive()") << "archive id " << id << " already exists: \"" << archiveName
<< "\"" << std::endl;
        return NULL;
    }

    archive = new TXPArchive;
    if (archive->openFile(archiveName) == false)
    {
        ReaderWriterTXPERROR("createArchive()") << "failed to load archive: \"" << archiveName << "\"" << std::endl;
        return NULL;
    }

    if (archive->loadMaterials() == false)
    {
        ReaderWriterTXPERROR("createArchive()") << "failed to load materials from archive: \"" <<
archiveName << "\"" << std::endl;
        return NULL;
    }

    if (archive->loadModels() == false)
    {
        ReaderWriterTXPERROR("createArchive()") << "failed to load models from archive: \"" << archiveName <<
"\"" << std::endl;
        return NULL;
    }

    if (archive->loadLightAttributes() == false)
    {
        ReaderWriterTXPERROR("createArchive()") << "failed to load light attributes from archive: \"" <<
archiveName << "\"" << std::endl;
        return NULL;
    }

    if (archive->loadTextStyles() == false)
    {
        ReaderWriterTXPERROR("createArchive()") << "failed to load text styles from archive: \"" <<
archiveName << "\"" << std::endl;
        return NULL;
    }

    archive->setId(id);

    _archives[id] = archive;

    return archive;
}

bool ReaderWriterTXP::removeArchive( int id )
{
    OSG_INFO<<"ReaderWriterTXP::removeArchive(id="<<id<<")"<<std::endl;
    //return (_archives.erase(id) >= 1);
    bool result=_archives.erase(id) >= 1;
    OSG_WARN<<"remove archive " << id << " size " << _archives.size()
        << " result " << result << std::endl;
    return result;

}

class SeamFinder: public osg::NodeVisitor
{
public:
    SeamFinder(int x, int y, int lod, const TXPArchive::TileInfo& info, TXPArchive *archive ):
    osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
    _x(x), _y(y), _lod(lod), _info(info), _archive(archive)
    {}

    virtual void apply(osg::Group& group)
    {
        for (unsigned int i = 0; i < group.getNumChildren(); i++)
        {
            osg::Node* child = group.getChild(i);
            osg::Node* seam = seamReplacement(child);
            if (child != seam)
            {
                group.replaceChild(child,seam);
            }
            else
            {
                child->accept(*this);
            }
        }
    }

protected:
    osg::Node* seamReplacement(osg::Node* node);

    SeamFinder& operator = (const SeamFinder&) { return *this; }

    int _x, _y, _lod;
    const TXPArchive::TileInfo& _info;
    TXPArchive *_archive;
};

#define equalDoubles(a, b) (fabs(a-b) < 0.001)

osg::Node* SeamFinder::seamReplacement(osg::Node* node)
{
    osg::Group* group = node->asGroup();
    if ( group == 0 )
        return node;

    std::vector<osg::Node*> nonSeamChildren;
    osg::LOD* hiRes = 0;
    osg::LOD* loRes = 0;

    const trpgHeader* header = _archive->GetHeader();
    trpgHeader::trpgTileType tileType;
    header->GetTileOriginType(tileType);

    for (unsigned int i = 0; i < group->getNumChildren(); i++)
    {
        osg::LOD* lod = dynamic_cast<osg::LOD*>(group->getChild(i));
        if (lod == 0)
        {
            nonSeamChildren.push_back(group->getChild(i));
            continue;
        }

        bool nonSeamChild = true;

        // looks like the problem is in here - likely due to seamLOD info
        // not being adjusted properly in tiled databases
            // seam center is outside the bounding box of the tile
        osg::Vec3 lodCenter = lod->getCenter();

        if(tileType == trpgHeader::TileLocal)
        {
            trpg2dPoint tileExtents;
            header->GetTileSize(0, tileExtents);
            osg::BoundingBox bbox;
            _archive->getExtents(bbox);
            osg::Vec3 offset(0.0, 0.0, 0.0);

            int divider = (0x1 << _lod);
            // calculate which tile model is located in
            tileExtents.x /= divider;
            tileExtents.y /= divider;
            offset[0] = _x*tileExtents.x;// + tileExtents.x*0.5;
            offset[1] = _y*tileExtents.y;// + tileExtents.y*0.5;
            lodCenter += offset;
        }

        if (!_info.bbox.contains(lodCenter))
        {
            const osg::LOD::RangeList& rangeList = lod->getRangeList();
            if (!rangeList.size())
            {
                // TODO: Warn here
                continue;
            }

            TXPArchive::TileInfo lod_plus_one_info;
            if (!this->_archive->getTileInfo(_x,_y,_lod+1,lod_plus_one_info))
            {
                // TODO: Warn here
                continue;
            }

            double lod_plus_oneSwitchInDistance =  lod_plus_one_info.maxRange;
            double lod0SwitchInDistance =  _info.lod0Range;

            // low res seam has min/max ranges of lod+1 range/lod 0 range
            if (equalDoubles(lod_plus_oneSwitchInDistance,rangeList.at(0).first) && equalDoubles(lod0SwitchInDistance,rangeList.at(0).second))
            {
                if (loRes==0)
                {
                    loRes = lod;
                    nonSeamChild = false;
                }
            }
            else
            // hi res seam has min/max ranges of 0 range/lod+1 range
            if (rangeList.at(0).first==0.0 && equalDoubles(lod_plus_oneSwitchInDistance,rangeList.at(0).second))
            {
                if (hiRes==0)
                {
                    hiRes = lod;
                    nonSeamChild = false;
                }
            }
        }
        if (nonSeamChild)
        {
            nonSeamChildren.push_back(lod);
        }
    }

    if (loRes)
    {
        int dx = 0;
        int dy = 0;
        int lod = _lod;
        osg::Vec3 lodCenter = loRes->getCenter();

        if(tileType == trpgHeader::TileLocal)
        {
            trpg2dPoint tileExtents;
            header->GetTileSize(0, tileExtents);
            osg::BoundingBox bbox;
            _archive->getExtents(bbox);
            osg::Vec3 offset(0.0, 0.0, 0.0);

            int divider = (0x1 << _lod);
            // calculate which tile model is located in
            tileExtents.x /= divider;
            tileExtents.y /= divider;
            offset[0] = _x*tileExtents.x;// + tileExtents.x*0.5;
            offset[1] = _y*tileExtents.y;// + tileExtents.y*0.5;
            lodCenter += offset;
        }

        osg::Vec3 delta = lodCenter-_info.center;
        if (fabs(delta.x())>fabs(delta.y()))
        {
            if ( delta.x() < 0.0 )
                --dx;    // west
            else
                dx++;                  // east
        }
        else
        {
            if ( delta.y() < 0.0 )
                --dy;    // south
            else
                ++dy;                  // north
        }

        TXPSeamLOD* seam = new TXPSeamLOD(_x, _y, lod, dx, dy);
        seam->setCenter(loRes->getCenter());
        seam->addChild(loRes->getChild(0));        // low res
        if (hiRes)
        {
            seam->addChild(hiRes->getChild(0));    // high res
        }

        if (nonSeamChildren.empty())
        {
            return seam;
        }
        else
        {
            osg::Group* newGroup = new osg::Group;

            newGroup->addChild(seam);

            for (unsigned int i = 0; i < nonSeamChildren.size(); i++)
                newGroup->addChild(nonSeamChildren[i]);

            return newGroup;
        }
    }

    return node;
}

osg::Node* ReaderWriterTXP::getTileContent(const TXPArchive::TileInfo &info, int x, int y, int lod,
TXPArchive* archive,  std::vector<TXPArchive::TileLocationInfo>& childrenLoc)
{
    if ( archive == 0 )
        return 0;

    int majorVersion, minorVersion;
    archive->GetVersion(majorVersion, minorVersion);

    double realMinRange = info.minRange;
    double realMaxRange = info.maxRange;
    double  usedMaxRange = osg::maximum(info.maxRange,1e7);
    osg::Vec3 tileCenter;
    osg::Group* tileGroup =
archive->getTileContent(x,y,lod,realMinRange,realMaxRange,usedMaxRange,tileCenter, childrenLoc);

    // if group has only one child, then simply use its child.
    // if the node is a transform, then stop processing so as to not loose the transformation
    while (tileGroup && !tileGroup->asTransform() &&
           tileGroup->getNumChildren()==1 && tileGroup->getChild(0)->asGroup())
    {
        tileGroup = tileGroup->getChild(0)->asGroup();
    }

    bool doSeam = false;
    if(majorVersion == 2 && minorVersion >= 1)
        doSeam = (childrenLoc.size() > 0);
    else
        doSeam = (lod < (archive->getNumLODs() - 1));

    // Handle seams
    if (tileGroup && doSeam)
    {
        SeamFinder sfv(x,y,lod,info,archive);
        tileGroup->accept(sfv);
    }

    return tileGroup;
}

// this version only gets called if the TXP version is >= than 2.1
osg::Node* ReaderWriterTXP::getTileContent(const TXPArchive::TileInfo &info, const
TXPArchive::TileLocationInfo& loc, TXPArchive* archive, 
std::vector<TXPArchive::TileLocationInfo>& childrenLoc)
{
    if ( archive == 0 )
        return 0;

    // int numLods = archive->getNumLODs();

    double realMinRange = info.minRange;
    double realMaxRange = info.maxRange;
    double usedMaxRange = osg::maximum(info.maxRange,1e7);
    osg::Vec3 tileCenter;
    osg::Group* tileGroup =
archive->getTileContent(loc,realMinRange,realMaxRange,usedMaxRange,tileCenter, childrenLoc);

    // if group has only one child, then simply use its child.
    // if the node is a transform, then stop processing so as to not loose the transformation
    while (tileGroup && !tileGroup->asTransform() &&
           tileGroup->getNumChildren()==1 && tileGroup->getChild(0)->asGroup())
    {
        tileGroup = tileGroup->getChild(0)->asGroup();
    }

    // Handle seams
    if (tileGroup && childrenLoc.size() > 0)
    {
        SeamFinder sfv(loc.x, loc.y, loc.lod, info, archive);
        tileGroup->accept(sfv);
    }

    return tileGroup;
}

REGISTER_OSGPLUGIN(txp, ReaderWriterTXP)

_______________________________________________
osg-submissions mailing list
osg-submissions@...
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
Tim George | 30 Jul 00:39 2014

FBO Blit issue in RenderStage.cpp

Hi,

Currently there is a problem with using a camera with a viewport with a non 0 offset and also using an FBO. The
problem is that only area made up of the viewports width and height is drawn based on an offset of 0,0 instead
of using the viewports offset. 

It is caused by line 991 in RenderStage.cpp:

Code:
fbo_ext->glBlitFramebuffer(
0, 0, static_cast<GLint>(_viewport->width()), static_cast<GLint>(_viewport->height()), 
0, 0, static_cast<GLint>(_viewport->width()), static_cast<GLint>(_viewport->height()), 
blitMask, GL_NEAREST);

which is not taking into account the viewport x and y when performing the blit. It probably should be:

Code:
fbo_ext->glBlitFramebuffer(
static_cast<GLint>(_viewport->x()), static_cast<GLint>(_viewport->y()),
static_cast<GLint>(_viewport->width()) + static_cast<GLint>(_viewport->x()),
static_cast<GLint>(_viewport->height()) + static_cast<GLint>(_viewport->y()), 
static_cast<GLint>(_viewport->x()), static_cast<GLint>(_viewport->y()), 
static_cast<GLint>(_viewport->width()) + static_cast<GLint>(_viewport->x()),
static_cast<GLint>(_viewport->height()) + static_cast<GLint>(_viewport->y()), 
blitMask, GL_NEAREST);

instead

Also line 1010 appears to have the same problem.

Thanks,
Tim[/code]

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=60506#60506
Don Tolley | 20 Jul 23:47 2014
Picon

Re: FFMPEG plug-in fixes

Hi,

I am tried using this fix, however while I did get sound but it is distorted.  I am using the 3.2.1 version of OSG
and the latest ffmpeg build for windows.

What version of ffmpeg did you use for your tests by the way? any suggestions?

Cheers,

Don

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=60367#60367
Jaap Glas | 17 Jul 14:56 2014

Crash-fix in Glyph.cpp if scene has 2D textures with stride

Dear all,

I am an employee of dGB Earth Sciences. We have ported the 3D visualization
of our open-source seismic interpretation package OpendTect to OpenSceneGraph.
We are currently in the bug fixing stage of the OpendTect 5.0 beta-release.

I want to submit a bugfix for a crash occurring in osgText/Glyph.cpp if
the scene tree contains (large) 2D textures from images with STRIDE.

============================================================================
#0  0x00007fffe8ea4350 in __memmove_ssse3 () from /lib64/libc.so.6
#1  0x00007fffe52ced76 in ?? () from /usr/lib64/libnvidia-glcore.so.310.44
#2  0x00007fffe52d8e86 in ?? () from /usr/lib64/libnvidia-glcore.so.310.44
#3  0x00007fffe53dd8be in ?? () from /usr/lib64/libnvidia-glcore.so.310.44
#4  0x00007fffe53c2643 in ?? () from /usr/lib64/libnvidia-glcore.so.310.44
#5  0x00007fffe53c7fdd in ?? () from /usr/lib64/libnvidia-glcore.so.310.44
#6  0x00007fffe53cbabf in ?? () from /usr/lib64/libnvidia-glcore.so.310.44
#7  0x00007fffe53cc1fa in ?? () from /usr/lib64/libnvidia-glcore.so.310.44
#8  0x00007ffff30092fd in osgText::GlyphTexture::apply (this=0x1bb8cf0, state=
    ...)
    at /d43/jaap/dev/jaapOSG/build/OpenSceneGraph3.3.1/src/osgText/Glyph.cpp:234
#9  0x00007ffff56c30b6 in osg::State::applyAttributeOnTexUnit (this=0x125f180,
    unit=0, attribute=0x1bb8cf0, as=...)
    at /d43/jaap/dev/jaapOSG/build/OpenSceneGraph3.3.1/include/osg/State:1713
#10 0x00007ffff56c2f3f in osg::State::applyTextureAttribute (this=0x125f180,
    unit=0, attribute=0x1bb8cf0)
    at /d43/jaap/dev/jaapOSG/build/OpenSceneGraph3.3.1/include/osg/State:411
#11 0x00007ffff30204da in osgText::Text::drawTextWithBackdrop (this=0x1baed70,
    state=..., colorMultiplier=...)
==============================================================================

The crash disappears if I either (1) disable the use of images with stride
in the (public) osgGeo-library, or (2) add the following bugfix to Glyph.cpp.
This combination gives me the confidence that I understand where this problem
originates from, without trying to understand the full OpenGL details. 

===============================================================================
<at> <at> -221,7 +223,12 <at> <at>
             imageData[i] = 0;
         }
 
+        glPixelStorei(GL_UNPACK_ALIGNMENT,1);
 
+        #if !defined(OSG_GLES1_AVAILABLE) && !defined(OSG_GLES2_AVAILABLE)
+        glPixelStorei(GL_UNPACK_ROW_LENGTH,getTextureWidth());
+        #endif
+
         // allocate the texture memory.
         glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA,
                 getTextureWidth(), getTextureHeight(), 0,
================================================================================

I have copied (and adapted) the added lines above from the same source file,
where they were used in front of a similar call to glTexSubImage2D(.) around
line 515.

QUESTION: The only thing I am wondering is whether exactly the same bugfix
should also be added in front of the call to glTexSubImage2D(.) around
line 376, where "the image is subloaded once"?

The attached file osgText/Glyph.cpp with modifications was taken from the
OSG 3.3.1 developers release, but the same bugfix(es) should go into the
OSG 3.2 stable release too.


Best regards,

Jaap Glas

--
--
dr. Jaap C. Glas
Software Engineer
______________________________

dGB Earth Sciences
Phone: +31 53 4315155
E-mail: jaap.glas-T0UFp3o85ygAvxtiuMwx3w@public.gmane.org
Internet: dgbes.com & opendtect.org
______________________________
Attachment (Glyph.cpp): text/x-c++src, 21 KiB
_______________________________________________
osg-submissions mailing list
osg-submissions@...
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
Pjotr Svetachov | 16 Jul 16:10 2014
Picon

remove unneeded ref_ptrs in the cullvisitor.

Hi Robert,

I think I spotted some unneeded ref_ptrs in the cullvisitor. The call
pushModelViewMatrix or pushProjectionMatrix will already keep the
reference when adding it to the MatrixStack. In CullVisitor::apply
methods for the billboard and the camera you already take a pointer
instead of a ref_ptr.

Cheers,
Pjotr
Attachment (CullVisitor.cpp): text/x-c++src, 76 KiB
_______________________________________________
osg-submissions mailing list
osg-submissions@...
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
Luc Frauciel | 10 Jul 11:48 2014

Bug in osgviewerQt with QT5/VS2012/Windows7

Hi Robert,

 

We’ve recently upgraded to a QT5/VS2012/Windows7 environment.

We use an application that uses osgviewerQt model for Qt/OpenSceneGraph integration.

With the new environment, the application hang each time a widget partially covers the QGLWidget.

Some investigation showed that it was related to QTimer used to refresh the widget.

The problem is similar to this thread :

https://bugreports.qt-project.org/browse/QTBUG-27266

A solution is to fire the timer only once and repeat once called.

This problem only appear on windows, with VS2012, QT up to 5.3,  but the new behavior shouldn’t affect negatively other platforms.

 

    Regards,

 

Luc Frauciel
Responsable R&D

R&D Manager

 









1Spatial France SAS

Les informations contenues dans cet e-mail sont confidentielles et uniquement adressées au destinataire. Les opinions qui y sont exprimées peuvent être celles de l'auteur et ne représentent pas nécessairement celles du Groupe 1Spatial. Cet e-mail a été scanné et est garanti sans aucun virus. 1Spatial France SAS est une société de droit français, membre du Groupe 1Spatial. Siège Social : Immeuble AXEO2, 23-25 Avenue Aristide Briand, 94110 Arcueil, France. RCS CRETEIL 334 416 336

#include <QTimer>
#include <QApplication>
#include <QGridLayout>

#include <osgViewer/CompositeViewer>
#include <osgViewer/ViewerEventHandlers>

#include <osgGA/MultiTouchTrackballManipulator>

#include <osgDB/ReadFile>

#include <osgQt/GraphicsWindowQt>

#include <iostream>

class ViewerWidget : public QWidget, public osgViewer::CompositeViewer
{
public:
    ViewerWidget(osgViewer::ViewerBase::ThreadingModel
threadingModel=osgViewer::CompositeViewer::SingleThreaded) : QWidget()
    {
        setThreadingModel(threadingModel);

        // disable the default setting of viewer.done() by pressing Escape.
        setKeyEventSetsDone(0);

        QWidget* widget1 = addViewWidget( createGraphicsWindow(0,0,100,100),
osgDB::readNodeFile("cow.osgt") );
        QWidget* widget2 = addViewWidget( createGraphicsWindow(0,0,100,100),
osgDB::readNodeFile("glider.osgt") );
        QWidget* widget3 = addViewWidget( createGraphicsWindow(0,0,100,100),
osgDB::readNodeFile("axes.osgt") );
        QWidget* widget4 = addViewWidget( createGraphicsWindow(0,0,100,100),
osgDB::readNodeFile("fountain.osgt") );
        QWidget* popupWidget = addViewWidget( createGraphicsWindow(900,100,320,240,"Popup
window",true), osgDB::readNodeFile("dumptruck.osgt") );
        popupWidget->show();

        QGridLayout* grid = new QGridLayout;
        grid->addWidget( widget1, 0, 0 );
        grid->addWidget( widget2, 0, 1 );
        grid->addWidget( widget3, 1, 0 );
        grid->addWidget( widget4, 1, 1 );
        setLayout( grid );

        connect( &_timer, SIGNAL(timeout()), this, SLOT(update()) );
		_timer.setSingleShot(true);
        _timer.start( 10 );
    }

    QWidget* addViewWidget( osgQt::GraphicsWindowQt* gw, osg::Node* scene )
    {
        osgViewer::View* view = new osgViewer::View;
        addView( view );

        osg::Camera* camera = view->getCamera();
        camera->setGraphicsContext( gw );

        const osg::GraphicsContext::Traits* traits = gw->getTraits();

        camera->setClearColor( osg::Vec4(0.2, 0.2, 0.6, 1.0) );
        camera->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) );
        camera->setProjectionMatrixAsPerspective(30.0f,
static_cast<double>(traits->width)/static_cast<double>(traits->height), 1.0f, 10000.0f );

        view->setSceneData( scene );
        view->addEventHandler( new osgViewer::StatsHandler );
        view->setCameraManipulator( new osgGA::MultiTouchTrackballManipulator );
        gw->setTouchEventsEnabled( true );
        return gw->getGLWidget();
    }

    osgQt::GraphicsWindowQt* createGraphicsWindow( int x, int y, int w, int h, const std::string& name="",
bool windowDecoration=false )
    {
        osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
        osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
        traits->windowName = name;
        traits->windowDecoration = windowDecoration;
        traits->x = x;
        traits->y = y;
        traits->width = w;
        traits->height = h;
        traits->doubleBuffer = true;
        traits->alpha = ds->getMinimumNumAlphaBits();
        traits->stencil = ds->getMinimumNumStencilBits();
        traits->sampleBuffers = ds->getMultiSamples();
        traits->samples = ds->getNumMultiSamples();

        return new osgQt::GraphicsWindowQt(traits.get());
    }

    virtual void paintEvent( QPaintEvent* event )
    { 
	    frame();
		_timer.start( 10 );
	}

protected:

    QTimer _timer;
};

int main( int argc, char** argv )
{
    osg::ArgumentParser arguments(&argc, argv);

#if QT_VERSION >= 0x050000
    // Qt5 is currently crashing and reporting "Cannot make QOpenGLContext current in a different thread"
when the viewer is run multi-threaded, this is regression from Qt4
    osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::SingleThreaded;
#else
    osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::CullDrawThreadPerContext;
#endif

    while (arguments.read("--SingleThreaded")) threadingModel = osgViewer::ViewerBase::SingleThreaded;
    while (arguments.read("--CullDrawThreadPerContext")) threadingModel = osgViewer::ViewerBase::CullDrawThreadPerContext;
    while (arguments.read("--DrawThreadPerContext")) threadingModel = osgViewer::ViewerBase::DrawThreadPerContext;
    while (arguments.read("--CullThreadPerCameraDrawThreadPerContext")) threadingModel = osgViewer::ViewerBase::CullThreadPerCameraDrawThreadPerContext;

    QApplication app(argc, argv);
    ViewerWidget* viewWidget = new ViewerWidget(threadingModel);
    viewWidget->setGeometry( 100, 100, 800, 600 );
    viewWidget->show();
    return app.exec();
}
_______________________________________________
osg-submissions mailing list
osg-submissions@...
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
Voerman, L. | 8 Jul 13:11 2014
Picon

bug in deprecated-dotosg ProxyNode with NULL options

Hi Robert,
I found a new way to crach the osgviewer:
osgviewer "ProxyNode { FileNameList { cow.osgt } num_children 1 }".osgs

The proxy node reader wrongly assumes options to be non NULL.

fixed in attached zip:
src\osgWrappers\deprecated-dotosg\osg\ProxyNode.cpp

applies to both the 3.2 branch and svn trunk

Regards, Laurens.

_______________________________________________
osg-submissions mailing list
osg-submissions@...
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
FlySky | 8 Jul 04:37 2014

Compile fix for Visual Studio

 
Hi Robert,
 
    osgviewer.cpp(3.3.2) compile error with vs2003-vs2008 :
   .\osgviewer.cpp(41) : fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory
  
   Visual Studio 2003 - 2008 (Visual C++ 7.1 - 9) don't claim to be C99 compatible.
 
   code:
   #include <stdint.h>
 
   Just define them.
 
   #ifdef _MSC_VER
   typedef __int32 int32_t;
   typedef unsigned __int32 uint32_t;
   typedef __int64 int64_t;
   typedef unsigned __int64 uint64_t;
   #else
   #include <stdint.h>
   #endif
 
cheers,
 
FlySky
 


_______________________________________________
osg-submissions mailing list
osg-submissions@...
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
Mikhail Matrosov | 7 Jul 15:24 2014
Picon

Division by zero on resize

When viewer width or height is equal to zero, division by zero occurs in GraphicsContext::resizedImplementation(). It breaks camera projection matrix and the scene is not drawn. 

Many people have already experienced this issue when viewer is added as QWidget to QTabWidget or QMdiArea. See http://forum.openscenegraph.org/viewtopic.php?t=7239

In the attached GraphicsContext.cpp file call to GraphicsContext::resizedImplementation() is ignored in the case any dimension is equal to zero. This fixes the issue for me.

Base version of OSG is 3.2.1, published in stable releases.

-----
Best regards, Mikhail Matrosov
Attachment (GraphicsContext.cpp): text/x-c++src, 41 KiB
_______________________________________________
osg-submissions mailing list
osg-submissions@...
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
Voerman, L. | 2 Jul 11:53 2014
Picon

MSVC warning: InteractiveImageHandler inherits run via dominance

Hi Robert,
just like ClusterCullingCallback (fixed in r14322) visual studio likes an explicit implementation of run() for InteractiveImageHandler.

The warning is (14 times):
include\osgViewer/ViewerEventHandlers(542): warning C4250: 'osgViewer::InteractiveImageHandler' : inherits 'osgGA::EventHandler::osgGA::EventHandler::run' via dominance (src\osgViewer\StatsHandler.cpp)
          include\osgGA/EventHandler(45) : see declaration of 'osgGA::EventHandler::run'


attached a zipped version of include\osgViewer\ViewerEventHandlers
patch applies to svn trunk (3.3.3) only.

Regards, Laurens.
Attachment (ViewerEventHandlers.zip): application/zip, 6958 bytes
_______________________________________________
osg-submissions mailing list
osg-submissions@...
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
We See | 30 Jun 13:49 2014
Picon

Re: Change CPU-affinity of DatabaseThreads

Hi Robert,
A long time ago (Nov 2013) I submitted a small change for DatabasePager, which allows users to change the
CPU-affinity of DatabaseThread. You never answerred to this submission and also did not merge it in.

Is there a problem with this change or did you simply overlook it?

Please could you have a look at this (for me important) extension and merge it in, or tell me what's wrong with it?

Thank you!

Cheers,
WeSee

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=60064#60064

Gmane