VR-Forces 5.0.2 Developer's Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
exampleOsgTerrainPaging

Table of Contents

Overview

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.

Expected Result

exampleOsgTerrainPaging.png
Osg Terrain Paging Result

Example details

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.

Building the Example

VR-Vantage includes pre-built versions of the example plug-in. To build it yourself, follow the instructions at Building VR-Vantage Examples, Applications, and Plug-ins.

Running the Example

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).

For more information about running examples, please see Running Applications and Examples.

Example Source Files


exampleNodeVisitor.cxx

/*****************************************************************************
* Copyright (c) 2022 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include <osg/ProxyNode>
#include <osg/Transform>
#include <iostream>
namespace makVrv
{
: osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN )
{
}
ExampleNodeVisitor::~ExampleNodeVisitor()
{
}
void ExampleNodeVisitor::apply(osg::ProxyNode& node)
{
myProxyNodes.push_back(&node);
}
const ProxyNodes& ExampleNodeVisitor::proxyNodes(void) const
{
return myProxyNodes;
}
}

exampleNodeVisitor.h

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#pragma once
#include <vrvOsg/vrvOsg.h>
#include <osg/NodeVisitor>
#include <vector>
namespace osg
{
class ProxyNode;
};
namespace makVrv
{
typedef std::vector<osg::ProxyNode*> ProxyNodes;
class ExampleNodeVisitor : public osg::NodeVisitor
{
public:
virtual void apply(osg::ProxyNode& node);
const ProxyNodes& proxyNodes(void) const;
private:
};
}

exampleOsgTerrainPaging.h

/*********************************************************************
** Copyright (c) 2019 MaK Technologies, Inc.
** All rights reserved.
*********************************************************************/
#pragma once
#ifdef _WIN32
#ifdef EXAMPLEOSGTERRAINPAGING_EXPORTS
#define DT_DLL_EXAMPLEOSGTERRAINPAGING __declspec ( dllexport )
#else
#define DT_DLL_EXAMPLEOSGTERRAINPAGING __declspec ( dllimport )
#endif
#else
#define DT_DLL_EXAMPLEOSGTERRAINPAGING
#endif

exampleOsgTerrainPagingPlugin.cxx

/*********************************************************************
** Copyright (c) 2020 MaK Technologies, Inc.
** All rights reserved.
*********************************************************************/
#include <vrvCore/DtDe.h>
#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;
// This demonstrates the use of DtTerrainPageSignaler to listen in on paged in and out events
class PagedLODsProcessor
{
public:
PagedLODsProcessor();
~PagedLODsProcessor();
void init(DtDe* de);
void printDetails(void);
void printDetailsTimed(void);
private:
// handler for when a child of a page pages in (ie files pertaining to it
// have been loaded and the child added to the scenegraph under the page node
void slot_childPagedIn(const osg::Group* page, const osg::Node* child);
// handler for when a child of a page pages out (ie files pertaining to it
// have been un-loaded and the child about to be removed from under the page
// node (and hence the scene graph)
void slot_childAboutToPageOut(const osg::Group* page, const osg::Node* child);
typedef std::vector<boost::signalslib::connection> Connections;
Connections myConnections;
DtDe* myDe;
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)
{
unsigned int count = 0;
for(MapLODsToProxyNodes::const_iterator it = myMapLODsToProxyNodes.begin(); it != myMapLODsToProxyNodes.end();++it)
{
const SetProxyNodes& proxyNodes = it->second;
count += proxyNodes.size();
}
// This will change as pages page in and out
// When the terrain closes, this does not go to zero
// This is because we don't listen in on Paged deletion events
// Please look at DtOsgNodeObserver on how this can be handled
// Even if we listen in on the pages' deletion, and clear our map,
// the number of pages may not go to zero
// This is because osg may hang on to some nodes in its own internal cache
// as per its own caching policy and not delete them
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()
{
DtTerrainPageSignaler& signaler = DtTerrainPageSignaler::instance(*myDe);
// Connect the signals and the slots
myConnections.push_back(signaler.signal_childPagedIn.connect(boost::bind(&PagedLODsProcessor::slot_childPagedIn, this, _1, _2)));
myConnections.push_back(signaler.signal_childAboutToPageOut.connect(boost::bind(&PagedLODsProcessor::slot_childAboutToPageOut, this, _1, _2)));
}
void PagedLODsProcessor::slot_childPagedIn(const osg::Group* page, const osg::Node* child)
{
// Hack: the visitor methods are not const. most visitors are actually just read only visitors.
// There should be appropriate overloads in osg
osg::Group* pageNonConst = const_cast<osg::Group*>(page);
osg::Node* childNonConst = const_cast<osg::Node*>(child);
// There's no entry corresponding to this page
if (myMapLODsToProxyNodes.find(pageNonConst) == myMapLODsToProxyNodes.end())
{
// Therefore, just make an entry
myMapLODsToProxyNodes.insert(std::make_pair(pageNonConst, SetProxyNodes()));
}
// Let's say that we are interested in just the proxy nodes for the child
// Therefore, find the proxy nodes under this child. A different usage
// case might involve looking for light point nodes and turning them on/off, etc
// You could look for other nodes of interest. For example, light point nodes, etc
childNonConst->accept(visitor);
// Register all unique proxy nodes encountered
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)
{
// Hack: the visitor methods are not const. most visitors are actually just read only visitors.
// There should be appropriate overloads in osg
osg::Group* pageNonConst = const_cast<osg::Group*>(page);
osg::Node* childNonConst = const_cast<osg::Node*>(child);
// If a child for this page is paging out, an entry must have been made above
ASSERT_PREDICATE(myMapLODsToProxyNodes.find(pageNonConst) != myMapLODsToProxyNodes.end());
// This actually should not happen
if (myMapLODsToProxyNodes.find(pageNonConst) == myMapLODsToProxyNodes.end())
{
std::cout<<"Page not registered"<<std::endl;
return;
}
// Find proxy nodes under this child
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())
{
// Erase the entry
myMapLODsToProxyNodes[pageNonConst].erase(node);
}
}
}
static PagedLODsProcessor processor;
{
processor.init(de);
std::cout<<"Initialized Osg Terrain Paging Callbacks!!"<<std::endl;
de->signal_postTick.connect(boost::bind(&PagedLODsProcessor::printDetailsTimed, &processor));
}
void init(DtDe& de)
{
// Ensure that init only gets called once
// (not strictly necessary here, but this is good practice in general)
// We only want to create the accessory if we're running in master mode:
if (de.isInMasterMode())
{
}
}
{
// Setup the plugin. Normally, the init function and functionality
// should be in its own library.
{
init(*de);
return true;
}
return false;
}

exampleOsgTerrainPagingPlugin.h

/******************************************************************************
** Copyright (c) 2019 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
// Get proper local export symbol
// Setup proper plugin export symbol
#define DT_DE_PLUGIN_EXPORT_MACRO DT_DLL_EXAMPLEOSGTERRAINPAGING
// Declare & export the plugin initialization function (bool initDeModule(DtDe* de))
namespace makVrv { class DtDe; }
// Work function for the plugin initialization
// Callback to load the DtAccessoryDriver into the display engine

[<< Examples] [Home] [Top of Page]


Document ID: Generated on Sun Dec 4 20:22:03 EST 2022 from SVN revision 249613
Copyright © 2005-2021 MAK Technologies. All Rights Reserved (www.mak.com)