Hi Adrian,
I have just checked in a trial of using localised prototype()/create()
methods added to CullVisitor and DatabasePager. The added methods
look like:
/** Create a shallow copy of the CullVisitor, used by
CullVisitor::create() to clone the prototype..*/
virtual CullVisitor* clone() const { return new CullVisitor(*this); }
/** get the prototype singleton used by CullVisitor::create().*/
static osg::ref_ptr<CullVisitor>& prototype();
/** create a CullVisitor by cloning CullVisitor::prototype().*/
static CullVisitor* create();
The DatabasePager is exactly the save for class name. The
implementation looks like:
osg::ref_ptr<CullVisitor>& CullVisitor::prototype()
{
static osg::ref_ptr<CullVisitor> s_CullVisitor = new CullVisitor;
return s_CullVisitor;
}
CullVisitor* CullVisitor::create()
{
return CullVisitor::prototype().valid() ?
CullVisitor::prototype()->clone() :
new CullVisitor;
}
Things to note are the fact that the prototype method passed back a
reference to the static ref_ptr<CullVisitor>, this allows you to
directly modify it without the need for a set/get pairing.
To pass on your own implementations you'll need to something like the
following (note, the copy constructor and clone() method being
overriden):
class MyCullVisitor : public osgUtil::CullVisitor
{
public:
MyCullVisitor()
{
osg::notify(osg::NOTICE)<<"Constructig my CullVisitor
"<<this<<std::endl;
}
MyCullVisitor(const MyCullVisitor& rhs):
CullVisitor(rhs)
{
osg::notify(osg::NOTICE)<<"Constructig my
CullVisitor(CullVisitor)"<<this<<std::endl;
}
~MyCullVisitor()
{
osg::notify(osg::NOTICE)<<"Destructig my
MyCullVisitor"<<this<<std::endl;
}
virtual CullVisitor* clone() const { return new MyCullVisitor(*this); }
void apply(osg::Geode& geode)
{
// osg::notify(osg::NOTICE)<<"In
MyCullVisitor::apply(Geode)"<<std::endl;
CullVisitor::apply(geode);
}
};
class MyDatabasePager : public osgDB::DatabasePager
{
public:
MyDatabasePager()
{
osg::notify(osg::NOTICE)<<"Constructig my MyDatabasePager"<<std::endl;
}
MyDatabasePager(const MyDatabasePager& rhs):
DatabasePager(rhs)
{
osg::notify(osg::NOTICE)<<"Constructig my MyDatabasePager"<<std::endl;
}
~MyDatabasePager()
{
osg::notify(osg::NOTICE)<<"Destructig my MyDatabasePager"<<std::endl;
}
virtual DatabasePager* clone() const { return new MyDatabasePager(*this); }
};
int main(int argc, char** argv)
{
osgUtil::CullVisitor::prototype() = new MyCullVisitor;
osgDB::DatabasePager::prototype() = new MyDatabasePager;
.. usual set up of your application, osgViewer will now use these prototypes..
}
Attached is osgviewer.cpp modified with these changes.
The reason for me going for this solution is simply to keep the
factory method localised to each class, and it also offers the
possibility of configuring the original prototype without needing to
create a new instance.
A further evolution might be to make the default and copy constructors
of CullVisitor/DatabasePager pager protected to force developers to go
via the create() method, but this would prevent some types of usage so
I'll hang back on this.
Robert.
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This application is open source and may be redistributed and/or modified
* freely and without restriction, both in commericial and non commericial applications,
* as long as this copyright notice is maintained.
*
* This application 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.
*/
#include <osgDB/ReadFile>
#include <osgUtil/Optimizer>
#include <osg/CoordinateSystemNode>
#include <osg/Switch>
#include <osgText/Text>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/DriveManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgGA/StateSetManipulator>
#include <osgGA/AnimationPathManipulator>
#include <osgGA/TerrainManipulator>
#include <iostream>
class MyCullVisitor : public osgUtil::CullVisitor
{
public:
MyCullVisitor()
{
osg::notify(osg::NOTICE)<<"Constructig my CullVisitor "<<this<<std::endl;
}
MyCullVisitor(const MyCullVisitor& rhs):
CullVisitor(rhs)
{
osg::notify(osg::NOTICE)<<"Constructig my CullVisitor(CullVisitor)"<<this<<std::endl;
}
~MyCullVisitor()
{
osg::notify(osg::NOTICE)<<"Destructig my MyCullVisitor"<<this<<std::endl;
}
virtual CullVisitor* clone() const { return new MyCullVisitor(*this); }
void apply(osg::Geode& geode)
{
// osg::notify(osg::NOTICE)<<"In MyCullVisitor::apply(Geode)"<<std::endl;
CullVisitor::apply(geode);
}
};
class MyDatabasePager : public osgDB::DatabasePager
{
public:
MyDatabasePager()
{
osg::notify(osg::NOTICE)<<"Constructig my MyDatabasePager"<<std::endl;
}
MyDatabasePager(const MyDatabasePager& rhs):
DatabasePager(rhs)
{
osg::notify(osg::NOTICE)<<"Constructig my MyDatabasePager"<<std::endl;
}
~MyDatabasePager()
{
osg::notify(osg::NOTICE)<<"Destructig my MyDatabasePager"<<std::endl;
}
virtual DatabasePager* clone() const { return new MyDatabasePager(*this); }
};
int main(int argc, char** argv)
{
osgUtil::CullVisitor::prototype() = new MyCullVisitor;
osgDB::DatabasePager::prototype() = new MyDatabasePager;
// use an ArgumentParser object to manage the program arguments.
osg::ArgumentParser arguments(&argc,argv);
arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard OpenSceneGraph example which loads and visualises 3d models.");
arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
arguments.getApplicationUsage()->addCommandLineOption("--image <filename>","Load an image and render it on a quad");
arguments.getApplicationUsage()->addCommandLineOption("--dem <filename>","Load an image/DEM and render it on a HeightField");
arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display command line parameters");
arguments.getApplicationUsage()->addCommandLineOption("--help-env","Display environmental variables available");
arguments.getApplicationUsage()->addCommandLineOption("--help-keys","Display keyboard & mouse bindings available");
arguments.getApplicationUsage()->addCommandLineOption("--help-all","Display all command line, env vars and keyboard & mouse bindings.");
arguments.getApplicationUsage()->addCommandLineOption("--SingleThreaded","Select SingleThreaded threading model for viewer.");
arguments.getApplicationUsage()->addCommandLineOption("--CullDrawThreadPerContext","Select CullDrawThreadPerContext threading model for viewer.");
arguments.getApplicationUsage()->addCommandLineOption("--DrawThreadPerContext","Select DrawThreadPerContext threading model for viewer.");
arguments.getApplicationUsage()->addCommandLineOption("--CullThreadPerCameraDrawThreadPerContext","Select CullThreadPerCameraDrawThreadPerContext threading model for viewer.");
// if user request help write it out to cout.
bool helpAll = arguments.read("--help-all");
unsigned int helpType = ((helpAll || arguments.read("-h") || arguments.read("--help"))? osg::ApplicationUsage::COMMAND_LINE_OPTION : 0 ) |
((helpAll || arguments.read("--help-env"))? osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE : 0 ) |
((helpAll || arguments.read("--help-keys"))? osg::ApplicationUsage::KEYBOARD_MOUSE_BINDING : 0 );
if (helpType)
{
arguments.getApplicationUsage()->write(std::cout, helpType);
return 1;
}
osgViewer::Viewer viewer(arguments);
// report any errors if they have occurred when parsing the program arguments.
if (arguments.errors())
{
arguments.writeErrorMessages(std::cout);
return 1;
}
if (arguments.argc()<=1)
{
arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
return 1;
}
bool createBackgroundContextForCompiling = false;
while (arguments.read("--bc")) { createBackgroundContextForCompiling = true; }
bool createBackgroundThreadsForCompiling = false;
while (arguments.read("--bt")) { createBackgroundContextForCompiling = true; createBackgroundThreadsForCompiling = true; }
// set up the camera manipulators.
{
osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
std::string pathfile;
char keyForAnimationPath = '5';
while (arguments.read("-p",pathfile))
{
osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile);
if (apm || !apm->valid())
{
unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
keyswitchManipulator->addMatrixManipulator( keyForAnimationPath, "Path", apm );
keyswitchManipulator->selectMatrixManipulator(num);
++keyForAnimationPath;
}
}
viewer.setCameraManipulator( keyswitchManipulator.get() );
}
// add the state manipulator
viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
// add the thread model handler
viewer.addEventHandler(new osgViewer::ThreadingHandler);
// add the window size toggle handler
viewer.addEventHandler(new osgViewer::WindowSizeHandler);
// add the stats handler
viewer.addEventHandler(new osgViewer::StatsHandler);
// add the help handler
viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));
// add the record camera path handler
viewer.addEventHandler(new osgViewer::RecordCameraPathHandler);
// load the data
osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
if (!loadedModel)
{
std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
return 1;
}
// any option left unread are converted into errors to write out later.
arguments.reportRemainingOptionsAsUnrecognized();
// report any errors if they have occurred when parsing the program arguments.
if (arguments.errors())
{
arguments.writeErrorMessages(std::cout);
return 1;
}
// optimize the scene graph, remove redundant nodes and state etc.
osgUtil::Optimizer optimizer;
optimizer.optimize(loadedModel.get());
viewer.setSceneData( loadedModel.get() );
viewer.realize();
if (createBackgroundContextForCompiling)
{
int numProcessors = OpenThreads::GetNumberOfProcessors();
int processNum = 0;
for(unsigned int i=0; i<= osg::GraphicsContext::getMaxContextID(); ++i)
{
osg::GraphicsContext* gc = osg::GraphicsContext::getOrCreateCompileContext(i);
if (gc && createBackgroundThreadsForCompiling)
{
gc->createGraphicsThread();
gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors);
gc->getGraphicsThread()->startThread();
++processNum;
}
}
}
viewer.run();
}
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org