Added osg::PagedLOD and osgProducer::DatabasePager class, and linked up osgProducer::Viewer

to manage the pager.
This commit is contained in:
Robert Osfield
2003-07-08 14:44:00 +00:00
parent 9239173019
commit c2eabe1d4b
21 changed files with 810 additions and 59 deletions

View File

@@ -55,6 +55,7 @@ CXXFILES =\
Notify.cpp\
Object.cpp\
OccluderNode.cpp\
PagedLOD.cpp\
Point.cpp\
PolygonMode.cpp\
PolygonOffset.cpp\

143
src/osg/PagedLOD.cpp Normal file
View File

@@ -0,0 +1,143 @@
#include <osg/PagedLOD>
using namespace osg;
PagedLOD::PagedLOD(const PagedLOD& plod,const CopyOp& copyop):
LOD(plod,copyop)
{
}
void PagedLOD::traverse(NodeVisitor& nv)
{
double timeStamp = nv.getFrameStamp()?nv.getFrameStamp()->getReferenceTime():0.0;
bool updateTimeStamp = nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR;
switch(nv.getTraversalMode())
{
case(NodeVisitor::TRAVERSE_ALL_CHILDREN):
std::for_each(_children.begin(),_children.end(),NodeAcceptOp(nv));
break;
case(NodeVisitor::TRAVERSE_ACTIVE_CHILDREN):
{
float distance = nv.getDistanceToEyePoint(getCenter(),true);
// first check to see if any children can be directly traversed.
unsigned int numChildren = osg::minimum(_children.size(),numChildren=_rangeList.size());
bool childTraversed = false;
for(unsigned int i=0;i<numChildren;++i)
{
if (_rangeList[i].first<=distance && distance<_rangeList[i].second)
{
if (updateTimeStamp) _timeStampList[i]=timeStamp;
//std::cout<<"PagedLOD::traverse() - Selecting child "<<i<<std::endl;
_children[i]->accept(nv);
childTraversed = true;
}
}
if (!childTraversed)
{
//std::cout<<"PagedLOD::traverse() - falling back "<<std::endl;
// select the last valid child.
if (numChildren>0)
{
//std::cout<<" to child "<<numChildren-1<<std::endl;
if (updateTimeStamp) _timeStampList[numChildren-1]=timeStamp;
_children[numChildren-1]->accept(nv);
}
// now request the loading of the next unload child.
if (nv.getDatabaseRequestHandler() && numChildren<_fileNameList.size())
{
//std::cout<<" requesting child "<<_fileNameList[numChildren]<<std::endl;
nv.getDatabaseRequestHandler()->requestNodeFile(_fileNameList[numChildren],this);
}
}
break;
}
default:
break;
}
}
bool PagedLOD::addChild( Node *child )
{
if (LOD::addChild(child))
{
if (_children.size()>_fileNameList.size()) _fileNameList.resize(_children.size());
if (_children.size()>_timeStampList.size()) _timeStampList.resize(_children.size(),0);
return true;
}
return false;
}
bool PagedLOD::addChild(Node *child, float min, float max)
{
if (LOD::addChild(child,min,max))
{
if (_children.size()>_fileNameList.size()) _fileNameList.resize(_children.size());
if (_children.size()>_timeStampList.size()) _timeStampList.resize(_children.size(),0.0);
return true;
}
return false;
}
bool PagedLOD::addChild(Node *child, float min, float max,const std::string& filename)
{
if (LOD::addChild(child,min,max))
{
if (_children.size()>_fileNameList.size()) _fileNameList.resize(_children.size());
if (_children.size()>_timeStampList.size()) _timeStampList.resize(_children.size(),0.0);
_fileNameList[_children.size()-1] = filename;
return true;
}
return false;
}
bool PagedLOD::removeChild( Node *child )
{
// find the child's position.
unsigned int pos=getChildIndex(child);
if (pos==_children.size()) return false;
_rangeList.erase(_rangeList.begin()+pos);
_fileNameList.erase(_fileNameList.begin()+pos);
_timeStampList.erase(_timeStampList.begin()+pos);
return Group::removeChild(child);
}
void PagedLOD::setFileName(unsigned int childNo, const std::string& filename)
{
if (childNo>=_fileNameList.size()) _fileNameList.resize(childNo+1);
_fileNameList[childNo] = filename;
}
void PagedLOD::setTimeStamp(unsigned int childNo, double timeStamp)
{
if (childNo>=_timeStampList.size()) _timeStampList.resize(childNo+1,0.0);
_timeStampList[childNo] = timeStamp;
}
void PagedLOD::removeExpiredChildren(double expiryTime)
{
for(unsigned int i=_children.size();i>0;)
{
--i;
if (!_fileNameList[i].empty() && _timeStampList[i]<expiryTime)
{
//std::cout<<"Removing child "<<_children[i].get()<<std::endl;
Group::removeChild(_children[i].get());
}
}
}

View File

@@ -31,6 +31,44 @@
using namespace osg;
using namespace osgDB;
#if 0
// temporary test of autoregistering, not compiled by default.
enum Methods
{
SET_1,
SET_2,
END
};
typedef std::pair<Methods,std::string> MethodPair;
class Proxy
{
public:
Proxy(MethodPair* methods)
{
std::cout<<"methods "<<methods<<std::endl;
for(int i=0;methods[i].first!=END;++i)
{
std::cout<<"\t"<<methods[i].first<<"\t"<<methods[i].second<<std::endl;
}
}
};
static MethodPair methods[] =
{
MethodPair(SET_1,"SET_1"),
MethodPair(SET_2,"SET_2"),
MethodPair(END,"")
};
Proxy myproxy(methods);
#endif
void PrintFilePathList(std::ostream& stream,const FilePathList& filepath)
{
for(FilePathList::const_iterator itr=filepath.begin();

View File

@@ -34,6 +34,7 @@ CXXFILES =\
Node.cpp\
Object.cpp\
OccluderNode.cpp\
PagedLOD.cpp\
Point.cpp\
PolygonMode.cpp\
PolygonOffset.cpp\

View File

@@ -0,0 +1,125 @@
#include "osg/PagedLOD"
#include "osgDB/Registry"
#include "osgDB/Input"
#include "osgDB/Output"
using namespace osg;
using namespace osgDB;
// forward declare functions to use later.
bool PagedLOD_readLocalData(Object& obj, Input& fr);
bool PagedLOD_writeLocalData(const Object& obj, Output& fw);
// register the read and write functions with the osgDB::Registry.
RegisterDotOsgWrapperProxy g_PagedLODProxy
(
new osg::PagedLOD,
"PagedLOD",
"Object Node LOD PagedLOD",
&PagedLOD_readLocalData,
&PagedLOD_writeLocalData
);
bool PagedLOD_readLocalData(Object& obj, Input& fr)
{
bool iteratorAdvanced = false;
PagedLOD& lod = static_cast<PagedLOD&>(obj);
bool matchFirst;
if ((matchFirst=fr.matchSequence("FileNameList {")) || fr.matchSequence("FileNameList %i {"))
{
// set up coordinates.
int entry = fr[0].getNoNestedBrackets();
int capacity;
if (matchFirst)
{
fr += 2;
}
else if (fr[1].getInt(capacity))
{
lod.getFileNameList().reserve(capacity);
fr += 3;
}
unsigned int i=0;
while (!fr.eof() && fr[0].getNoNestedBrackets()>entry)
{
if (fr[0].isString() || fr[0].isQuotedString())
{
if (fr[0].getStr()) lod.setFileName(i,fr[0].getStr());
else lod.setFileName(i,"");
++fr;
++i;
}
else
{
++fr;
}
}
iteratorAdvanced = true;
++fr;
}
int num_children;
if (fr[0].matchWord("num_children") &&
fr[1].getInt(num_children))
{
// could allocate space for children here...
fr+=2;
iteratorAdvanced = true;
}
Node* node = NULL;
while((node=fr.readNode())!=NULL)
{
lod.addChild(node);
iteratorAdvanced = true;
}
return iteratorAdvanced;
}
bool PagedLOD_writeLocalData(const Object& obj, Output& fw)
{
const PagedLOD& lod = static_cast<const PagedLOD&>(obj);
fw.indent() << "FileNameList "<<lod.getNumFileNames()<<" {"<< std::endl;
fw.moveIn();
unsigned int numChildrenToWriteOut = 0;
for(unsigned int i=0; i<lod.getNumFileNames();++i)
{
if (lod.getFileName(i).empty())
{
fw.indent() << "\"\"" << std::endl;
++numChildrenToWriteOut;
}
else
{
fw.indent() << lod.getFileName(i) << std::endl;
}
}
fw.moveOut();
fw.indent() << "}"<< std::endl;
fw.indent() << "num_children " << numChildrenToWriteOut << std::endl;
for(unsigned int i=0;i<lod.getNumChildren();++i)
{
if (lod.getFileName(i).empty())
{
fw.writeObject(*lod.getChild(i));
}
}
return true;
}

View File

@@ -0,0 +1,198 @@
#include <osgProducer/DatabasePager>
#include <osgDB/ReadFile>
using namespace osgProducer;
DatabasePager::DatabasePager()
{
std::cout<<"Constructing DatabasePager()"<<std::endl;
_expiryDelay = 1.0;
}
void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* group)
{
// search to see if filename already exist in the file loaded list.
bool foundEntry = false;
_fileLoadedListMutex.lock();
for(DatabaseRequestList::iterator litr = _fileLoadedList.begin();
litr != _fileLoadedList.end() && !foundEntry;
++litr)
{
if ((*litr)->_fileName==fileName)
{
foundEntry = true;
++((*litr)->_numOfRequests);
}
}
_fileLoadedListMutex.unlock();
if (!foundEntry)
{
_fileRequestListMutex.lock();
// search to see if entry already in file request list.
bool foundEntry = false;
for(DatabaseRequestList::iterator ritr = _fileRequestList.begin();
ritr != _fileRequestList.end() && !foundEntry;
++ritr)
{
if ((*ritr)->_fileName==fileName)
{
foundEntry = true;
++((*ritr)->_numOfRequests);
}
}
if (!foundEntry)
{
osg::ref_ptr<DatabaseRequest> databaseRequest = new DatabaseRequest;
databaseRequest->_fileName = fileName;
databaseRequest->_groupForAddingLoadedSubgraph = group;
_fileRequestList.push_back(databaseRequest);
}
_fileRequestListMutex.unlock();
}
if (!threadIsRunning())
{
std::cout<<"DatabasePager::startThread()"<<std::endl;
startThread();
}
}
void DatabasePager::run()
{
std::cout<<"DatabasePager::run()"<<std::endl;
while(true)
{
osg::ref_ptr<DatabaseRequest> databaseRequest;
// get the front of the file request list.
_fileRequestListMutex.lock();
if (!_fileRequestList.empty()) databaseRequest = _fileRequestList.front();
_fileRequestListMutex.unlock();
if (databaseRequest.valid())
{
// load the data, note safe to write to the databaseRequest since once
// it is created this thread is the only one to write to the _loadedModel pointer.
databaseRequest->_loadedModel = osgDB::readNodeFile(databaseRequest->_fileName);
_fileRequestListMutex.lock();
_fileRequestList.erase(_fileRequestList.begin());
_fileRequestListMutex.unlock();
if (databaseRequest->_loadedModel.valid())
{
_fileLoadedListMutex.lock();
_fileLoadedList.push_back(databaseRequest);
_fileLoadedListMutex.unlock();
}
}
// hack hack hack... sleep for 1ms so we give other threads a chance..
#ifdef WIN32
Sleep(1);
#else
usleep(1000);
#endif
}
cancel();
join();
}
void DatabasePager::addLoadedDataToSceneGraph()
{
DatabaseRequestList localFileLoadedList;
// get the dat for the _fileLoadedList, leaving it empty via a std::vector<>.swap.
_fileLoadedListMutex.lock();
localFileLoadedList.swap(_fileLoadedList);
_fileLoadedListMutex.unlock();
// add the loaded data into the scene graph.
for(DatabaseRequestList::iterator itr=localFileLoadedList.begin();
itr!=localFileLoadedList.end();
++itr)
{
DatabaseRequest* databaseRequest = itr->get();
registerPagedLODs(databaseRequest->_loadedModel.get());
databaseRequest->_groupForAddingLoadedSubgraph->addChild(databaseRequest->_loadedModel.get());
//std::cout<<"merged subgraph"<<databaseRequest->_fileName<<" after "<<databaseRequest->_numOfRequests<<" requests."<<std::endl;
}
}
void DatabasePager::removeExpiredSubgraphs(double currentFrameTime)
{
double expiryTime = currentFrameTime - _expiryDelay;
//std::cout<<"DatabasePager::removeExpiredSubgraphs("<<expiryTime<<") "<<std::endl;
for(PagedLODList::iterator itr=_pagedLODList.begin();
itr!=_pagedLODList.end();
++itr)
{
osg::PagedLOD* plod = itr->get();
plod->removeExpiredChildren(expiryTime);
}
for(unsigned int i=_pagedLODList.size();
i>0;
)
{
--i;
osg::PagedLOD* plod = _pagedLODList[i].get();
if (plod->referenceCount()==1)
{
//std::cout<<" PagedLOD "<<plod<<" orphaned"<<std::endl;
_pagedLODList.erase(_pagedLODList.begin()+i);
}
else
{
//std::cout<<" PagedLOD "<<plod<<" refcount "<<plod->referenceCount()<<std::endl;
}
}
}
class FindPagedLODsVisitor : public osg::NodeVisitor
{
public:
FindPagedLODsVisitor(DatabasePager::PagedLODList& pagedLODList):
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_pagedLODList(pagedLODList)
{
}
virtual void apply(osg::PagedLOD& plod)
{
_pagedLODList.push_back(&plod);
traverse(plod);
}
DatabasePager::PagedLODList& _pagedLODList;
};
void DatabasePager::registerPagedLODs(osg::Node* subgraph)
{
FindPagedLODsVisitor fplv(_pagedLODList);
if (subgraph) subgraph->accept(fplv);
}

View File

@@ -2,6 +2,7 @@ TOPDIR = ../..
include $(TOPDIR)/Make/makedefs
CXXFILES =\
DatabasePager.cpp\
EventAdapter.cpp\
KeyboardMouseCallback.cpp\
OsgCameraGroup.cpp\

View File

@@ -19,6 +19,7 @@
#include <osgDB/FileUtils>
#include <osgProducer/OsgCameraGroup>
#include <osgProducer/DatabasePager>
using namespace Producer;
using namespace osgProducer;
@@ -262,23 +263,32 @@ bool OsgCameraGroup::realize( ThreadingModel thread_model )
// small visitor to check for the existance of particle systems,
// which currently arn't thread safe, so we would need to disable
// multithreading of cull and draw.
class SearchForParticleNodes : public osg::NodeVisitor
class SearchForSpecialNodes : public osg::NodeVisitor
{
public:
SearchForParticleNodes():
SearchForSpecialNodes():
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_foundParticles(false)
_foundParticles(false),
_foundPagedLOD(false)
{
}
virtual void apply(osg::Node& node)
{
if (strcmp(node.libraryName(),"osgParticle")==0) _foundParticles = true;
if (!_foundParticles) traverse(node);
if (!_foundParticles ||
!_foundPagedLOD) traverse(node);
}
virtual void apply(osg::PagedLOD& node)
{
_foundPagedLOD = true;
apply((osg::Node&)node);
}
bool _foundParticles;
bool _foundPagedLOD;
};
bool OsgCameraGroup::realize()
@@ -373,11 +383,11 @@ bool OsgCameraGroup::realize()
setUpSceneViewsWithData();
if (getTopMostSceneData() && _thread_model!=Producer::CameraGroup::SingleThreaded)
if (getTopMostSceneData())
{
SearchForParticleNodes sfpn;
getTopMostSceneData()->accept(sfpn);
if (sfpn._foundParticles)
SearchForSpecialNodes sfsn;
getTopMostSceneData()->accept(sfsn);
if (sfsn._foundParticles)
{
osg::notify(osg::INFO)<<"Warning: disabling multi-threading of cull and draw"<<std::endl;
osg::notify(osg::INFO)<<" to avoid threading problems in osgParticle."<<std::endl;
@@ -403,7 +413,26 @@ bool OsgCameraGroup::realize()
}
if (sfsn._foundPagedLOD)
{
std::cout << "setting up paged LOD"<<std::endl;
_databasePager = new DatabasePager;
_databasePager->registerPagedLODs(getTopMostSceneData());
for(SceneHandlerList::iterator p=_shvec.begin();
p!=_shvec.end();
++p)
{
(*p)->getSceneView()->getCullVisitor()->setDatabaseRequestHandler(_databasePager.get());
}
}
}
_initialized = CameraGroup::realize();

View File

@@ -352,6 +352,16 @@ void Viewer::update()
}
}
if (_databasePager.valid())
{
// removed any children PagedLOD children that havn't been visited in the cull traversal recently.
_databasePager->removeExpiredSubgraphs(_frameStamp->getReferenceTime());
// add the newly loaded data into the scene graph.
_databasePager->addLoadedDataToSceneGraph();
}
if (_updateVisitor.valid())
{
_updateVisitor->setTraversalNumber(_frameStamp->getFrameNumber());