From 9d1ace20d9a39a5bd8e3364cd51eb4b8bb5a3077 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 21 Jan 2004 17:26:23 +0000 Subject: [PATCH] Added new mechanism for handling Seams. --- VisualStudio/osgPlugins/txp/txp.dsp | 8 - src/osgPlugins/txp/GNUmakefile | 1 - src/osgPlugins/txp/ReaderWriterTXP.cpp | 248 +++++++++++++- src/osgPlugins/txp/ReaderWriterTXP.h | 5 +- src/osgPlugins/txp/TXPArchive.cpp | 2 +- src/osgPlugins/txp/TXPNode.cpp | 57 +++- src/osgPlugins/txp/TXPPagedLOD.cpp | 71 ++-- src/osgPlugins/txp/TXPPagedLOD.h | 23 +- src/osgPlugins/txp/TXPParser.cpp | 2 +- src/osgPlugins/txp/TXPSeamLOD.cpp | 86 ++--- src/osgPlugins/txp/TXPSeamLOD.h | 49 +-- src/osgPlugins/txp/TXPTileNode.cpp | 309 ----------------- src/osgPlugins/txp/TXPTileNode.h | 65 ---- src/osgPlugins/txp/TileMapper.cpp | 449 +++++++++++++++++++++++-- src/osgPlugins/txp/TileMapper.h | 156 ++++++--- 15 files changed, 855 insertions(+), 676 deletions(-) delete mode 100644 src/osgPlugins/txp/TXPTileNode.cpp delete mode 100644 src/osgPlugins/txp/TXPTileNode.h diff --git a/VisualStudio/osgPlugins/txp/txp.dsp b/VisualStudio/osgPlugins/txp/txp.dsp index f04133a0a..f09156335 100644 --- a/VisualStudio/osgPlugins/txp/txp.dsp +++ b/VisualStudio/osgPlugins/txp/txp.dsp @@ -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 diff --git a/src/osgPlugins/txp/GNUmakefile b/src/osgPlugins/txp/GNUmakefile index 98db0cdcf..6a1fe047a 100644 --- a/src/osgPlugins/txp/GNUmakefile +++ b/src/osgPlugins/txp/GNUmakefile @@ -7,7 +7,6 @@ CXXFILES =\ TXPIO.cpp\ TXPNode.cpp\ TXPPageManager.cpp\ - TXPTileNode.cpp\ TXPParser.cpp\ TXPSeamLOD.cpp\ TXPPagedLOD.cpp\ diff --git a/src/osgPlugins/txp/ReaderWriterTXP.cpp b/src/osgPlugins/txp/ReaderWriterTXP.cpp index 5653ea8fd..554fbb122 100644 --- a/src/osgPlugins/txp/ReaderWriterTXP.cpp +++ b/src/osgPlugins/txp/ReaderWriterTXP.cpp @@ -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 = 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 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 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 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 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 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 nonSeamChildren; + osg::LOD* hiRes = 0; + osg::LOD* loRes = 0; + + for (unsigned int i = 0; i < group->getNumChildren(); i++) + { + osg::LOD* lod = dynamic_cast(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"<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 g_txpReaderWriterProxy; diff --git a/src/osgPlugins/txp/ReaderWriterTXP.h b/src/osgPlugins/txp/ReaderWriterTXP.h index a51e261a2..3c217d572 100644 --- a/src/osgPlugins/txp/ReaderWriterTXP.h +++ b/src/osgPlugins/txp/ReaderWriterTXP.h @@ -43,9 +43,10 @@ #include #include +#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 > _archives; + + osg::Node* getTileContent(TXPArchive::TileInfo &info, int x, int y, int lod, TXPArchive* archive); static int _archiveId; }; diff --git a/src/osgPlugins/txp/TXPArchive.cpp b/src/osgPlugins/txp/TXPArchive.cpp index de4a4816d..190458ef0 100644 --- a/src/osgPlugins/txp/TXPArchive.cpp +++ b/src/osgPlugins/txp/TXPArchive.cpp @@ -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 ) { diff --git a/src/osgPlugins/txp/TXPNode.cpp b/src/osgPlugins/txp/TXPNode.cpp index d0209d381..1446d2a42 100644 --- a/src/osgPlugins/txp/TXPNode.cpp +++ b/src/osgPlugins/txp/TXPNode.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include @@ -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(&nv); + if (cv) + { + //const osg::Timer& timer = *osg::Timer::instance(); + //osg::Timer_t start = timer.tick(); + //std::cout<<"Doing visible tile search"< 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 "<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(); - + } } diff --git a/src/osgPlugins/txp/TXPPagedLOD.cpp b/src/osgPlugins/txp/TXPPagedLOD.cpp index a146cac5f..64a980b02 100644 --- a/src/osgPlugins/txp/TXPPagedLOD.cpp +++ b/src/osgPlugins/txp/TXPPagedLOD.cpp @@ -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(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;igetPagedLOD(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 "<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 "<0 && ((int)numChildren-1)!=_lastChildTraversed) + if (numChildren>0 && ((int)numChildren-1)!=lastChildTraversed) { //std::cout<<" to child "<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; } } + diff --git a/src/osgPlugins/txp/TXPPagedLOD.h b/src/osgPlugins/txp/TXPPagedLOD.h index ee3927681..3440f5c43 100644 --- a/src/osgPlugins/txp/TXPPagedLOD.h +++ b/src/osgPlugins/txp/TXPPagedLOD.h @@ -35,6 +35,7 @@ #define __TXPPAGEDLOD_H_ #include +#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 _neighbours; }; } // namespace diff --git a/src/osgPlugins/txp/TXPParser.cpp b/src/osgPlugins/txp/TXPParser.cpp index 34bb50057..67b4a0ead 100644 --- a/src/osgPlugins/txp/TXPParser.cpp +++ b/src/osgPlugins/txp/TXPParser.cpp @@ -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 ) { diff --git a/src/osgPlugins/txp/TXPSeamLOD.cpp b/src/osgPlugins/txp/TXPSeamLOD.cpp index 3a5604a78..79cf214bb 100644 --- a/src/osgPlugins/txp/TXPSeamLOD.cpp +++ b/src/osgPlugins/txp/TXPSeamLOD.cpp @@ -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(TileMapper::instance()->getPagedLOD(_neighbourTileX,_neighbourTileY, _neighbourTileLOD)); -#if 1 - if (pagedLOD && pagedLOD->getLastTraversedChild()>0) + + TileMapper* tileMapper = dynamic_cast(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 = "<getCenter()<getNumChildren()); - for(int i=numChildren-1;i>=0;--i) - { - //std::cout<<" child "<getMinRange(i)<<" max = "<getMaxRange(i)<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 { diff --git a/src/osgPlugins/txp/TXPSeamLOD.h b/src/osgPlugins/txp/TXPSeamLOD.h index 0eb7b05fe..e3a97de06 100644 --- a/src/osgPlugins/txp/TXPSeamLOD.h +++ b/src/osgPlugins/txp/TXPSeamLOD.h @@ -39,8 +39,7 @@ #include #include -#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; }; } diff --git a/src/osgPlugins/txp/TXPTileNode.cpp b/src/osgPlugins/txp/TXPTileNode.cpp deleted file mode 100644 index 1be0898d7..000000000 --- a/src/osgPlugins/txp/TXPTileNode.cpp +++ /dev/null @@ -1,309 +0,0 @@ -#include - -#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() <getDir(), - lod, - x, - y, - _archive->getId() - ); - - osg::ref_ptr 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; -} - - diff --git a/src/osgPlugins/txp/TXPTileNode.h b/src/osgPlugins/txp/TXPTileNode.h deleted file mode 100644 index 198ad5b25..000000000 --- a/src/osgPlugins/txp/TXPTileNode.h +++ /dev/null @@ -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 -#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_ diff --git a/src/osgPlugins/txp/TileMapper.cpp b/src/osgPlugins/txp/TileMapper.cpp index 59585f4ee..1fb7f51f8 100644 --- a/src/osgPlugins/txp/TileMapper.cpp +++ b/src/osgPlugins/txp/TileMapper.cpp @@ -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 +//#include "TXPTileNode.h" +#include "TXPPagedLOD.h" + +#include using namespace txp; -TileMapper* TileMapper::instance() +float TileMapper::getDistanceToEyePoint(const osg::Vec3& pos, bool withLODScale) const { - static osg::ref_ptr 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 lock(_mutex); - TileMap::iterator itr = _tileMap.find(TileTriple(x,y,lod)); - if (itr!=_tileMap.end()) return itr->second; - else return 0; + + //std::cout << "distance("< 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 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 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()<(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="<lod + <<" X="<x + <<" Y="<y + <<" ptr="<<&node<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"<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 ToRemoveList; + typedef std::vector ToAddList; + + ToRemoveList toRemoveList; + ToAddList toAddList; + + do + { +// std::cout<<"doing checkAllVisibleTiles() loop with "<<_tileMap.size()<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="<first.lod +// <<" X="<first.x +// <<" Y="<first.y<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()<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; } diff --git a/src/osgPlugins/txp/TileMapper.h b/src/osgPlugins/txp/TileMapper.h index 4a4503ad1..b8b1d26f7 100644 --- a/src/osgPlugins/txp/TileMapper.h +++ b/src/osgPlugins/txp/TileMapper.h @@ -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 -#include +#include +#include -#include +#include 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 (lodrhs.lod) + return false; + if (xrhs.x) + return false; + if (yrhs.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 > 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 (xrhs.x) - return false; - if (yrhs.y) - return false; - if (lodrhs.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_