Added new mechanism for handling Seams.

This commit is contained in:
Robert Osfield
2004-01-21 17:26:23 +00:00
parent 2f194ad5a0
commit 9d1ace20d9
15 changed files with 855 additions and 676 deletions

View File

@@ -126,10 +126,6 @@ SOURCE=..\..\..\src\osgPlugins\txp\TXPSeamLOD.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\TXPTileNode.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\TileMapper.cpp
# End Source File
# Begin Source File
@@ -254,10 +250,6 @@ SOURCE=..\..\..\src\osgPlugins\txp\TXPSeamLOD.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\TXPTileNode.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\osgPlugins\txp\TileMapper.h
# End Source File
# Begin Source File

View File

@@ -7,7 +7,6 @@ CXXFILES =\
TXPIO.cpp\
TXPNode.cpp\
TXPPageManager.cpp\
TXPTileNode.cpp\
TXPParser.cpp\
TXPSeamLOD.cpp\
TXPPagedLOD.cpp\

View File

@@ -8,8 +8,10 @@
#include "ReaderWriterTXP.h"
#include "TXPNode.h"
#include "TXPTileNode.h"
#include "TXPArchive.h"
#include "TXPPagedLOD.h"
#include "TXPSeamLOD.h"
#include "TileMapper.h"
#define ReaderWriterTXPERROR(s) osg::notify(osg::NOTICE) << "txp::ReaderWriterTXP::" << (s) << " error: "
@@ -59,17 +61,40 @@ osgDB::ReaderWriter::ReadResult ReaderWriterTXP::readNode(const std::string& fil
sscanf(name.c_str(),"tile%d_%dx%d_%d",&lod,&x,&y,&id);
TXPArchive* archive = getArchive(id,osgDB::getFilePath(fileName));
osg::ref_ptr<TXPTileNode> txpTileNode = new TXPTileNode;
txpTileNode->setArchive(archive);
if (txpTileNode->loadTile(x,y,lod))
{
//osg::notify(osg::NOTICE) << "Tile " << x << " " << y << " " << lod << " lodaded" << std::endl;
TXPArchive::TileInfo info;
if (!archive->getTileInfo(x,y,lod,info))
return ReadResult::ERROR_IN_READING_FILE;
return txpTileNode.get();
osg::ref_ptr<osg::Node> tileContent = getTileContent(info,x,y,lod,archive);
int numLods = archive->getNumLODs();
if (lod < (numLods-1))
{
char pagedLODfile[1024];
sprintf(pagedLODfile,"%s\\subtiles%d_%dx%d_%d.txp",
archive->getDir(),
lod,
x,
y,
archive->getId()
);
osg::ref_ptr<TXPPagedLOD> pagedLOD = new TXPPagedLOD;
// not 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);
return pagedLOD.get();
}
else
return ReadResult::ERROR_IN_READING_FILE;
return tileContent.get();
}
// We load subtilesLOD_XxY_ID.txp
@@ -82,6 +107,10 @@ osgDB::ReaderWriter::ReadResult ReaderWriterTXP::readNode(const std::string& fil
osg::ref_ptr<osg::Group> subtiles = new osg::Group;
int numLods = archive->getNumLODs();
int sizeX, sizeY;
archive->getLODSize(lod+1,sizeX,sizeY);
for (int ix = 0; ix < 2; ix++)
for (int iy = 0; iy < 2; iy++)
{
@@ -89,12 +118,41 @@ osgDB::ReaderWriter::ReadResult ReaderWriterTXP::readNode(const std::string& fil
int tileY = y*2+iy;
int tileLOD = lod+1;
TXPTileNode* txpTileNode = new TXPTileNode;
txpTileNode->setArchive(archive);
if (txpTileNode->loadTile(tileX,tileY,tileLOD))
TXPArchive::TileInfo info;
if (!archive->getTileInfo(tileX,tileY,tileLOD,info))
continue;
osg::ref_ptr<osg::Node> tileContent = getTileContent(info,tileX,tileY,tileLOD,archive);
if (tileLOD < (numLods-1))
{
subtiles->addChild(txpTileNode);
char pagedLODfile[1024];
sprintf(pagedLODfile,"%s\\subtiles%d_%dx%d_%d.txp",
archive->getDir(),
tileLOD,
tileX,
tileY,
archive->getId()
);
osg::ref_ptr<TXPPagedLOD> pagedLOD = new TXPPagedLOD;
// not 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);
subtiles->addChild(pagedLOD.get());
}
else
{
subtiles->setUserData(new TileIdentifier(tileX,tileY,tileLOD));
subtiles->addChild(tileContent.get());
}
}
@@ -162,5 +220,167 @@ TXPArchive *ReaderWriterTXP::getArchive(int id, const std::string& dir)
return archive;
}
class SeamFinder: public osg::NodeVisitor
{
public:
SeamFinder(int x, int y, int lod, TXPArchive::TileInfo& info, TXPArchive *archive ):
NodeVisitor(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);
int _x, _y, _lod;
TXPArchive::TileInfo& _info;
TXPArchive *_archive;
};
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;
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;
// seam center is outside the bounding box of the tile
if (!_info.bbox.contains(lod->getCenter()))
{
// seams have center as the neighbour tile
osg::Vec3 d = _info.center - lod->getCenter();
if (((fabs(d.x())-_info.size.x()) > 0.0001) && ((fabs(d.y())-_info.size.y()) > 0.0001))
{
nonSeamChildren.push_back(lod);
continue;
}
// low res seam has min/max ranges of lod+1 range/lod 0 range
if ((fabs(_info.minRange-lod->getMinRange(0))<0.001)&&(fabs(_info.lod0Range-lod->getMaxRange(0))<0.001))
{
if (loRes==0)
{
loRes = lod;
nonSeamChild = false;
}
}
// hi res seam has min/max ranges of 0 range/lod+1 range
if ((lod->getMinRange(0)==0.0f)&&(fabs(_info.minRange-lod->getMaxRange(0))<0.001))
{
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 delta = loRes->getCenter()-_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->addChild(loRes->getChild(0)); // low res
if (hiRes)
{
seam->addChild(hiRes->getChild(0)); // high res
}
if (nonSeamChildren.size())
{
std::cout<<"Alert *** need to place in a seperate osg::Group NOT the TXPSeamLOD"<<std::endl;
for (unsigned int i = 0; i < nonSeamChildren.size(); i++)
seam->addChild(nonSeamChildren[i]);
}
return seam;
}
return node;
}
osg::Node* ReaderWriterTXP::getTileContent(TXPArchive::TileInfo &info, int x, int y, int lod, TXPArchive* archive)
{
if (archive == 0) return false;
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(x,y,lod,realMinRange,realMaxRange,usedMaxRange,tileCenter);
// if group has only one child, then simply use its child.
#if 1
while (tileGroup->getNumChildren()==1 && tileGroup->getChild(0)->asGroup())
{
tileGroup = tileGroup->getChild(0)->asGroup();
}
#endif
// Handle seams
if (lod < (numLods-1))
{
SeamFinder sfv(x,y,lod,info,archive);
tileGroup->accept(sfv);
}
return tileGroup;
}
osgDB::RegisterReaderWriterProxy<ReaderWriterTXP> g_txpReaderWriterProxy;

View File

@@ -43,9 +43,10 @@
#include <osg/Referenced>
#include <map>
#include "TXPArchive.h"
namespace txp
{
class TXPArchive;
class ReaderWriterTXP : public osgDB::ReaderWriter
{
public:
@@ -64,6 +65,8 @@ public:
protected:
TXPArchive *getArchive(int id, const std::string&);
std::map< int,osg::ref_ptr<TXPArchive> > _archives;
osg::Node* getTileContent(TXPArchive::TileInfo &info, int x, int y, int lod, TXPArchive* archive);
static int _archiveId;
};

View File

@@ -224,7 +224,7 @@ bool TXPArchive::loadMaterials()
osg_material->setShininess(osg::Material::FRONT_AND_BACK , (float)shinines);
osg_material->setAlpha(osg::Material::FRONT_AND_BACK ,(float)alpha);
osg_state_set->setAttributeAndModes(osg_material, osg::StateAttribute::ON);
//osg_state_set->setAttributeAndModes(osg_material, osg::StateAttribute::ON);
if( alpha < 1.0f )
{

View File

@@ -1,6 +1,8 @@
#include <osg/Notify>
#include <osg/BoundingBox>
#include <osg/PagedLOD>
#include <osg/Timer>
#include <osgUtil/CullVisitor>
#include <iostream>
#include <vector>
@@ -9,6 +11,9 @@
#include "TileMapper.h"
#include "TXPNode.h"
#include "TXPPagedLOD.h"
using namespace txp;
@@ -46,8 +51,40 @@ void TXPNode::traverse(osg::NodeVisitor& nv)
switch(nv.getVisitorType())
{
case osg::NodeVisitor::CULL_VISITOR:
{
osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
if (cv)
{
//const osg::Timer& timer = *osg::Timer::instance();
//osg::Timer_t start = timer.tick();
//std::cout<<"Doing visible tile search"<<std::endl;
osg::ref_ptr<TileMapper> tileMapper = new TileMapper;
tileMapper->pushViewport(cv->getViewport());
tileMapper->pushProjectionMatrix(&(cv->getProjectionMatrix()));
tileMapper->pushModelViewMatrix(&(cv->getModelViewMatrix()));
// traverse the scene graph to search for valid tiles
accept(*tileMapper);
tileMapper->popModelViewMatrix();
tileMapper->popProjectionMatrix();
tileMapper->popViewport();
//std::cout<<" found " << tileMapper._tileMap.size() << std::endl;
tileMapper->checkValidityOfAllVisibleTiles();
cv->setUserData(tileMapper.get());
//std::cout<<"Completed visible tile search in "<<timer.delta_m(start,timer.tick())<<std::endl;
}
updateEye(nv);
break;
}
case osg::NodeVisitor::UPDATE_VISITOR:
updateSceneGraph();
break;
@@ -188,30 +225,17 @@ osg::Node* TXPNode::addPagedLODTile(int x, int y, int lod)
TXPArchive::TileInfo info;
_archive->getTileInfo(x,y,lod,info);
TXPPagedLOD* pagedLOD = new TXPPagedLOD;
osg::PagedLOD* pagedLOD = new osg::PagedLOD;
pagedLOD->setFileName(0,pagedLODfile);
//pagedLOD->setPriorityOffset(0,1.0f);
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->setTileId(x,y,lod);
int sizeX, sizeY;
if (_archive->getLODSize(lod,sizeX,sizeY))
{
if ((x-1) > -1) pagedLOD->addNeighbour(x-1,y);
if ((x+1) < sizeX) pagedLOD->addNeighbour(x+1,y);
if ((y-1) > -1) pagedLOD->addNeighbour(x,y-1);
if ((y+1) < sizeY) pagedLOD->addNeighbour(x,y+1);
}
_nodesToAdd.push_back(pagedLOD);
TileMapper::instance()->insertPagedLOD(x,y,lod,pagedLOD);
return pagedLOD;
}
@@ -234,10 +258,7 @@ void TXPNode::updateSceneGraph()
}
_nodesToAdd.clear();
}
TileMapper::instance()->prunePagedLOD();
}
}

View File

@@ -3,78 +3,55 @@
using namespace txp;
TXPPagedLOD::TXPPagedLOD():
PagedLOD(),
_tileX(-1),
_tileY(-1),
_tileLOD(-1),
_lastChildTraversed(-1)
PagedLOD()
{
}
TXPPagedLOD::TXPPagedLOD(const TXPPagedLOD& plod,const osg::CopyOp& copyop):
PagedLOD(plod,copyop),
_tileX(plod._tileX),
_tileY(plod._tileY),
_tileLOD(plod._tileLOD),
_lastChildTraversed(plod._lastChildTraversed)
PagedLOD(plod,copyop),
_tileIdentifier(plod._tileIdentifier)
{
}
TXPPagedLOD::~TXPPagedLOD()
{
TileMapper::instance()->removePagedLOD(_tileX,_tileY,_tileLOD);
}
void TXPPagedLOD::traverse(osg::NodeVisitor& nv)
{
// PagedLOD::traverse(nv);
//
// return;
TileMapper* tileMapper = dynamic_cast<TileMapper*>(nv.getUserData());
bool forceUseOfFirstChild = tileMapper ? (tileMapper->isNodeBlackListed(this)) : false;
double timeStamp = nv.getFrameStamp()?nv.getFrameStamp()->getReferenceTime():0.0;
bool updateTimeStamp = nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR;
switch(nv.getTraversalMode())
{
case(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN):
case(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN):
std::for_each(_children.begin(),_children.end(),osg::NodeAcceptOp(nv));
break;
case(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN):
case(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN):
{
float distance = nv.getDistanceToEyePoint(getCenter(),true);
_lastChildTraversed = -1;
int lastChildTraversed = -1;
bool needToLoadChild = false;
bool rollBack = false;
for(unsigned int i=0;i<_rangeList.size();++i)
unsigned maxRangeSize = _rangeList.size();
if (maxRangeSize!=0 && forceUseOfFirstChild) maxRangeSize=1;
for(unsigned int i=0;i<maxRangeSize;++i)
{
if (_rangeList[i].first<=distance && distance<_rangeList[i].second)
if (forceUseOfFirstChild || _rangeList[i].first<=distance && distance<_rangeList[i].second)
{
if (i<_children.size())
{
bool acceptThisChild = true;
if (updateTimeStamp) _perRangeDataList[i]._timeStamp=timeStamp;
if (i)
{
for (unsigned int ni = 0; ni < _neighbours.size(); ni++)
{
Neighbour& n = _neighbours[ni];
if (TileMapper::instance()->getPagedLOD(n._x, n._y, _tileLOD)== 0)
{
rollBack = true;
acceptThisChild = false;
break;
}
}
}
if (acceptThisChild)
{
if (updateTimeStamp) _perRangeDataList[i]._timeStamp=timeStamp;
_children[i]->accept(nv);
_lastChildTraversed = (int)i;
}
//std::cout<<"PagedLOD::traverse() - Selecting child "<<i<<std::endl;
_children[i]->accept(nv);
lastChildTraversed = (int)i;
}
else
{
@@ -82,14 +59,6 @@ void TXPPagedLOD::traverse(osg::NodeVisitor& nv)
}
}
}
if (rollBack)
{
if (updateTimeStamp) _perRangeDataList[0]._timeStamp=timeStamp;
_children[0]->accept(nv);
_lastChildTraversed = 0;
//std::cout << "Rolling back" << std::endl;
}
if (needToLoadChild)
{
@@ -97,12 +66,11 @@ void TXPPagedLOD::traverse(osg::NodeVisitor& nv)
//std::cout<<"PagedLOD::traverse() - falling back "<<std::endl;
// select the last valid child.
if (numChildren>0 && ((int)numChildren-1)!=_lastChildTraversed)
if (numChildren>0 && ((int)numChildren-1)!=lastChildTraversed)
{
//std::cout<<" to child "<<numChildren-1<<std::endl;
if (updateTimeStamp) _perRangeDataList[numChildren-1]._timeStamp=timeStamp;
_children[numChildren-1]->accept(nv);
_lastChildTraversed = numChildren-1;
}
// now request the loading of the next unload child.
@@ -128,3 +96,4 @@ void TXPPagedLOD::traverse(osg::NodeVisitor& nv)
break;
}
}

View File

@@ -35,6 +35,7 @@
#define __TXPPAGEDLOD_H_
#include <osg/PagedLOD>
#include "TileMapper.h"
namespace txp
{
@@ -52,33 +53,15 @@ namespace txp
inline void setTileId(int x, int y, int lod)
{
_tileX = x; _tileY = y; _tileLOD = lod;
_tileIdentifier.set(x,y,lod);
}
inline void addNeighbour(int x,int y)
{
Neighbour n;
n._x = x;
n._y = y;
_neighbours.push_back(n);
}
TileIdentifier _tileIdentifier;
int _tileX;
int _tileY;
int _tileLOD;
inline const int getLastTraversedChild() const { return _lastChildTraversed; }
protected:
virtual ~TXPPagedLOD();
int _lastChildTraversed;
struct Neighbour
{
int _x, _y;
};
std::vector<Neighbour> _neighbours;
};
} // namespace

View File

@@ -412,7 +412,7 @@ void TXPParser::loadLocalMaterials()
osg_material->setShininess(osg::Material::FRONT_AND_BACK , (float)shinines);
osg_material->setAlpha(osg::Material::FRONT_AND_BACK ,(float)alpha);
osg_state_set->setAttributeAndModes(osg_material, osg::StateAttribute::ON);
//osg_state_set->setAttributeAndModes(osg_material, osg::StateAttribute::ON);
if( alpha < 1.0f )
{

View File

@@ -1,6 +1,5 @@
#include "TXPSeamLOD.h"
#include "TXPArchive.h"
#include "TXPTileNode.h"
#include "TXPPagedLOD.h"
#include "TileMapper.h"
@@ -9,90 +8,43 @@ using namespace txp;
TXPSeamLOD::TXPSeamLOD() :
Group()
{
_neighbourTileX =
_neighbourTileY =
_neighbourTileLOD = -1;
_tileRef = 0;
_txpNode = 0;
_archive = 0;
_hiResPresent = false;
_nonSeamChildrenIndex = -1;
_dx = 0;
_dy = 0;
}
TXPSeamLOD::TXPSeamLOD(int x, int y, int lod, const osg::Vec3& center, float dmin, float dmid, float dmax) :
TXPSeamLOD::TXPSeamLOD(int x, int y, int lod, int dx, int dy) :
Group()
{
_neighbourTileX = x;
_neighbourTileY = y;
_neighbourTileLOD = lod;
_center = center;
_min = dmin;
_mid = dmid;
_max = dmax;
_txpNode = 0;
_tileRef = 0;
_archive = 0;
_hiResPresent = false;
_nonSeamChildrenIndex = -1;
_tid.x = x;
_tid.y = y;
_tid.lod = lod;
_dx = dx;
_dy = dy;
}
TXPSeamLOD::TXPSeamLOD(const TXPSeamLOD& ttg,const osg::CopyOp& copyop) :
Group(ttg,copyop)
{
_neighbourTileX = ttg._neighbourTileX;
_neighbourTileY = ttg._neighbourTileY;
_neighbourTileLOD = ttg._neighbourTileLOD;
_tileRef = ttg._tileRef;
_archive = ttg._archive;
_hiResPresent = ttg._hiResPresent;
_nonSeamChildrenIndex = ttg._nonSeamChildrenIndex;
_tid = ttg._tid;
_dx = ttg._dx;
_dy = ttg._dy;
}
void TXPSeamLOD::traverse(osg::NodeVisitor& nv)
{
if (nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR && _children.size()==2)
if (nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR && getNumChildren()==2)
{
//osg::PagedLOD* pagedLOD = TileMapper::instance()->getPagedLOD(_neighbourTileX,_neighbourTileY, _neighbourTileLOD);
TXPPagedLOD* pagedLOD = dynamic_cast<TXPPagedLOD*>(TileMapper::instance()->getPagedLOD(_neighbourTileX,_neighbourTileY, _neighbourTileLOD));
#if 1
if (pagedLOD && pagedLOD->getLastTraversedChild()>0)
TileMapper* tileMapper = dynamic_cast<TileMapper*>(nv.getUserData());
if (tileMapper && !tileMapper->isTileNeighbourALowerLODLevel(_tid,_dx,_dy))
{
getChild(1)->accept(nv);
}
else
{
getChild(0)->accept(nv);
#else
bool acceptLoRes = true;
if (pagedLOD)
{
float distance = nv.getDistanceToEyePoint(_center,true);
distance = nv.getDistanceToEyePoint(pagedLOD->getCenter(),true);
//std::cout<<"distance to eye from center = "<<distance<<" min = "<< _min<<" mid = "<< _mid << " max = "<<_max<<std::endl;
//std::cout<<" TXPSeam::_center "<<_center<<" PageLOD::_center "<<pagedLOD->getCenter()<<std::endl;
int numChildren = osg::minimum(getNumChildren(),pagedLOD->getNumChildren());
for(int i=numChildren-1;i>=0;--i)
{
//std::cout<<" child "<<i<<" range = min "<<pagedLOD->getMinRange(i)<<" max = "<<pagedLOD->getMaxRange(i)<<std::endl;
if (distance<=pagedLOD->getMaxRange(i))
{
getChild(i)->accept(nv);
acceptLoRes = false;
break;
}
}
}
if (acceptLoRes)
{
getChild(0)->accept(nv); // pick low res
}
if (_nonSeamChildrenIndex > -1)
{
for (int i = _nonSeamChildrenIndex; i < (int)getNumChildren(); i++ )
getChild(i)->accept(nv);
}
#endif
}
else
{

View File

@@ -39,8 +39,7 @@
#include <map>
#include <string>
#include "TXPTileNode.h"
#include "TXPArchive.h"
#include "TileMapper.h"
namespace txp
{
@@ -50,8 +49,7 @@ public:
TXPSeamLOD();
TXPSeamLOD(int x, int y, int lod, const osg::Vec3& center, float dmin,
float dmid, float dmax);
TXPSeamLOD(int x, int y, int lod, int dx, int dy);
TXPSeamLOD(const TXPSeamLOD&,
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
@@ -60,49 +58,12 @@ public:
virtual void traverse(osg::NodeVisitor& nv);
void setTileRef(bool* b)
{
_tileRef = b;
}
void setTxpNode(TXPTileNode* txpNode)
{
_txpNode = txpNode;
}
TXPTileNode* getTxpNode() const
{
return _txpNode;
}
void setArchive(TXPArchive* ar)
{
_archive = ar;
}
inline void setHiResPresent(bool p) { _hiResPresent = p; }
inline void setNonSeamChildrenIndex(int ix) { _nonSeamChildrenIndex = ix; }
protected:
bool _hiResPresent;
TileIdentifier _tid;
int _nonSeamChildrenIndex;
int _neighbourTileX;
int _neighbourTileY;
int _neighbourTileLOD;
osg::Vec3 _center;
float _min;
float _mid;
float _max;
bool* _tileRef;
TXPTileNode* _txpNode;
TXPArchive* _archive;
int _dx;
int _dy;
};
}

View File

@@ -1,309 +0,0 @@
#include <osg/PagedLOD>
#include "TileMapper.h"
#include "TXPTileNode.h"
#include "TXPArchive.h"
#include "TXPSeamLOD.h"
#include "TXPPagedLOD.h"
using namespace txp;
class PrintVisitor : public osg::NodeVisitor
{
public:
PrintVisitor():NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN)
{
_indent = 0;
_step = 4;
}
inline void moveIn() { _indent += _step; }
inline void moveOut() { _indent -= _step; }
inline void writeIndent()
{
for(int i=0;i<_indent;++i) std::cout << " ";
}
virtual void apply(osg::Node& node)
{
moveIn();
writeIndent(); std::cout << node.className() <<std::endl;
traverse(node);
moveOut();
}
virtual void apply(osg::Geode& node) { apply((osg::Node&)node); }
virtual void apply(osg::Billboard& node) { apply((osg::Geode&)node); }
virtual void apply(osg::LightSource& node) { apply((osg::Group&)node); }
virtual void apply(osg::ClipNode& node) { apply((osg::Group&)node); }
virtual void apply(osg::Group& node) { apply((osg::Node&)node); }
virtual void apply(osg::Transform& node) { apply((osg::Group&)node); }
virtual void apply(osg::Projection& node) { apply((osg::Group&)node); }
virtual void apply(osg::Switch& node) { apply((osg::Group&)node); }
virtual void apply(osg::LOD& lod)
{
moveIn();
writeIndent(); std::cout << lod.className() <<std::endl;
if (lod.className()=="TXPPagedLOD")
{
TXPPagedLOD *plod = (TXPPagedLOD*)&lod;
writeIndent(); std::cout << "X="<<plod->_tileX<<" Y="<<plod->_tileY<<" LOD="<<plod->_tileLOD<< std::endl;
}
//writeIndent(); std::cout << "center="<<lod.getCenter()<<std::endl;
for(unsigned int i=0;i<lod.getNumChildren();++i)
{
//writeIndent(); std::cout << "child min="<<lod.getMinRange(i)<<" max="<<lod.getMaxRange(i)<<std::endl;
lod.getChild(i)->accept(*this);
}
moveOut();
}
virtual void apply(osg::Impostor& node) { apply((osg::LOD&)node); }
protected:
int _indent;
int _step;
};
TXPTileNode::TXPTileNode():
osg::Group(),
_archive(0)
{
}
TXPTileNode::TXPTileNode(const TXPTileNode& tn,const osg::CopyOp& copyop):
osg::Group(tn,copyop),
_archive(tn._archive)
{
}
TXPTileNode::~TXPTileNode()
{
}
void TXPTileNode::setArchive(TXPArchive* archive)
{
_archive = archive;
}
class SeamFinder: public osg::NodeVisitor
{
public:
SeamFinder(int x, int y, int lod, TXPArchive::TileInfo& info, TXPArchive *archive ):
NodeVisitor(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);
int _x, _y, _lod;
TXPArchive::TileInfo& _info;
TXPArchive *_archive;
};
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;
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;
// seam center is outside the bounding box of the tile
if (!_info.bbox.contains(lod->getCenter()))
{
// seams have center as the neighbour tile
osg::Vec3 d = _info.center - lod->getCenter();
if (((fabs(d.x())-_info.size.x()) > 0.0001) && ((fabs(d.y())-_info.size.y()) > 0.0001))
{
nonSeamChildren.push_back(lod);
continue;
}
// low res seam has min/max ranges of lod+1 range/lod 0 range
if ((fabs(_info.minRange-lod->getMinRange(0))<0.001)&&(fabs(_info.lod0Range-lod->getMaxRange(0))<0.001))
{
if (loRes==0)
{
loRes = lod;
nonSeamChild = false;
}
}
// hi res seam has min/max ranges of 0 range/lod+1 range
if ((lod->getMinRange(0)==0.0f)&&(fabs(_info.minRange-lod->getMaxRange(0))<0.001))
{
if (hiRes==0)
{
hiRes = lod;
nonSeamChild = false;
}
}
}
if (nonSeamChild)
{
nonSeamChildren.push_back(lod);
}
}
if (loRes)
{
int x = _x;
int y = _y;
int lod = _lod;
osg::Vec3 delta = loRes->getCenter()-_info.center;
if (fabs(delta.x())>fabs(delta.y()))
{
if (delta.x()<0.0) --x; // west
else x++; // east
}
else
{
if (delta.y()<0.0) --y; // south
else ++y; // north
}
TXPSeamLOD* seam = new TXPSeamLOD(
x,
y,
lod,
loRes->getCenter(),
0.f,
_info.minRange,
_info.maxRange
);
seam->setArchive(_archive);
seam->addChild(loRes->getChild(0)); // low res
if (hiRes)
{
seam->addChild(hiRes->getChild(0)); // high res
seam->setHiResPresent(true);
}
if (nonSeamChildren.size())
{
seam->setNonSeamChildrenIndex(seam->getNumChildren());
for (unsigned int i = 0; i < nonSeamChildren.size(); i++)
seam->addChild(nonSeamChildren[i]);
}
return seam;
}
return node;
}
bool TXPTileNode::loadTile(int x, int y, int lod)
{
if (_archive == 0) return false;
TXPArchive::TileInfo info;
bool validTile = _archive->getTileInfo(x,y,lod,info);
int numLods = _archive->getNumLODs();
if (validTile)
{
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);
// if group has only one child, then simply use its child.
#if 1
while (tileGroup->getNumChildren()==1 && tileGroup->getChild(0)->asGroup())
{
tileGroup = tileGroup->getChild(0)->asGroup();
}
#endif
// Handle seams
if (lod < (numLods-1))
{
SeamFinder sfv(x,y,lod,info,_archive);
tileGroup->accept(sfv);
}
if (lod < (numLods-1))
{
char pagedLODfile[1024];
sprintf(pagedLODfile,"%s\\subtiles%d_%dx%d_%d.txp",
_archive->getDir(),
lod,
x,
y,
_archive->getId()
);
osg::ref_ptr<TXPPagedLOD> pagedLOD = new TXPPagedLOD;
// not use maximum(info.maxRange,1e7) as just maxRange would result in some corner tiles from being culled out.
pagedLOD->addChild(tileGroup,info.minRange,osg::maximum(info.maxRange,1e7));
pagedLOD->setFileName(1,pagedLODfile);
pagedLOD->setRange(1,0,info.minRange);
pagedLOD->setCenter(info.center);
//pagedLOD->setCenter(tileCenter);
pagedLOD->setRadius(info.radius);
pagedLOD->setPriorityOffset(0,numLods-lod);
pagedLOD->setPriorityScale(0,1.0f);
pagedLOD->setNumChildrenThatCannotBeExpired(1);
pagedLOD->setTileId(x,y,lod);
int sizeX, sizeY;
if (_archive->getLODSize(lod,sizeX,sizeY))
{
if ((x-1) > -1) pagedLOD->addNeighbour(x-1,y);
if ((x+1) < sizeX) pagedLOD->addNeighbour(x+1,y);
if ((y-1) > -1) pagedLOD->addNeighbour(x,y-1);
if ((y+1) < sizeY) pagedLOD->addNeighbour(x,y+1);
}
TileMapper::instance()->insertPagedLOD(x,y,lod,pagedLOD.get());
addChild(pagedLOD.get());
//PrintVisitor pv;
//accept(pv);
}
else
{
addChild(tileGroup);
}
return true;
}
return false;
}

View File

@@ -1,65 +0,0 @@
/***************************************************************************
* December 2003
*
* This TerraPage loader was re-written in a fashion to use PagedLOD
* to manage paging entirely, also includes a version of Terrex's smart mesh
* adapted to work with PagedLOD. The essential code by Boris Bralo is still present,
* slight modified.
* nick at terrex dot com
*
* Ported to PagedLOD technology by Trajce Nikolov (Nick) & Robert Osfield
*****************************************************************************/
/***************************************************************************
* OpenSceneGraph loader for Terrapage format database
* by Boris Bralo 2002
*
* based on/modifed sgl (Scene Graph Library) loader by Bryan Walsh
*
* This loader is based on/modified from Terrain Experts Performer Loader,
* and was ported to SGL by Bryan Walsh / bryanw at earthlink dot net
*
* That loader is redistributed under the terms listed on Terrain Experts
* website (www.terrex.com/www/pages/technology/technologypage.htm)
*
* "TerraPage is provided as an Open Source format for use by anyone...
* We supply the TerraPage C++ source code free of charge. Anyone
* can use it and redistribute it as needed (including our competitors).
* We do, however, ask that you keep the TERREX copyrights intact."
*
* Copyright Terrain Experts Inc. 1999.
* All Rights Reserved.
*
*****************************************************************************/
#ifndef __TXPTILENODE_H_
#define __TXPTILENODE_H_
#include <osg/Group>
#include "TXPArchive.h"
namespace txp
{
class TXPArchive;
class TXPTileNode : public osg::Group
{
public:
TXPTileNode();
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
TXPTileNode(const TXPTileNode&,
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
META_Node(txp, TXPTileNode);
void setArchive(TXPArchive* archive);
bool loadTile(int x, int y, int lod);
protected:
virtual ~TXPTileNode();
TXPArchive* _archive;
};
} // namespace
#endif // __TXPTILENODE_H_

View File

@@ -1,48 +1,437 @@
/* -*-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.
*/
#include "TileMapper.h"
#include <OpenThreads/ScopedLock>
//#include "TXPTileNode.h"
#include "TXPPagedLOD.h"
#include <osg/Material>
using namespace txp;
TileMapper* TileMapper::instance()
float TileMapper::getDistanceToEyePoint(const osg::Vec3& pos, bool withLODScale) const
{
static osg::ref_ptr<TileMapper> s_tilemapper = new TileMapper;
return s_tilemapper.get();
if (withLODScale) return (pos-getEyeLocal()).length()*getLODScale();
else return (pos-getEyeLocal()).length();
}
osg::PagedLOD* TileMapper::getPagedLOD(int x, int y, int lod)
inline TileMapper::value_type distance(const osg::Vec3& coord,const osg::Matrix& matrix)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
TileMap::iterator itr = _tileMap.find(TileTriple(x,y,lod));
if (itr!=_tileMap.end()) return itr->second;
else return 0;
//std::cout << "distance("<<coord<<", "<<matrix<<")"<<std::endl;
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));
}
void TileMapper::insertPagedLOD(int x, int y, int lod, osg::PagedLOD* pagedLod)
float TileMapper::getDistanceFromEyePoint(const osg::Vec3& pos, bool withLODScale) const
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
_tileMap[TileTriple(x,y,lod)]=pagedLod;
const osg::Matrix& matrix = *_modelviewStack.back();
float dist = distance(pos,matrix);
if (withLODScale) return dist*getLODScale();
else return dist;
}
void TileMapper::removePagedLOD(int x, int y, int lod)
void TileMapper::apply(osg::Node& node)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
TileMap::iterator itr = _tileMap.find(TileTriple(x,y,lod));
if (itr!=_tileMap.end()) _tileMap.erase(itr);
if (isCulled(node)) return;
// push the culling mode.
pushCurrentMask();
traverse(node);
// pop the culling mode.
popCurrentMask();
}
void TileMapper::prunePagedLOD()
void TileMapper::apply(osg::Group& node)
{
// OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
// for(TileMap::iterator itr = _tileMap.begin();
// itr!=_tileMap.end();
// ++itr)
// {
// if (itr->second.valid() && itr->second->referenceCount()==1)
// {
// TileMap::iterator eitr = itr;
// --itr;
// _tileMap.erase(eitr);
// }
// }
//std::cout<<"_tileMap.size()="<<_tileMap.size()<<std::endl;
if (isCulled(node)) return;
// push the culling mode.
pushCurrentMask();
TileIdentifier* tid = dynamic_cast<TileIdentifier*>(node.getUserData());
if (tid)
{
_tileStack.push_back(TileStack::value_type(*tid,&node));
_containsGeode = false;
}
traverse(node);
if (tid)
{
if (_containsGeode)
{
insertTile(*tid);
_containsGeode = false;
#if 0
std::cout<<"found Group="<<tid->lod
<<" X="<<tid->x
<<" Y="<<tid->y
<<" ptr="<<&node<<std::endl;
std::cout<<" inheritance list "<<_tileStack.size()<<std::endl;
for(TileStack::iterator itr=_tileStack.begin();
itr!=_tileStack.end();
++itr)
{
std::cout<<" LOD="<<itr->first.lod
<<" X="<<itr->first.x
<<" Y="<<itr->first.y
<<" className="<<itr->second->className()
<<" ptr="<<itr->second<<std::endl;
}
osg::StateSet* stateset = node.getOrCreateStateSet();
osg::Material* material = new osg::Material;
material->setColorMode(osg::Material::OFF);
stateset->setAttribute(material);
switch(tid->lod)
{
case(0): material->setEmission(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f)); break;
case(1): material->setEmission(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,0.0f,0.0f,1.0f)); break;
case(2): material->setEmission(osg::Material::FRONT_AND_BACK,osg::Vec4(0.0f,1.0f,0.0f,1.0f)); break;
case(3): material->setEmission(osg::Material::FRONT_AND_BACK,osg::Vec4(0.0f,0.0f,1.0f,1.0f)); break;
case(4): material->setEmission(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,0.0f,1.0f,1.0f)); break;
}
#endif
}
_tileStack.pop_back();
}
// 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)
{
_tileStack.push_back(TileStack::value_type(txpPagedLOD->_tileIdentifier,&node));
_containsGeode = false;
}
traverse(node);
if (txpPagedLOD)
{
if (_containsGeode)
{
insertTile(txpPagedLOD->_tileIdentifier);
_containsGeode = false;
#if 0
std::cout<<"found txpPagedLOD LOD="<<txpPagedLOD->_tileIdentifier.lod
<<" X="<<txpPagedLOD->_tileIdentifier.x
<<" Y="<<txpPagedLOD->_tileIdentifier.y
<<" ptr="<<txpPagedLOD<<std::endl;
std::cout<<" inheritance list "<<_tileStack.size()<<std::endl;
for(TileStack::iterator itr=_tileStack.begin();
itr!=_tileStack.end();
++itr)
{
std::cout<<" LOD="<<itr->first.lod
<<" X="<<itr->first.x
<<" Y="<<itr->first.y
<<" className="<<itr->second->className()
<<" ptr="<<itr->second<<std::endl;
}
osg::StateSet* stateset = txpPagedLOD->getOrCreateStateSet();
osg::Material* material = new osg::Material;
material->setColorMode(osg::Material::OFF);
stateset->setAttribute(material);
switch(txpPagedLOD->_tileIdentifier.lod)
{
case(0): material->setEmission(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,1.0f,1.0f,1.0f)); break;
case(1): material->setEmission(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,0.0f,0.0f,1.0f)); break;
case(2): material->setEmission(osg::Material::FRONT_AND_BACK,osg::Vec4(0.0f,1.0f,0.0f,1.0f)); break;
case(3): material->setEmission(osg::Material::FRONT_AND_BACK,osg::Vec4(0.0f,0.0f,1.0f,1.0f)); break;
case(4): material->setEmission(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0f,0.0f,1.0f,1.0f)); break;
}
#endif
}
_tileStack.pop_back();
}
// pop the culling mode.
popCurrentMask();
}
void TileMapper::insertTile(const TileIdentifier& tid)
{
_tileMap.insert(TileMap::value_type(tid,_tileStack));
}
bool TileMapper::canParentBeTraversed(const TileIdentifier& tid) const
{
// 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.
std::cout<<"TileMapper::canDescend() Not found tile in map"<<std::endl;
return true;
}
const TileStack& ts = itr->second;
// note tile here, is tid's parent.
const TileStack::value_type* tile = (ts.size()>=2) ? &ts[ts.size()-2] : 0;
// note parent here, is tid's parents parent.
const TileStack::value_type* parent = (ts.size()>=3) ? &ts[ts.size()-3] : 0;
if (!tile)
{
// no self!!! so we can descend safely?!! shouldn't ever get here.
//std::cout<<"TileMapper::canDescend() tile==0"<<std::endl;
return true;
}
if (!parent)
{
// no parent so we can descend safely.
return true;
}
bool tileHasNorthNeighour = _tileMap.count(TileIdentifier(tid.x,tid.y+1,tid.lod))!=0;
bool tileHasEastNeighour = _tileMap.count(TileIdentifier(tid.x+1,tid.y,tid.lod))!=0;
bool tileHasSouthNeighour = _tileMap.count(TileIdentifier(tid.x,tid.y-1,tid.lod))!=0;
bool tileHasWestNeighour = _tileMap.count(TileIdentifier(tid.x-1,tid.y,tid.lod))!=0;
if (tileHasNorthNeighour && tileHasEastNeighour && tileHasSouthNeighour && tileHasWestNeighour)
{
// tile has neigbours on all sides at the same lod level, so its safe to descend.
//std::cout<<"TileMapper::canDescend() has neightbours on all sides"<<std::endl;
return true;
}
const TileIdentifier& parent_tid = parent->first;
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 = tile->second->getBound().center() - parent->second->getBound().center();
if (delta.y()>=0.0f) // noth side
{
if (delta.x()>=0.0f)
{
// NE, only traverse if our parent doesn't have any neighbours to the north or east.
return (!parentHasNorthNeighour && !parentHasEastNeighour);
}
else
{
// NW, only traverse if our parent doesn't have any neighbours to the north or west.
return (!parentHasNorthNeighour && !parentHasWestNeighour);
}
}
else // south side
{
if (delta.x()>=0.0f)
{
// SE, only traverse if our parent doesn't have any neighbours to the south or east.
return (!parentHasSouthNeighour && !parentHasEastNeighour);
}
else
{
// SW, only traverse if our parent doesn't have any neighbours to the south or west.
return (!parentHasSouthNeighour && !parentHasWestNeighour);
}
}
// we shouldn't get here...
return true;
}
void TileMapper::checkValidityOfAllVisibleTiles()
{
typedef std::vector<TileIdentifier> ToRemoveList;
typedef std::vector<TileStack> ToAddList;
ToRemoveList toRemoveList;
ToAddList toAddList;
do
{
// std::cout<<"doing checkAllVisibleTiles() loop with "<<_tileMap.size()<<std::endl;
toRemoveList.clear();
toAddList.clear();
for(TileMap::iterator itr=_tileMap.begin();
itr!=_tileMap.end();
++itr)
{
if (!canParentBeTraversed(itr->first))
{
// need to remove.
toRemoveList.push_back(itr->first);
// trim the end of itr's TileStack and add into toAddList
toAddList.push_back(itr->second);
// std::cout<<"Tile failed"
// <<" LOD="<<itr->first.lod
// <<" X="<<itr->first.x
// <<" Y="<<itr->first.y<<std::endl;
}
}
for(ToRemoveList::iterator ritr=toRemoveList.begin();
ritr!=toRemoveList.end();
++ritr)
{
//std::cout<<"Removing Tile"<<std::endl;
_tileMap.erase(*ritr);
}
for(ToAddList::iterator aitr=toAddList.begin();
aitr!=toAddList.end();
++aitr)
{
//std::cout<<"Adding Parents Tile back in"<<std::endl;
aitr->pop_back();
_blackListedNodeSet.insert(aitr->back().second);
_tileMap.insert(TileMap::value_type(aitr->back().first,*aitr));
}
} while (!toRemoveList.empty());
if (!_blackListedNodeSet.empty()) std::cout<<"********** We have blacked list "<<_blackListedNodeSet.size()<<std::endl;
}
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.
std::cout<<"TileMapper::isTileNeighbourALowerLODLevel() Not found tile in map"<<std::endl;
return false;
}
const TileStack& ts = itr->second;
// note tile here, is tid's parent.
const TileStack::value_type* tile = (ts.size()>=1) ? &ts[ts.size()-1] : 0;
if (!tile)
{
// no tile, so must assume taht neight is now at a lower level
return false;
}
// note parent here, is tid's parents parent.
const TileStack::value_type* parent = (ts.size()>=2) ? &ts[ts.size()-2] : 0;
if (!parent)
{
// no parent so we must assume that is not at a lower level
return false;
}
const TileIdentifier& parent_tid = parent->first;
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 = tile->second->getBound().center() - parent->second->getBound().center();
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;
}

View File

@@ -1,73 +1,137 @@
/* -*-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.
*/
#ifndef __TILEMAPPER_H_
#define __TILEMAPPER_H_
#include "trpage_sys.h"
#include "trpage_read.h"
#include <osg/Referenced>
#include <osg/PagedLOD>
#include <osg/CullStack>
#include <osg/NodeVisitor>
#include <OpenThreads/Mutex>
#include <set>
namespace txp
{
class TileMapper : public osg::Referenced
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;
static TileMapper* instance();
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);
osg::PagedLOD* getPagedLOD(int x, int y, int lod);
void insertTile(const TileIdentifier& tid);
void insertPagedLOD(int x, int y, int lod, osg::PagedLOD* pagedLod);
bool canParentBeTraversed(const TileIdentifier& tid) const;
void removePagedLOD(int x, int y, int lod);
void checkValidityOfAllVisibleTiles();
void prunePagedLOD();
bool containsBlackListedNodes() const
{
return !_blackListedNodeSet.empty();
}
inline bool isNodeBlackListed(const osg::Node* node) const
{
return _blackListedNodeSet.count(node)!=0;
}
bool isTileNeighbourALowerLODLevel(const TileIdentifier& tid, int dx, int dy) const;
protected:
// Constructor
TileMapper()
{}
typedef std::vector< std::pair<TileIdentifier,osg::Node*> > TileStack;
typedef std::map< TileIdentifier, TileStack > TileMap;
typedef std::set< const osg::Node* > BlacklistedNodeSet;
// Destructor
virtual ~TileMapper()
{}
struct TileTriple
{
TileTriple(int ax, int ay, int alod):
x(ax),y(ay),lod(alod)
{}
int x,y,lod;
bool operator < (const TileTriple& rhs) const
{
if (x<rhs.x)
return true;
if (x>rhs.x)
return false;
if (y<rhs.y)
return true;
if (y>rhs.y)
return false;
if (lod<rhs.lod)
return true;
if (lod>rhs.lod)
return false;
return false;
}
};
typedef std::map< TileTriple, osg::PagedLOD* > TileMap;
OpenThreads::Mutex _mutex;
TileStack _tileStack;
TileMap _tileMap;
bool _containsGeode;
BlacklistedNodeSet _blackListedNodeSet;
};
} // namespace
#endif // __TXPARCHIVE_H_
#endif // __TILEMAPPER_H_