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