Hi Robert,

I went thru the TileMapper today very carefuly and I remove all the
tileStack approach - it made everything simplier and I think more proper.
Cleaned the code as well. It was tested on huge archive with many lods as
well with variable lods. Fix attached.

I swear, with this no more issues will be reported !

Updated code attached. Please CI into svn, I will call again for testing
(the community is silent though :-) .. is this so acient so noone is using
it anymore? :)

Cheers,
-Nick


On Tue, Dec 14, 2010 at 11:20 PM, Trajce (Nick) Nikolov <
[email protected]> wrote:

>  Okay
>
> -Nick
>
>
>   On Tue, Dec 14, 2010 at 11:10 PM, Robert Osfield <
> [email protected]> wrote:
>
>> Hi Nick,
>>
>> On Tue, Dec 14, 2010 at 6:43 PM, Trajce (Nick) Nikolov
>> <[email protected]> wrote:
>> > So, good time to call the community to do tests. If all ok, then I clean
>> it
>>
>> Could you do the call for testing and coordinate the thread as I've
>> got a number of other issues to juggle with right now.
>>
>> Cheers,
>>  Robert.
>> _______________________________________________
>> osg-submissions mailing list
>> [email protected]
>>
>> http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
>>
>
>
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2004 Robert Osfield 
 *
 * This library is open source and may be redistributed and/or modified under  
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 * 
 * This library 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 
 * OpenSceneGraph Public License for more details.
*/

/*	Dec 2010 - TileMapper was fixed and simplified
	Nick
*/

#include "TileMapper.h"
#include "TXPPagedLOD.h"

#include <osg/Material>

using namespace txp;

float TileMapper::getDistanceToEyePoint(const osg::Vec3& pos, bool withLODScale) const
{
    if (withLODScale)
	return (pos-getEyeLocal()).length()*getLODScale();
    else
	return (pos-getEyeLocal()).length();
}

inline TileMapper::value_type distance(const osg::Vec3& coord,const osg::Matrix& matrix)
{

    return -((TileMapper::value_type)coord[0]*(TileMapper::value_type)matrix(0,2)+
	     (TileMapper::value_type)coord[1]*(TileMapper::value_type)matrix(1,2)+
	     (TileMapper::value_type)coord[2]*(TileMapper::value_type)matrix(2,2)+
	     matrix(3,2));
}

float TileMapper::getDistanceFromEyePoint(const osg::Vec3& pos, bool withLODScale) const
{
    const osg::Matrix& matrix = *_modelviewStack.back();
    float dist = distance(pos,matrix);
    
    if (withLODScale)
	return dist*getLODScale();
    else
	return dist;
}

void TileMapper::apply(osg::Node& node)
{
    if (node.getName()=="TileContent") 
    {
        _containsGeode = true;
        return;
    }

    if (isCulled(node))
	return;

    // push the culling mode.
    pushCurrentMask();

    traverse(node);

    // pop the culling mode.
    popCurrentMask();
}

void TileMapper::apply(osg::Group& node)
{
    if (node.getName()=="TileContent") 
    {
        _containsGeode = true;
        return;
    }

    if (isCulled(node))
	return;

    // push the culling mode.
    pushCurrentMask();

    TileIdentifier* tid = dynamic_cast<TileIdentifier*>(node.getUserData());
    
    if (tid)
    {
        _containsGeode = false;
    }

    traverse(node);

    if (tid)
    {
        if (_containsGeode)
        {
            insertTile(*tid);

            _containsGeode = false;

        }
    
    }

    // pop the culling mode.
    popCurrentMask();
}

void TileMapper::apply(osg::Geode&)
{
    _containsGeode = true;
}

void TileMapper::apply(osg::PagedLOD& node)
{
    if (isCulled(node))
	return;

    // push the culling mode.
    pushCurrentMask();

    TXPPagedLOD* txpPagedLOD = dynamic_cast<TXPPagedLOD*>(&node);
    if (txpPagedLOD)
    {
        _containsGeode = false;
    }

    traverse(node);

    if (txpPagedLOD)
    {
        if (_containsGeode)
        {
            insertTile(txpPagedLOD->_tileIdentifier);

            _containsGeode = false;
        }
    }

    // pop the culling mode.
    popCurrentMask();
}

void TileMapper::insertTile(const TileIdentifier& tid)
{
    _tileMap.insert(TileMap::value_type(tid,1));
}


bool TileMapper::isTileNeighbourALowerLODLevel(const TileIdentifier& tid, int dx, int dy) const
{
    if (_tileMap.count(TileIdentifier(tid.x+dx,tid.y+dy,tid.lod))!=0)
    {
        // we have a neightbour at the same lod level.
        return false;
    }

    // find the tiles parents.
    TileMap::const_iterator itr = _tileMap.find(tid);
    if (itr==_tileMap.end())
    {
        // not found tile in _tileMap, what should we do??
        // return true as a fallback right now.
#if 0
		std::cout << "TileMapper::isTileNeighbourALowerLODLevel() Not found tile in map," << std::endl;
		std::cout << "    LOD=" << tid.lod << "  X=" << tid.x << "  Y=" << tid.y << std::endl;
#endif 
        return true;
    }
	TileIdentifier parent_tid(tid.x/2,tid.y/2,tid.lod-1);
    
    bool parentHasNorthNeighour = _tileMap.count(TileIdentifier(parent_tid.x,  parent_tid.y+1,parent_tid.lod))!=0;
    bool parentHasEastNeighour  = _tileMap.count(TileIdentifier(parent_tid.x+1,parent_tid.y,  parent_tid.lod))!=0;
    bool parentHasSouthNeighour = _tileMap.count(TileIdentifier(parent_tid.x,  parent_tid.y-1,parent_tid.lod))!=0;
    bool parentHasWestNeighour  = _tileMap.count(TileIdentifier(parent_tid.x-1,parent_tid.y,  parent_tid.lod))!=0;
    

    // identify whether the tile is a NE/SE/SW/NW tile relative to its parent.
	osg::Vec3 delta(tid.x%2,tid.y%2,0);
    
    if (delta.y()>0.0f) // noth side
    {        
        if (delta.x()>0.0f)
        {
            // NE
            if (dy==1)
				return parentHasNorthNeighour;
            else if (dx==1)
				return parentHasEastNeighour;
        }
        else 
        {
            // NW
            if (dy==1)
				return parentHasNorthNeighour;
            else if (dx==-1)
				return parentHasWestNeighour;
        }
    }
    else // south side
    {
        if (delta.x()>0.0f)
        {
            // SE
            if (dy==-1)
				return parentHasSouthNeighour;
            else if (dx==1)
				return parentHasEastNeighour;
        }
        else 
        {
            // SW
            if (dy==-1)
				return parentHasSouthNeighour;
            else if (dx==-1)
				return parentHasWestNeighour;
        }
    }
    
    return false;
}
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2004 Robert Osfield 
 *
 * This library is open source and may be redistributed and/or modified under  
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 * 
 * This library 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 
 * OpenSceneGraph Public License for more details.
*/

/*	Dec 2010 - TileMapper was fixed and simplified
	Nick
*/

#ifndef __TILEMAPPER_H_
#define __TILEMAPPER_H_

#include "trpage_sys.h"
#include "trpage_read.h"

#include <osg/CullStack>
#include <osg/NodeVisitor>

#include <set>

namespace txp
{

struct TileIdentifier : public osg::Referenced
{
    TileIdentifier():
        x(-1),
        y(-1),
        lod(-1)
	{}

    TileIdentifier(int ax, int ay, int alod):
        x(ax),
        y(ay),
        lod(alod)
	{}
    
    TileIdentifier(const TileIdentifier& rhs):
        osg::Referenced(),
        x(rhs.x),
        y(rhs.y),
        lod(rhs.lod)
	{}

    TileIdentifier& operator = (const TileIdentifier& rhs)
    {
        if (this==&rhs) return *this;
        x = rhs.x;
        y = rhs.y;
        lod = rhs.lod;
        return *this;
    }

    void set(int ax, int ay, int alod)
    {
        x = ax;
        y = ay;
        lod = alod;
    }

    bool operator < (const TileIdentifier& rhs) const
    {
        if (lod<rhs.lod)
            return true;
        if (lod>rhs.lod)
            return false;
        if (x<rhs.x)
            return true;
        if (x>rhs.x)
            return false;
        if (y<rhs.y)
            return true;
        if (y>rhs.y)
            return false;
        return false;
    }

    int x,y,lod;

};

class TileMapper : public osg::NodeVisitor, public osg::CullStack
{
public:
    
    typedef osg::Matrix::value_type value_type;


    TileMapper():
        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN) {}

            
    virtual osg::Vec3 getEyePoint() const
    {
		return getEyeLocal();
    }
    virtual float getDistanceToEyePoint(const osg::Vec3& pos, bool withLODScale) const;
    virtual float getDistanceFromEyePoint(const osg::Vec3& pos, bool withLODScale) const;

    virtual void apply(osg::Node& node);
    virtual void apply(osg::Group& node);
    virtual void apply(osg::Geode& node);
    virtual void apply(osg::PagedLOD& node);
    
    void insertTile(const TileIdentifier& tid);
    
    bool isTileNeighbourALowerLODLevel(const TileIdentifier& tid, int dx, int dy) const;
    
protected:

    typedef std::map< TileIdentifier, int>		TileMap;
    TileMap										_tileMap;
    bool										_containsGeode;
    
};

} // namespace

#endif // __TILEMAPPER_H_
#include <osg/Notify>
#include <osg/BoundingBox>
#include <osg/PagedLOD>
#include <osg/Timer>
#include <osg/MatrixTransform>
#include <osgUtil/CullVisitor>
#include <osgDB/Registry>
#include <osgDB/ReaderWriter>

#include <iostream>
#include <vector>
#include <algorithm>
#include <stdio.h>

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


using namespace txp;
using namespace osg;



class RetestCallback : public osg::NodeCallback
{

public:
    RetestCallback()
    {
        timer = osg::Timer::instance(); // get static timer
        prevTime = 0; // should this be instantiated with current time?
    }

    virtual void operator () ( osg::Node * node, osg::NodeVisitor * nv )
    {
        osg::Group *pLOD = (osg::Group *) node; 
        osg::Group *n = NULL;
        if ((pLOD->getNumChildren() > 0) &&
            (n = (osg::Group *) pLOD->getChild(0)) &&
            (n->getNumChildren() == 0))
        {
            osg::Timer_t curTime = timer->tick();
            if ((prevTime + 2.0/timer->getSecondsPerTick() ) < curTime)
            {
                prevTime = curTime;
                pLOD->removeChildren( 0, pLOD->getNumChildren());
            }
        }

        NodeCallback::traverse( node, nv );
    }

protected:
    const osg::Timer* timer;
    osg::Timer_t prevTime;
};



#define TXPNodeERROR(s) OSG_NOTICE << "txp::TXPNode::" << (s) << " error: "

TXPNode::TXPNode():
osg::Group(),
_originX(0.0),
_originY(0.0)
{
    setNumChildrenRequiringUpdateTraversal(1);
    setCullingActive(false);
}
            
TXPNode::TXPNode(const TXPNode& txpNode,const osg::CopyOp& copyop):
osg::Group(txpNode,copyop),
_originX(txpNode._originX),
_originY(txpNode._originY)
{
    setNumChildrenRequiringUpdateTraversal(1);
}

TXPNode::~TXPNode()
{
   if (_archive.get())
   {
      if (osgDB::ReaderWriter * rw =
          osgDB::Registry::instance()->getReaderWriterForExtension("txp"))
      {
         if (ReaderWriterTXP * rwTXP =
             dynamic_cast< ReaderWriterTXP * >(rw))
         {
            const int id = _archive->getId();
            if (!rwTXP->removeArchive(id))
            {
               TXPNodeERROR("Failed to remove archive ") << id << std::endl;
            }
         }
      }
   }
}

void TXPNode::traverse(osg::NodeVisitor& nv)
{
    switch(nv.getVisitorType())
    {
    case osg::NodeVisitor::CULL_VISITOR:
    {

        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
                
        osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
        if (cv)
        {
//#define PRINT_TILEMAPP_TIMEINFO
#ifdef PRINT_TILEMAPP_TIMEINFO
            const osg::Timer& timer = *osg::Timer::instance();
            osg::Timer_t start = timer.tick();
            std::cout<<"Doing visible tile search"<<std::endl;
#endif // PRINT_TILEMAPP_TIMEINFO
        
            osg::ref_ptr<TileMapper> tileMapper = new TileMapper;
            tileMapper->setLODScale(cv->getLODScale());
            tileMapper->pushReferenceViewPoint(cv->getReferenceViewPoint());
            tileMapper->pushViewport(cv->getViewport());
            tileMapper->pushProjectionMatrix((cv->getProjectionMatrix()));
            tileMapper->pushModelViewMatrix((cv->getModelViewMatrix()), osg::Transform::RELATIVE_RF);

            // traverse the scene graph to search for valid tiles
            accept(*tileMapper);

            tileMapper->popModelViewMatrix();
            tileMapper->popProjectionMatrix();
            tileMapper->popViewport();
            tileMapper->popReferenceViewPoint();

            //std::cout<<"   found " << tileMapper._tileMap.size() << std::endl;
            
            cv->setUserData(tileMapper.get());

#ifdef PRINT_TILEMAPP_TIMEINFO        
            std::cout<<"Completed visible tile search in "<<timer.delta_m(start,timer.tick())<<std::endl;
#endif // PRINT_TILEMAPP_TIMEINFO        

        }        
    
        updateEye(nv);
        break;
    }
    case osg::NodeVisitor::UPDATE_VISITOR:
    {
        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);

        updateSceneGraph();
        break;
    }
    default:
        break;
    }
    Group::traverse(nv);
}

osg::BoundingSphere TXPNode::computeBound() const
{
#if 1

    // Steve Lunsford 10/28/05 : - Had to avoid using the child group nodes for bounds calculation
    // because apparently the loader doesn't load all the sub-tiles for this node, resulting in a Group::computeBounds
    // call which returns a size smaller than the actual size represented by this node so consequently this node gets culled out.
    // note, submission merged and rearranged by Robert Osfield as an #if #else just in case we need to revert.
    return osg::BoundingSphere( _extents );
#else
    // original code which uses the extents of the children when one is available.
    if (getNumChildren() == 0)
    {
        return osg::BoundingSphere( _extents );
    }
    return Group::computeBound();
#endif
}

void TXPNode::setArchiveName(const std::string& archiveName)
{
    _archiveName = archiveName;
}

void TXPNode::setOptions(const std::string& options)
{
    _options = options;
}

const std::string& TXPNode::getOptions() const
{
    return _options;
}

const std::string& TXPNode::getArchiveName() const
{
    return _archiveName;
}

bool TXPNode::loadArchive(TXPArchive* archive)
{
    //if (_archive.get())
    //{
    //    TXPNodeERROR("loadArchive()") << "archive already open" << std::endl;
    //    return false;
    //}


   //modified by Brad Anderegg on May-27-08
   //if NULL is passed in we will create a new archive and open the database
   //otherwise we will use the archive provided which should have already been loaded 
   //by ReaderWriterTXP::getArchive(). See line 57-77 of ReaderWriterTXP.cpp.
   if(archive == NULL)
   {
       _archive = new TXPArchive;
       if (_archive->openFile(_archiveName) == false)
       {
           TXPNodeERROR("loadArchive()") << "failed to load archive: \"" << _archiveName << "\"" << std::endl;
           return false;
       }
   }
   else
   {
      _archive = archive;
   } 

    _archive->getOrigin(_originX,_originY);
    _archive->getExtents(_extents);

    int32 numLod;
    _archive->GetHeader()->GetNumLods(numLod);

    trpg2iPoint tileSize;
    _archive->GetHeader()->GetLodSize(0,tileSize);

    _pageManager = new TXPPageManager;

    // We are going to use _pageManager to manage lod 0 only, all other lod
    // are managed by this OSG plugin
    _pageManager->Init(_archive.get(), 1);

    return true;
}

void TXPNode::updateEye(osg::NodeVisitor& nv)
{
    if (!_pageManager)
    {
        OSG_NOTICE<<"TXPNode::updateEye() no pageManager created"<<std::endl;
        return;
    }

    trpg2dPoint loc;
    loc.x = nv.getEyePoint().x() - _originX;
    loc.y = nv.getEyePoint().y() - _originY;

    if (_pageManager->SetLocation(loc))
    {
        trpgManagedTile *tile=NULL;

        while((tile = _pageManager->GetNextUnload()))
        {
            int x,y,lod;
            tile->GetTileLoc(x,y,lod);
            if (lod == 0)
            {
                osg::Node* node = (osg::Node*)(tile->GetLocalData());
                _nodesToRemove.push_back(node);

                //OSG_NOTICE << "Tile unload: " << x << " " << y << " " << lod << std::endl;
            }
            _pageManager->AckUnload();
        }

        while ((tile = _pageManager->GetNextLoad()))
        {
            int x,y,lod;
            tile->GetTileLoc(x,y,lod);
            if (lod==0)
            {
                osg::Node* node = addPagedLODTile(x,y);
                tile->SetLocalData(node);
                //OSG_NOTICE << "Tile load: " << x << " " << y << " " << lod << std::endl;
            }
            _pageManager->AckLoad();
            
        }
    }
}

osg::Node* TXPNode::addPagedLODTile(int x, int y)
{
    // For TerraPage 2.1 and over this method must only be use with lod = 0.
    // If you look at the code that calls it, it is effectively called only when
    // lod = 0. So all is OK
    int lod = 0;
    char pagedLODfile[1024];
    sprintf(pagedLODfile,"%s\\tile%d_%dx%d_%d.txp",_archive->getDir(),lod,x,y,_archive->getId());


    TXPArchive::TileInfo info;
    _archive->getTileInfo(x,y,lod,info);

    osg::PagedLOD* pagedLOD = new osg::PagedLOD;
    pagedLOD->setFileName(0,pagedLODfile);
    pagedLOD->setPriorityOffset(0,_archive->getNumLODs());
    pagedLOD->setPriorityScale(0,1.0f);
    pagedLOD->setRange(0,0.0,info.maxRange);
    pagedLOD->setCenter(info.center);
    pagedLOD->setRadius(info.radius);
    pagedLOD->setNumChildrenThatCannotBeExpired(1);
    pagedLOD->setUpdateCallback(new RetestCallback);

    const trpgHeader* header = _archive->GetHeader();
    trpgHeader::trpgTileType tileType;
    header->GetTileOriginType(tileType);
    if(tileType == trpgHeader::TileLocal)
    {
        // add in MatrixTransform node with Matrixd offsets
        // get offsets from tile.bbox
        osg::Vec3d sw(info.bbox._min);
        sw[2] = 0.0;
        osg::Matrix offset;
        offset.setTrans(sw);
        osg::MatrixTransform *tform = new osg::MatrixTransform(offset);
        pagedLOD->setCenter(info.center - sw);
        tform->addChild(pagedLOD);
        _nodesToAdd.push_back(tform);
        return tform;
    }
    else
    {
    _nodesToAdd.push_back(pagedLOD);
    
    return pagedLOD;
}
}

void TXPNode::updateSceneGraph()
{
    if (!_nodesToRemove.empty())
    {
        for (unsigned int i = 0; i < _nodesToRemove.size(); i++)
        {
            removeChild(_nodesToRemove[i]);
        }
        _nodesToRemove.clear();
    }

    if (!_nodesToAdd.empty())
    {
        for (unsigned int i = 0; i < _nodesToAdd.size(); i++)
        {
            addChild(_nodesToAdd[i]);
        }
        _nodesToAdd.clear();
        
    }    
}


_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to