*
* This application is open source and may be redistributed and/or modified
* freely and without restriction, both in commercial and non commercial 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 <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osgGA/StateSetManipulator>
#include <iostream>
const std::string frameNumberName = "Custom Frame Number";
const std::string frameTimeName = "Custom Frame Time";
const std::string customTimeName = "Custom";
const std::string operation1TimeName = "Operation1";
const std::string operation2TimeName = "Operation2";
const std::string otherThreadTimeName = "Thread";
void initUserStats(osgViewer::StatsHandler* statsHandler)
{
statsHandler->addUserStatsLine("Frame", osg::Vec4(0.7,0.7,0.7,1), osg::Vec4(0.7,0.7,0.7,0.5),
frameNumberName, 1.0, false, false, "", "", 0.0);
statsHandler->addUserStatsLine("MS/frame", osg::Vec4(1,0,1,1), osg::Vec4(1,0,1,0.5),
frameTimeName, 1000.0, true, false, "", "", 0.02);
statsHandler->addUserStatsLine("Custom", osg::Vec4(1,1,1,1), osg::Vec4(1,1,1,0.5),
customTimeName + " time taken", 1000.0, true, false, customTimeName + " begin", customTimeName + " end", 0.016);
statsHandler->addUserStatsLine("Sleep1", osg::Vec4(1,0,0,1), osg::Vec4(1,0,0,0.5),
operation1TimeName + " time taken", 1000.0, true, false, operation1TimeName + " begin", operation1TimeName + " end", 0.016);
statsHandler->addUserStatsLine("Sleep2", osg::Vec4(1,0.5,0.5,1), osg::Vec4(1,0.5,0.5,0.5),
operation2TimeName + " time taken", 1000.0, true, false, operation2TimeName + " begin", operation2TimeName + " end", 0.016);
statsHandler->addUserStatsLine("Thread", osg::Vec4(0,0.5,0,1), osg::Vec4(0,0.5,0,0.5),
otherThreadTimeName + " time taken", 1000.0, true, false, otherThreadTimeName + " begin", otherThreadTimeName + " end", 0.016);
}
void updateUserStats(osgViewer::Viewer& viewer)
{
if (viewer.getViewerStats()->collectStats("update") && viewer.getCamera()->getStats()->collectStats("rendering"))
{
unsigned int framenumber = viewer.getFrameStamp()->getFrameNumber();
double update = 0.0, cull = 0.0;
viewer.getViewerStats()->getAveragedAttribute("Update traversal time taken", update);
viewer.getCamera()->getStats()->getAveragedAttribute("Cull traversal time taken", cull);
double eventBegin = 0.0, updateBegin = 0.0, cullEnd = 0.0, drawEnd = 0.0;
viewer.getViewerStats()->getAttribute(framenumber-2, "Event traversal begin time", eventBegin);
viewer.getViewerStats()->getAttribute(framenumber-2, "Update traversal begin time", updateBegin);
viewer.getCamera()->getStats()->getAttribute(framenumber-2, "Cull traversal end time", cullEnd);
viewer.getCamera()->getStats()->getAttribute(framenumber-2, "Draw traversal end time", drawEnd);
viewer.getViewerStats()->setAttribute(framenumber, frameNumberName, framenumber);
viewer.getViewerStats()->setAttribute(framenumber-1, frameTimeName, drawEnd - eventBegin);
viewer.getViewerStats()->setAttribute(framenumber-1, customTimeName + " time taken", update+cull);
viewer.getViewerStats()->setAttribute(framenumber-1, customTimeName + " begin", updateBegin + (1.0/60.0));
viewer.getViewerStats()->setAttribute(framenumber-1, customTimeName + " end", cullEnd + (1.0/60.0));
}
}
void startTiming(osgViewer::Viewer& viewer, const std::string& name)
{
osg::Timer_t tick = osg::Timer::instance()->tick();
double currentTime = osg::Timer::instance()->delta_s(viewer.getStartTick(), tick);
unsigned int framenumber = viewer.getFrameStamp()->getFrameNumber();
viewer.getViewerStats()->setAttribute(framenumber, name + " begin", currentTime);
}
void endTiming(osgViewer::Viewer& viewer, const std::string& name)
{
osg::Timer_t tick = osg::Timer::instance()->tick();
double currentTime = osg::Timer::instance()->delta_s(viewer.getStartTick(), tick);
unsigned int framenumber = viewer.getFrameStamp()->getFrameNumber();
viewer.getViewerStats()->setAttribute(framenumber, name + " end", currentTime);
double begin = 0.0;
double elapsed = 0.0;
if (viewer.getViewerStats()->getAttribute(framenumber, name + " begin", begin))
{
elapsed = currentTime - begin;
}
viewer.getViewerStats()->setAttribute(framenumber, name + " time taken", elapsed);
}
void doSomethingAndTimeIt(osgViewer::Viewer& viewer, const std::string& name, double milliseconds)
{
startTiming(viewer, name);
osg::Timer_t startTick = osg::Timer::instance()->tick();
while (osg::Timer::instance()->delta_m(startTick, osg::Timer::instance()->tick()) < milliseconds)
{
OpenThreads::Thread::YieldCurrentThread();
}
endTiming(viewer, name);
}
class UselessThread : public OpenThreads::Thread
{
public:
UselessThread(osgViewer::Viewer& viewer, double timeToRun)
: _viewer(viewer)
, _timeToRun(timeToRun)
, _done(false)
, _process(false)
{
}
void run()
{
while (!_done)
{
if (_process)
{
startTiming(_viewer, otherThreadTimeName);
osg::Timer_t startTick = osg::Timer::instance()->tick();
while (osg::Timer::instance()->delta_m(startTick, osg::Timer::instance()->tick()) < _timeToRun)
{
OpenThreads::Thread::YieldCurrentThread();
}
endTiming(_viewer, otherThreadTimeName);
_process = false;
}
else
{
OpenThreads::Thread::microSleep(50);
}
}
}
int cancel()
{
_done = true;
return OpenThreads::Thread::cancel();
}
void process()
{
_process = true;
}
protected:
osgViewer::Viewer& _viewer;
double _timeToRun;
bool _done;
bool _process;
};
int main(int argc, char** argv)
{
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("--login <url> <username> <password>","Provide authentication information for http file access.");
osgViewer::Viewer viewer(arguments);
unsigned int helpType = 0;
if ((helpType = arguments.readHelpType()))
{
arguments.getApplicationUsage()->write(std::cout, helpType);
return 1;
}
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;
}
std::string url, username, password;
while(arguments.read("--login",url, username, password))
{
if (!osgDB::Registry::instance()->getAuthenticationMap())
{
osgDB::Registry::instance()->setAuthenticationMap(new osgDB::AuthenticationMap);
osgDB::Registry::instance()->getAuthenticationMap()->addAuthenticationDetails(
url,
new osgDB::AuthenticationDetails(username, password)
);
}
}
viewer.setCameraManipulator(new osgGA::TrackballManipulator);
viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
viewer.addEventHandler(new osgViewer::ThreadingHandler);
viewer.addEventHandler(new osgViewer::WindowSizeHandler);
osgViewer::StatsHandler* statsHandler = new osgViewer::StatsHandler;
viewer.addEventHandler(statsHandler);
initUserStats(statsHandler);
viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));
osg::ref_ptr<osg::Node> loadedModel = osgDB::readRefNodeFiles(arguments);
if (!loadedModel)
{
std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
return 1;
}
arguments.reportRemainingOptionsAsUnrecognized();
if (arguments.errors())
{
arguments.writeErrorMessages(std::cout);
return 1;
}
osgUtil::Optimizer optimizer;
optimizer.optimize(loadedModel);
viewer.setSceneData(loadedModel);
viewer.realize();
UselessThread thread(viewer, 6.0);
thread.start();
while (!viewer.done())
{
viewer.advance();
updateUserStats(viewer);
doSomethingAndTimeIt(viewer, operation1TimeName, 2.0);
thread.process();
viewer.eventTraversal();
viewer.updateTraversal();
doSomethingAndTimeIt(viewer, operation2TimeName, 3.0);
viewer.renderingTraversals();
}
thread.cancel();
thread.join();
}