The DtTerrainPageSignaler has signals that are triggered when pages from a database page in and out. The signaler will raise signals for anything that is derived from osg::PagedLOD, for example TerraPage (TXPPagedLOD). It also works with DtHierarchicalPagedLod (which does not derive from osg::PagedLOD). This example demonstrates how to listen in on DtTerrainPageSignaler signals and do some custom processing on those pages.
This example is best run with a database that has Proxy Nodes (external references) in it. This can be MetaFlight, TerraPage, etc. When a child of a Page pages in (that is, data for it has been loaded from the disk and the child added to the scenegraph as child of the page), we look for proxy nodes underneath the child. Then, we register the proxy nodes with the page in a map (if it has not been registered already)
When the children are about to page out (i.e. are going to be removed from underneath the page, and hence the scenegraph), we look for proxy nodes again, and remove them from the map.
Looking for proxy nodes is just an illustration. One can look for other types of nodes (e.g. grab at light point nodes and turn them on/off), track what pages are paged in/out, etc.
This example is a plug-in. You can run it by running ./bin64/exampleOsgTerrainPaging_stealth.bat (on Windows) or ./bin64/exampleOsgTerrainPaging_stealth.sh (on Linux). Once Vantage is started, load a MetaFlight terrain database (for example BDesign3dNevada.mft from the supplemental data package).
#include <vlutil/vlPerformanceStats.h>
#include <boost/bind.hpp>
#include <boost/unordered_set.hpp>
#include <boost/unordered_map.hpp>
#include <osg/ProxyNode>
#include <boost/foreach.hpp>
using namespace makVrv;
class PagedLODsProcessor
{
public:
PagedLODsProcessor();
~PagedLODsProcessor();
void printDetails(void);
void printDetailsTimed(void);
private:
void slot_childPagedIn(const osg::Group* page, const osg::Node* child);
void slot_childAboutToPageOut(const osg::Group* page, const osg::Node* child);
typedef std::vector<boost::signalslib::connection> Connections;
Connections myConnections;
typedef boost::unordered_set<osg::ProxyNode*> SetProxyNodes;
typedef boost::unordered_map<osg::Node*, SetProxyNodes> MapLODsToProxyNodes;
MapLODsToProxyNodes myMapLODsToProxyNodes;
void connectSignals(void);
DtTimedSection myTimer;
};
PagedLODsProcessor::PagedLODsProcessor()
: myDe(0)
{
}
void PagedLODsProcessor::printDetails(void)
{
for(MapLODsToProxyNodes::const_iterator it = myMapLODsToProxyNodes.begin(); it != myMapLODsToProxyNodes.end();++it)
{
const SetProxyNodes& proxyNodes = it->second;
count += proxyNodes.size();
}
std::cout<<"Num of Pages: "<<myMapLODsToProxyNodes.size()<<std::endl;
std::cout<<"Num of Proxy Nodes:"<<count<<std::endl;
}
void PagedLODsProcessor::printDetailsTimed()
{
static const float duration = 2.0;
static double elapsedTime = 0;
static double lastTime = 0;
double curr = myDe->simulationTime();
elapsedTime += (curr-lastTime);
lastTime = curr;
if (elapsedTime>duration)
{
printDetails();
elapsedTime = 0;
}
}
PagedLODsProcessor::~PagedLODsProcessor()
{
BOOST_FOREACH(boost::signalslib::connection& conn, myConnections)
{
conn.disconnect();
}
myConnections.clear();
printDetails();
}
{
myDe = de;
connectSignals();
}
void PagedLODsProcessor::connectSignals()
{
}
void PagedLODsProcessor::slot_childPagedIn(const osg::Group* page, const osg::Node* child)
{
osg::Group* pageNonConst = const_cast<osg::Group*>(page);
osg::Node* childNonConst = const_cast<osg::Node*>(child);
if (myMapLODsToProxyNodes.find(pageNonConst) == myMapLODsToProxyNodes.end())
{
myMapLODsToProxyNodes.insert(std::make_pair(pageNonConst, SetProxyNodes()));
}
childNonConst->accept(visitor);
const ProxyNodes& proxyNodes = visitor.proxyNodes();
for(ProxyNodes::const_iterator it = proxyNodes.begin(); it != proxyNodes.end(); ++it)
{
osg::ProxyNode* node = *it;
if (node->getNumFileNames()>0)
{
std::cout<<"Proxy node filename: "<< myDe->dePathConfiguration().resolvePath( node->getFileName(0) ) <<std::endl;
}
myMapLODsToProxyNodes[pageNonConst].insert(node);
}
}
void PagedLODsProcessor::slot_childAboutToPageOut(const osg::Group* page, const osg::Node* child)
{
osg::Group* pageNonConst = const_cast<osg::Group*>(page);
osg::Node* childNonConst = const_cast<osg::Node*>(child);
ASSERT_PREDICATE(myMapLODsToProxyNodes.find(pageNonConst) != myMapLODsToProxyNodes.end());
if (myMapLODsToProxyNodes.find(pageNonConst) == myMapLODsToProxyNodes.end())
{
std::cout<<"Page not registered"<<std::endl;
return;
}
childNonConst->accept(visitor);
const ProxyNodes& proxyNodes = visitor.proxyNodes();
for(ProxyNodes::const_iterator it = proxyNodes.begin(); it != proxyNodes.end(); ++it)
{
osg::ProxyNode* node = *it;
ASSERT_PREDICATE(myMapLODsToProxyNodes[pageNonConst].find(node) != myMapLODsToProxyNodes[pageNonConst].
end());
if (myMapLODsToProxyNodes[pageNonConst].find(node) != myMapLODsToProxyNodes[pageNonConst].
end())
{
myMapLODsToProxyNodes[pageNonConst].erase(node);
}
}
}
static PagedLODsProcessor processor;
{
processor.init(de);
std::cout<<"Initialized Osg Terrain Paging Callbacks!!"<<std::endl;
}
{
{
}
}
{
{
return true;
}
return false;
}