OpenSceneGraph Forum Forum Index OpenSceneGraph Forum
Official forum which mirrors the existent OSG mailing lists. Messages posted here are forwarded to the mailing list and vice versa.
 
   FAQFAQ    SearchSearch    MemberlistMemberlist    RulesRules    UsergroupsUsergroups    RegisterRegister 
 Mail2Forum SettingsMail2Forum Settings  ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 
   AlbumAlbum  OpenSceneGraph IRC ChatOpenSceneGraph IRC Chat   SmartFeedSmartFeed 

Statshandler layout fixes


 
Post new topic   Reply to topic    OpenSceneGraph Forum Forum Index -> Submission
View previous topic :: View next topic  
Author Message
Paul Melis
Guest





PostPosted: Tue Jan 27, 2009 8:22 pm    Post subject:
Statshandler layout fixes
Reply with quote

Hi Robert,

Here is an updated osgViewer::StatsHandler. It has the following changes:
- The text and dark background rectangles are now correctly placed, and
slightly resized here and there.
- All counters (vertices, etc) now use a fixed formatting with 0 digits
precision, to prevent the text from being shown in scientific notation
when the number get large (e.g. 6.34344e+6). I tested with a scene
containing roughly 4 million vertices, to make sure its stats would
display correctly.

I also made slight changes to osgcompositeviewer (attached) to aid in
testing the stats display, specifically displaying of camera and view
names. Unfortunately, I get a segfault when trying to switch on the View
statistics (i.e. when pressing 's' for the 4th time) with
"osgcompositeviewer cow.osg". Here's the stack trace, looks like a null
pointer somewhere. I looked at the problem briefly but decided I don't
know enough to fix it...

#0 osg::Stats::setAttribute (this=0x0, frameNumber=1556,
attributeName=@0xbff9f7fc, value=1) at
/home/melis/c/osg/svn/trunk/include/osg/Stats:41
#1 0xb7aa6aa1 in osgViewer::ViewerBase::renderingTraversals
(this=0xbff9f9d8) at
/home/melis/c/osg/svn/trunk/src/osgViewer/ViewerBase.cpp:670
#2 0xb7aa5083 in osgViewer::ViewerBase::frame (this=0xbff9f9d8,
simulationTime=1.7976931348623157e+308) at
/home/melis/c/osg/svn/trunk/src/osgViewer/ViewerBase.cpp:609
#3 0xb7aa51c1 in osgViewer::ViewerBase::run (this=0xbff9f9d8) at
/home/melis/c/osg/svn/trunk/src/osgViewer/ViewerBase.cpp:581
#4 0xb7a52fd0 in osgViewer::CompositeViewer::run (this=0xbff9f9d8) at
/home/melis/c/osg/svn/trunk/src/osgViewer/CompositeViewer.cpp:232
#5 0x0804c476 in main (argc=Cannot access memory at address 0x0
) at
/home/melis/c/osg/svn/trunk/examples/osgcompositeviewer/osgcompositeviewer.cpp:301

Regards,
Paul

/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library 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. See the
* OpenSceneGraph Public License for more details.
*/

#include <sstream>
#include <iomanip>
#include <stdio.h>

#include <osg/io_utils>

#include <osg/MatrixTransform>

#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/Renderer>

#include <osg/PolygonMode>
#include <osg/Geometry>

namespace osgViewer
{


StatsHandler::StatsHandler():
_keyEventTogglesOnScreenStats('s'),
_keyEventPrintsOutStats('S'),
_statsType(NO_STATS),
_initialized(false),
_threadingModel(ViewerBase::SingleThreaded),
_frameRateChildNum(0),
_viewerChildNum(0),
_cameraSceneChildNum(0),
_viewerSceneChildNum(0),
_numBlocks(Cool,
_blockMultiplier(10000.0)
{
_camera = new osg::Camera;
_camera->setRenderer(new Renderer(_camera.get()));
_camera->setProjectionResizePolicy(osg::Camera::FIXED);
}

bool StatsHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{

osgViewer::View* myview = dynamic_cast<osgViewer::View*>(&aa);
if (!myview) return false;

osgViewer::ViewerBase* viewer = myview->getViewerBase();
if (viewer && _threadingModelText.valid() && viewer->getThreadingModel()!=_threadingModel)
{
_threadingModel = viewer->getThreadingModel();
updateThreadingModelText();
}


if (ea.getHandled()) return false;

switch(ea.getEventType())
{
case(osgGA::GUIEventAdapter::KEYDOWN):
{
if (ea.getKey()==_keyEventTogglesOnScreenStats)
{
if (viewer->getViewerStats())
{
if (!_initialized)
{
setUpHUDCamera(viewer);
setUpScene(viewer);
}

++_statsType;

if (_statsType==LAST) _statsType = NO_STATS;

osgViewer::ViewerBase::Cameras cameras;
viewer->getCameras(cameras);

switch(_statsType)
{
case(NO_STATS):
{
viewer->getViewerStats()->collectStats("frame_rate",false);
viewer->getViewerStats()->collectStats("event",false);
viewer->getViewerStats()->collectStats("update",false);

for(osgViewer::ViewerBase::Cameras::iterator itr = cameras.begin();
itr != cameras.end();
++itr)
{
osg::Stats* stats = (*itr)->getStats();
if (stats)
{
stats->collectStats("rendering",false);
stats->collectStats("gpu",false);
stats->collectStats("scene",false);
}
}

viewer->getViewerStats()->collectStats("scene",false);

_camera->setNodeMask(0x0);
_switch->setAllChildrenOff();
break;
}
case(FRAME_RATE):
{
viewer->getViewerStats()->collectStats("frame_rate",true);

_camera->setNodeMask(0xffffffff);
_switch->setValue(_frameRateChildNum, true);
break;
}
case(VIEWER_STATS):
{
ViewerBase::Scenes scenes;
viewer->getScenes(scenes);
for(ViewerBase::Scenes::iterator itr = scenes.begin();
itr != scenes.end();
++itr)
{
Scene* scene = *itr;
osgDB::DatabasePager* dp = scene->getDatabasePager();
if (dp && dp->isRunning())
{
dp->resetStats();
}
}

viewer->getViewerStats()->collectStats("event",true);
viewer->getViewerStats()->collectStats("update",true);

for(osgViewer::ViewerBase::Cameras::iterator itr = cameras.begin();
itr != cameras.end();
++itr)
{
if ((*itr)->getStats()) (*itr)->getStats()->collectStats("rendering",true);
if ((*itr)->getStats()) (*itr)->getStats()->collectStats("gpu",true);
}

_camera->setNodeMask(0xffffffff);
_switch->setValue(_viewerChildNum, true);
break;
}
case(CAMERA_SCENE_STATS):
{
_camera->setNodeMask(0xffffffff);
_switch->setValue(_cameraSceneChildNum, true);

for(osgViewer::ViewerBase::Cameras::iterator itr = cameras.begin();
itr != cameras.end();
++itr)
{
osg::Stats* stats = (*itr)->getStats();
if (stats)
{
stats->collectStats("scene",true);
}
}

break;
}
case(VIEWER_SCENE_STATS):
{
_camera->setNodeMask(0xffffffff);
_switch->setValue(_viewerSceneChildNum, true);

viewer->getViewerStats()->collectStats("scene",true);

break;
}
default:
break;
}


}
return true;
}
if (ea.getKey()==_keyEventPrintsOutStats)
{
if (viewer->getViewerStats())
{
osg::notify(osg::NOTICE)<<std::endl<<"Stats report:"<<std::endl;
typedef std::vector<osg::Stats*> StatsList;
StatsList statsList;
statsList.push_back(viewer->getViewerStats());

osgViewer::ViewerBase::Contexts contexts;
viewer->getContexts(contexts);
for(osgViewer::ViewerBase::Contexts::iterator gcitr = contexts.begin();
gcitr != contexts.end();
++gcitr)
{
osg::GraphicsContext::Cameras& cameras = (*gcitr)->getCameras();
for(osg::GraphicsContext::Cameras::iterator itr = cameras.begin();
itr != cameras.end();
++itr)
{
if ((*itr)->getStats())
{
statsList.push_back((*itr)->getStats());
}
}
}

for(int i = viewer->getViewerStats()->getEarliestFrameNumber(); i<= viewer->getViewerStats()->getLatestFrameNumber()-1; ++i)
{
for(StatsList::iterator itr = statsList.begin();
itr != statsList.end();
++itr)
{
if (itr==statsList.begin()) (*itr)->report(osg::notify(osg::NOTICE), i);
else (*itr)->report(osg::notify(osg::NOTICE), i, " ");
}
osg::notify(osg::NOTICE)<<std::endl;
}

}
return true;
}
}
default: break;
}

return false;

}

void StatsHandler::updateThreadingModelText()
{
switch(_threadingModel)
{
case(osgViewer::Viewer::SingleThreaded): _threadingModelText->setText("ThreadingModel: SingleThreaded"); break;
case(osgViewer::Viewer::CullDrawThreadPerContext): _threadingModelText->setText("ThreadingModel: CullDrawThreadPerContext"); break;
case(osgViewer::Viewer::DrawThreadPerContext): _threadingModelText->setText("ThreadingModel: DrawThreadPerContext"); break;
case(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext): _threadingModelText->setText("ThreadingModel: CullThreadPerCameraDrawThreadPerContext"); break;
case(osgViewer::Viewer::AutomaticSelection): _threadingModelText->setText("ThreadingModel: AutomaticSelection"); break;
default:
_threadingModelText->setText("ThreadingModel: unknown"); break;
}
}

void StatsHandler::reset()
{
_initialized = false;
_camera->setGraphicsContext(0);
_camera->removeChildren( 0, _camera->getNumChildren() );
}

void StatsHandler::setUpHUDCamera(osgViewer::ViewerBase* viewer)
{
osgViewer::GraphicsWindow* window = dynamic_cast<osgViewer::GraphicsWindow*>(_camera->getGraphicsContext());

if (!window)
{
osgViewer::Viewer::Windows windows;
viewer->getWindows(windows);

if (windows.empty()) return;

window = windows.front();
}

_camera->setGraphicsContext(window);

_camera->setViewport(0, 0, window->getTraits()->width, window->getTraits()->height);
_camera->setRenderOrder(osg::Camera::POST_RENDER, 10);

_camera->setProjectionMatrix(osg::Matrix::ortho2D(0,1280,0,1024));
_camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
_camera->setViewMatrix(osg::Matrix::identity());

// only clear the depth buffer
_camera->setClearMask(0);

_camera->setRenderer(new Renderer(_camera.get()));

_initialized = true;
}

// Drawcallback to draw averaged attribute
struct AveragedValueTextDrawCallback : public virtual osg::Drawable::DrawCallback
{
AveragedValueTextDrawCallback(osg::Stats* stats, const std::string& name, int frameDelta, bool averageInInverseSpace, double multiplier):
_stats(stats),
_attributeName(name),
_frameDelta(frameDelta),
_averageInInverseSpace(averageInInverseSpace),
_multiplier(multiplier),
_tickLastUpdated(0)
{
}

/** do customized draw code.*/
virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
{
osgText::Text* text = (osgText::Text*)drawable;

osg::Timer_t tick = osg::Timer::instance()->tick();
double delta = osg::Timer::instance()->delta_m(_tickLastUpdated, tick);

if (delta>50) // update every 50ms
{
_tickLastUpdated = tick;
double value;
if (_stats->getAveragedAttribute( _attributeName, value, _averageInInverseSpace))
{
sprintf(_tmpText,"%4.2f",value * _multiplier);
text->setText(_tmpText);
}
else
{
text->setText("");
}
}
text->drawImplementation(renderInfo);
}

osg::ref_ptr<osg::Stats> _stats;
std::string _attributeName;
int _frameDelta;
bool _averageInInverseSpace;
double _multiplier;
mutable char _tmpText[128];
mutable osg::Timer_t _tickLastUpdated;
};

struct CameraSceneStatsTextDrawCallback : public virtual osg::Drawable::DrawCallback
{
CameraSceneStatsTextDrawCallback(osg::Camera* camera, int cameraNumber):
_camera(camera),
_tickLastUpdated(0),
_cameraNumber(cameraNumber)
{
}

/** do customized draw code.*/
virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
{
if (!_camera) return;

osgText::Text* text = (osgText::Text*)drawable;

osg::Timer_t tick = osg::Timer::instance()->tick();
double delta = osg::Timer::instance()->delta_m(_tickLastUpdated, tick);

if (delta > 100) // update every 100ms
{
_tickLastUpdated = tick;
std::ostringstream viewStr;
viewStr.clear();

osg::Stats* stats = _camera->getStats();
osgViewer::Renderer* renderer = dynamic_cast<osgViewer::Renderer*>(_camera->getRenderer());

if (stats && renderer)
{
viewStr.setf(std::ios::left, std::ios::adjustfield);
viewStr.width(14);
// Used fixed formatting, as scientific will switch to "...e+.." notation for
// large numbers of vertices/drawables/etc.
viewStr.setf(std::ios::fixed);
viewStr.precision(0);

viewStr << std::setw(1) << "#" << _cameraNumber << std::endl;

// Camera name
if (!_camera->getName().empty())
viewStr << _camera->getName();
viewStr << std::endl;

int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();
if (!(renderer->getGraphicsThreadDoesCull()))
{
--frameNumber;
}

#define STATS_ATTRIBUTE(str) \
if (stats->getAttribute(frameNumber, str, value)) \
viewStr << std::setw(Cool << value << std::endl; \
else \
viewStr << std::setw(Cool << "." << std::endl; \

double value = 0.0;

STATS_ATTRIBUTE("Visible vertex count")
STATS_ATTRIBUTE("Visible number of drawables")
STATS_ATTRIBUTE("Visible number of lights")
STATS_ATTRIBUTE("Visible number of render bins")
STATS_ATTRIBUTE("Visible depth")
STATS_ATTRIBUTE("Visible number of materials")
STATS_ATTRIBUTE("Visible number of impostors")

STATS_ATTRIBUTE("Visible number of GL_POINTS")
STATS_ATTRIBUTE("Visible number of GL_LINES")
STATS_ATTRIBUTE("Visible number of GL_LINE_STRIP")
STATS_ATTRIBUTE("Visible number of GL_LINE_LOOP")
STATS_ATTRIBUTE("Visible number of GL_TRIANGLES")
STATS_ATTRIBUTE("Visible number of GL_TRIANGLE_STRIP")
STATS_ATTRIBUTE("Visible number of GL_TRIANGLE_FAN")
STATS_ATTRIBUTE("Visible number of GL_QUADS")
STATS_ATTRIBUTE("Visible number of GL_QUAD_STRIP")
STATS_ATTRIBUTE("Visible number of GL_POLYGON")

text->setText(viewStr.str());
}
}
text->drawImplementation(renderInfo);
}

osg::observer_ptr<osg::Camera> _camera;
mutable osg::Timer_t _tickLastUpdated;
int _cameraNumber;
};


struct ViewSceneStatsTextDrawCallback : public virtual osg::Drawable::DrawCallback
{
ViewSceneStatsTextDrawCallback(osgViewer::View* view, int viewNumber):
_view(view),
_tickLastUpdated(0),
_viewNumber(viewNumber)
{
}

/** do customized draw code.*/
virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
{
if (!_view) return;

osgText::Text* text = (osgText::Text*)drawable;

osg::Timer_t tick = osg::Timer::instance()->tick();
double delta = osg::Timer::instance()->delta_m(_tickLastUpdated, tick);

if (delta > 200) // update every 100ms
{
_tickLastUpdated = tick;
osg::Stats* stats = _view->getStats();
if (stats)
{
std::ostringstream viewStr;
viewStr.clear();
viewStr.setf(std::ios::left, std::ios::adjustfield);
viewStr.width(20);
viewStr.setf(std::ios::fixed);
viewStr.precision(0);

viewStr << std::setw(1) << "#" << _viewNumber;

// View name
if (!_view->getName().empty())
viewStr << ": " << _view->getName();
viewStr << std::endl;

int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();
// if (!(renderer->getGraphicsThreadDoesCull()))
{
--frameNumber;
}

#define STATS_ATTRIBUTE_PAIR(str1, str2) \
if (stats->getAttribute(frameNumber, str1, value)) \
viewStr << std::setw(10) << value; \
else \
viewStr << std::setw(10) << "."; \
if (stats->getAttribute(frameNumber, str2, value)) \
viewStr << std::setw(10) << value << std::endl; \
else \
viewStr << std::setw(10) << "." << std::endl; \

double value = 0.0;

// header
viewStr << std::setw(10) << "Unique" << std::setw(10) << "Instanced" << std::endl;

STATS_ATTRIBUTE_PAIR("Number of unique StateSet","Number of instanced Stateset")
STATS_ATTRIBUTE_PAIR("Number of unique Group","Number of instanced Group")
STATS_ATTRIBUTE_PAIR("Number of unique Transform","Number of instanced Transform")
STATS_ATTRIBUTE_PAIR("Number of unique LOD","Number of instanced LOD")
STATS_ATTRIBUTE_PAIR("Number of unique Switch","Number of instanced Switch")
STATS_ATTRIBUTE_PAIR("Number of unique Geode","Number of instanced Geode")
STATS_ATTRIBUTE_PAIR("Number of unique Drawable","Number of instanced Drawable")
STATS_ATTRIBUTE_PAIR("Number of unique Geometry","Number of instanced Geometry")
STATS_ATTRIBUTE_PAIR("Number of unique Vertices","Number of instanced Vertices")
STATS_ATTRIBUTE_PAIR("Number of unique Primitives","Number of instanced Primitives")


text->setText(viewStr.str());
}
else
{
osg::notify(osg::WARN)<<std::endl<<"No valid view to collect scene stats from"<<std::endl;

text->setText("");
}
}
text->drawImplementation(renderInfo);
}

osg::observer_ptr<osgViewer::View> _view;
mutable osg::Timer_t _tickLastUpdated;
int _viewNumber;
};

struct BlockDrawCallback : public virtual osg::Drawable::DrawCallback
{
BlockDrawCallback(StatsHandler* statsHandler, float xPos, osg::Stats* viewerStats, osg::Stats* stats, const std::string& beginName, const std::string& endName, int frameDelta, int numFrames):
_statsHandler(statsHandler),
_xPos(xPos),
_viewerStats(viewerStats),
_stats(stats),
_beginName(beginName),
_endName(endName),
_frameDelta(frameDelta),
_numFrames(numFrames) {}

/** do customized draw code.*/
virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
{
osg::Geometry* geom = (osg::Geometry*)drawable;
osg::Vec3Array* vertices = (osg::Vec3Array*)geom->getVertexArray();

int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();

int startFrame = frameNumber + _frameDelta - _numFrames + 1;
int endFrame = frameNumber + _frameDelta;
double referenceTime;
if (!_viewerStats->getAttribute( startFrame, "Reference time", referenceTime))
{
return;
}

unsigned int vi = 0;
double beginValue, endValue;
for(int i = startFrame; i <= endFrame; ++i)
{
if (_stats->getAttribute( i, _beginName, beginValue) &&
_stats->getAttribute( i, _endName, endValue) )
{
(*vertices)[vi++].x() = _xPos + (beginValue - referenceTime) * _statsHandler->getBlockMultiplier();
(*vertices)[vi++].x() = _xPos + (beginValue - referenceTime) * _statsHandler->getBlockMultiplier();
(*vertices)[vi++].x() = _xPos + (endValue - referenceTime) * _statsHandler->getBlockMultiplier();
(*vertices)[vi++].x() = _xPos + (endValue - referenceTime) * _statsHandler->getBlockMultiplier();
}
}

drawable->drawImplementation(renderInfo);
}

StatsHandler* _statsHandler;
float _xPos;
osg::ref_ptr<osg::Stats> _viewerStats;
osg::ref_ptr<osg::Stats> _stats;
std::string _beginName;
std::string _endName;
int _frameDelta;
int _numFrames;
};

osg::Geometry* StatsHandler::createBackgroundRectangle(const osg::Vec3& pos, const float width, const float height, osg::Vec4& color)
{
osg::StateSet *ss = new osg::StateSet;

osg::Geometry* geometry = new osg::Geometry;

geometry->setUseDisplayList(false);
geometry->setStateSet(ss);

osg::Vec3Array* vertices = new osg::Vec3Array;
geometry->setVertexArray(vertices);

vertices->push_back(osg::Vec3(pos.x(), pos.y(), 0));
vertices->push_back(osg::Vec3(pos.x(), pos.y()-height,0));
vertices->push_back(osg::Vec3(pos.x()+width, pos.y()-height,0));
vertices->push_back(osg::Vec3(pos.x()+width, pos.y(),0));

osg::Vec4Array* colors = new osg::Vec4Array;
colors->push_back(color);
geometry->setColorArray(colors);
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);

osg::DrawElementsUInt *base = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS,0);
base->push_back(0);
base->push_back(1);
base->push_back(2);
base->push_back(3);

geometry->addPrimitiveSet(base);

return geometry;
}


struct StatsGraph : public osg::MatrixTransform
{
StatsGraph(osg::Vec3 pos, float width, float height)
: _pos(pos), _width(width), _height(height),
_statsGraphGeode(new osg::Geode)
{
_pos -= osg::Vec3(0, height, 0.1);
this->setMatrix(osg::Matrix::translate(_pos));
this->addChild(_statsGraphGeode.get());
}

void addStatGraph(osg::Stats* viewerStats, osg::Stats* stats, const osg::Vec4& color, float max, const std::string& nameBegin, const std::string& nameEnd = "")
{
_statsGraphGeode->addDrawable(new Graph(_width, _height, viewerStats, stats, color, max, nameBegin, nameEnd));
}

osg::Vec3 _pos;
float _width;
float _height;

osg::ref_ptr<osg::Geode> _statsGraphGeode;

protected:
struct Graph : public osg::Geometry
{
Graph(float width, float height, osg::Stats* viewerStats, osg::Stats* stats,
const osg::Vec4& color, float max, const std::string& nameBegin, const std::string& nameEnd = "")
{
this->setUseDisplayList(false);

this->setVertexArray(new osg::Vec3Array);

osg::Vec4Array* colors = new osg::Vec4Array;
colors->push_back(color);
this->setColorArray(colors);
this->setColorBinding(osg::Geometry::BIND_OVERALL);

this->setDrawCallback(new GraphUpdateCallback(width, height, viewerStats, stats, max, nameBegin, nameEnd));
}
};

struct GraphUpdateCallback : public osg::Drawable::DrawCallback
{
GraphUpdateCallback(float width, float height, osg::Stats* viewerStats, osg::Stats* stats,
float max, const std::string& nameBegin, const std::string& nameEnd = "")
: _width((unsigned int)width), _height((unsigned int)height), _curX(0),
_viewerStats(viewerStats), _stats(stats), _max(max), _nameBegin(nameBegin), _nameEnd(nameEnd)
{
}

virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
{
osg::Geometry* geometry = const_cast<osg::Geometry*>(drawable->asGeometry());
if (!geometry) return;
osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
if (!vertices) return;

int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();

// Get stats
double value;
if (_nameEnd.empty())
{
if (!_stats->getAveragedAttribute( _nameBegin, value, true ))
{
value = 0.0;
}
}
else
{
double beginValue, endValue;
if (_stats->getAttribute( frameNumber, _nameBegin, beginValue) &&
_stats->getAttribute( frameNumber, _nameEnd, endValue) )
{
value = endValue - beginValue;
}
else
{
value = 0.0;
}
}

// Add new vertex for this frame.
value = osg::clampTo(value, 0.0, double(_max));
vertices->push_back(osg::Vec3(float(_curX), float(_height) / _max * value, 0));

// One vertex per pixel in X.
if (vertices->size() > _width)
{
unsigned int excedent = vertices->size() - _width;
vertices->erase(vertices->begin(), vertices->begin() + excedent);

// Make the graph scroll when there is enough data.
// Note: We check the frame number so that even if we have
// many graphs, the transform is translated only once per
// frame.
static const float increment = -1.0;
if (GraphUpdateCallback::_frameNumber != frameNumber)
{
// We know the exact layout of this part of the scene
// graph, so this is OK...
osg::MatrixTransform* transform =
geometry->getParent(0)->getParent(0)->asTransform()->asMatrixTransform();
if (transform)
{
transform->setMatrix(transform->getMatrix() * osg::Matrix::translate(osg::Vec3(increment, 0, 0)));
}
}
}
else
{
// Create primitive set if none exists.
if (geometry->getNumPrimitiveSets() == 0)
geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, 0, 0));

// Update primitive set.
osg::DrawArrays* drawArrays = dynamic_cast<osg::DrawArrays*>(geometry->getPrimitiveSet(0));
if (!drawArrays) return;
drawArrays->setFirst(0);
drawArrays->setCount(vertices->size());
}

_curX++;
GraphUpdateCallback::_frameNumber = frameNumber;

geometry->dirtyBound();

drawable->drawImplementation(renderInfo);
}

const unsigned int _width;
const unsigned int _height;
mutable unsigned int _curX;
osg::Stats* _viewerStats;
osg::Stats* _stats;
const float _max;
const std::string _nameBegin;
const std::string _nameEnd;
static int _frameNumber;
};
};

int StatsGraph::GraphUpdateCallback::_frameNumber = 0;


osg::Geometry* StatsHandler::createGeometry(const osg::Vec3& pos, float height, const osg::Vec4& colour, unsigned int numBlocks)
{
osg::Geometry* geometry = new osg::Geometry;

geometry->setUseDisplayList(false);

osg::Vec3Array* vertices = new osg::Vec3Array;
geometry->setVertexArray(vertices);
vertices->reserve(numBlocks*4);

for(unsigned int i=0; i<numBlocks; ++i)
{
vertices->push_back(pos+osg::Vec3(i*20, height, 0.0));
vertices->push_back(pos+osg::Vec3(i*20, 0.0, 0.0));
vertices->push_back(pos+osg::Vec3(i*20+10.0, 0.0, 0.0));
vertices->push_back(pos+osg::Vec3(i*20+10.0, height, 0.0));
}

osg::Vec4Array* colours = new osg::Vec4Array;
colours->push_back(colour);
geometry->setColorArray(colours);
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);

geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, numBlocks*4));

return geometry;
}


struct FrameMarkerDrawCallback : public virtual osg::Drawable::DrawCallback
{
FrameMarkerDrawCallback(StatsHandler* statsHandler, float xPos, osg::Stats* viewerStats, int frameDelta, int numFrames):
_statsHandler(statsHandler),
_xPos(xPos),
_viewerStats(viewerStats),
_frameDelta(frameDelta),
_numFrames(numFrames) {}

/** do customized draw code.*/
virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
{
osg::Geometry* geom = (osg::Geometry*)drawable;
osg::Vec3Array* vertices = (osg::Vec3Array*)geom->getVertexArray();

int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();

int startFrame = frameNumber + _frameDelta - _numFrames + 1;
int endFrame = frameNumber + _frameDelta;
double referenceTime;
if (!_viewerStats->getAttribute( startFrame, "Reference time", referenceTime))
{
return;
}

unsigned int vi = 0;
double currentReferenceTime;
for(int i = startFrame; i <= endFrame; ++i)
{
if (_viewerStats->getAttribute( i, "Reference time", currentReferenceTime))
{
(*vertices)[vi++].x() = _xPos + (currentReferenceTime - referenceTime) * _statsHandler->getBlockMultiplier();
(*vertices)[vi++].x() = _xPos + (currentReferenceTime - referenceTime) * _statsHandler->getBlockMultiplier();
}
}

drawable->drawImplementation(renderInfo);
}

StatsHandler* _statsHandler;
float _xPos;
osg::ref_ptr<osg::Stats> _viewerStats;
std::string _endName;
int _frameDelta;
int _numFrames;
};

struct PagerCallback : public virtual osg::NodeCallback
{

PagerCallback( osgDB::DatabasePager* dp,
osgText::Text* minValue,
osgText::Text* maxValue,
osgText::Text* averageValue,
osgText::Text* filerequestlist,
osgText::Text* compilelist,
double multiplier):
_dp(dp),
_minValue(minValue),
_maxValue(maxValue),
_averageValue(averageValue),
_filerequestlist(filerequestlist),
_compilelist(compilelist),
_multiplier(multiplier)
{
}

virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (_dp.valid())
{
double value = _dp->getAverageTimeToMergeTiles();
if (value>= 0.0 && value <= 1000)
{
sprintf(_tmpText,"%4.0f",value * _multiplier);
_averageValue->setText(_tmpText);
}
else
{
_averageValue->setText("");
}

value = _dp->getMinimumTimeToMergeTile();
if (value>= 0.0 && value <= 1000)
{
sprintf(_tmpText,"%4.0f",value * _multiplier);
_minValue->setText(_tmpText);
}
else
{
_minValue->setText("");
}

value = _dp->getMaximumTimeToMergeTile();
if (value>= 0.0 && value <= 1000)
{
sprintf(_tmpText,"%4.0f",value * _multiplier);
_maxValue->setText(_tmpText);
}
else
{
_maxValue->setText("");
}

sprintf(_tmpText,"%4d", _dp->getFileRequestListSize());
_filerequestlist->setText(_tmpText);

sprintf(_tmpText,"%4d", _dp->getDataToCompileListSize());
_compilelist->setText(_tmpText);
}

traverse(node,nv);
}

osg::observer_ptr<osgDB::DatabasePager> _dp;

osg::ref_ptr<osgText::Text> _minValue;
osg::ref_ptr<osgText::Text> _maxValue;
osg::ref_ptr<osgText::Text> _averageValue;
osg::ref_ptr<osgText::Text> _filerequestlist;
osg::ref_ptr<osgText::Text> _compilelist;
double _multiplier;
char _tmpText[128];
osg::Timer_t _tickLastUpdated;
};


osg::Geometry* StatsHandler::createFrameMarkers(const osg::Vec3& pos, float height, const osg::Vec4& colour, unsigned int numBlocks)
{
osg::Geometry* geometry = new osg::Geometry;

geometry->setUseDisplayList(false);

osg::Vec3Array* vertices = new osg::Vec3Array;
geometry->setVertexArray(vertices);
vertices->reserve(numBlocks*2);

for(unsigned int i=0; i<numBlocks; ++i)
{
vertices->push_back(pos+osg::Vec3(double(i)*_blockMultiplier*0.01, height, 0.0));
vertices->push_back(pos+osg::Vec3(double(i)*_blockMultiplier*0.01, 0.0, 0.0));
}

osg::Vec4Array* colours = new osg::Vec4Array;
colours->push_back(colour);
geometry->setColorArray(colours);
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);

geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, numBlocks*2));

return geometry;
}

osg::Geometry* StatsHandler::createTick(const osg::Vec3& pos, float height, const osg::Vec4& colour, unsigned int numTicks)
{
osg::Geometry* geometry = new osg::Geometry;

geometry->setUseDisplayList(false);

osg::Vec3Array* vertices = new osg::Vec3Array;
geometry->setVertexArray(vertices);
vertices->reserve(numTicks*2);

for(unsigned int i=0; i<numTicks; ++i)
{
float tickHeight = (i%10) ? height : height * 2.0;
vertices->push_back(pos+osg::Vec3(double(i)*_blockMultiplier*0.001, tickHeight , 0.0));
vertices->push_back(pos+osg::Vec3(double(i)*_blockMultiplier*0.001, 0.0, 0.0));
}

osg::Vec4Array* colours = new osg::Vec4Array;
colours->push_back(colour);
geometry->setColorArray(colours);
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);

geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, numTicks*2));

return geometry;
}

void StatsHandler::setUpScene(osgViewer::ViewerBase* viewer)
{
_switch = new osg::Switch;

_camera->addChild(_switch.get());

osg::StateSet* stateset = _switch->getOrCreateStateSet();
stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
stateset->setMode(GL_BLEND,osg::StateAttribute:ShockedN);
stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
stateset->setAttribute(new osg::PolygonMode(), osg::StateAttribute::PROTECTED);

std::string font("fonts/arial.ttf");


// collect all the relevant cameras
ViewerBase::Cameras validCameras;
viewer->getCameras(validCameras);

ViewerBase::Cameras cameras;
for(ViewerBase::Cameras::iterator itr = validCameras.begin();
itr != validCameras.end();
++itr)
{
if ((*itr)->getStats())
{
cameras.push_back(*itr);
}
}

// check for query time support
unsigned int numCamrasWithTimerQuerySupport = 0;
for(ViewerBase::Cameras::iterator citr = cameras.begin();
citr != cameras.end();
++citr)
{
if ((*citr)->getGraphicsContext())
{
unsigned int contextID = (*citr)->getGraphicsContext()->getState()->getContextID();
const osg::Drawable::Extensions* extensions = osg::Drawable::getExtensions(contextID, false);
if (extensions && extensions->isTimerQuerySupported())
{
++numCamrasWithTimerQuerySupport;
}
}
}

bool acquireGPUStats = numCamrasWithTimerQuerySupport==cameras.size();

float leftPos = 10.0f;
float startBlocks = 150.0f;
float characterSize = 20.0f;

osg::Vec3 pos(leftPos,1000.0f,0.0f);

osg::Vec4 colorFR(1.0f,1.0f,1.0f,1.0f);
osg::Vec4 colorFRAlpha(1.0f,1.0f,1.0f,0.5f);
osg::Vec4 colorUpdate( 0.0f,1.0f,0.0f,1.0f);
osg::Vec4 colorUpdateAlpha( 0.0f,1.0f,0.0f,0.5f);
osg::Vec4 colorEvent(0.0f, 1.0f, 0.5f, 1.0f);
osg::Vec4 colorEventAlpha(0.0f, 1.0f, 0.5f, 0.5f);
osg::Vec4 colorCull( 0.0f,1.0f,1.0f,1.0f);
osg::Vec4 colorCullAlpha( 0.0f,1.0f,1.0f,0.5f);
osg::Vec4 colorDraw( 1.0f,1.0f,0.0f,1.0f);
osg::Vec4 colorDrawAlpha( 1.0f,1.0f,0.0f,0.5f);
osg::Vec4 colorGPU( 1.0f,0.5f,0.0f,1.0f);
osg::Vec4 colorGPUAlpha( 1.0f,0.5f,0.0f,0.5f);

osg::Vec4 colorDP( 1.0f,1.0f,0.5f,1.0f);


// frame rate stats
{
osg::Geode* geode = new osg::Geode();
_frameRateChildNum = _switch->getNumChildren();
_switch->addChild(geode, false);

osg::ref_ptr<osgText::Text> frameRateLabel = new osgText::Text;
geode->addDrawable( frameRateLabel.get() );

frameRateLabel->setColor(colorFR);
frameRateLabel->setFont(font);
frameRateLabel->setCharacterSize(characterSize);
frameRateLabel->setPosition(pos);
frameRateLabel->setText("Frame Rate: ");

pos.x() = frameRateLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> frameRateValue = new osgText::Text;
geode->addDrawable( frameRateValue.get() );

frameRateValue->setColor(colorFR);
frameRateValue->setFont(font);
frameRateValue->setCharacterSize(characterSize);
frameRateValue->setPosition(pos);
frameRateValue->setText("0.0");

frameRateValue->setDrawCallback(new AveragedValueTextDrawCallback(viewer->getViewerStats(),"Frame rate",-1, true, 1.0));

pos.y() -= characterSize*1.5f;

}

osg::Vec4 backgroundColor(0.0, 0.0, 0.0f, 0.3);
osg::Vec4 staticTextColor(1.0, 1.0, 0.0f, 1.0);
osg::Vec4 dynamicTextColor(1.0, 1.0, 1.0f, 1.0);
float backgroundMargin = 5;
float backgroundSpacing = 3;


// viewer stats
{
osg::Group* group = new osg::Group;
_viewerChildNum = _switch->getNumChildren();
_switch->addChild(group, false);

osg::Geode* geode = new osg::Geode();
group->addChild(geode);


{
pos.x() = leftPos;

_threadingModelText = new osgText::Text;
geode->addDrawable( _threadingModelText.get() );

_threadingModelText->setColor(colorFR);
_threadingModelText->setFont(font);
_threadingModelText->setCharacterSize(characterSize);
_threadingModelText->setPosition(pos);

updateThreadingModelText();

pos.y() -= characterSize*1.5f;
}

float topOfViewerStats = pos.y() + characterSize;

geode->addDrawable(createBackgroundRectangle( pos + osg::Vec3(-backgroundMargin, characterSize + backgroundMargin, 0),
_camera->getViewport()->width() - 2 * backgroundMargin,
(3 + 4.5 * cameras.size()) * characterSize + 2 * backgroundMargin,
backgroundColor) );

{
pos.x() = leftPos;

osg::ref_ptr<osgText::Text> eventLabel = new osgText::Text;
geode->addDrawable( eventLabel.get() );

eventLabel->setColor(colorUpdate);
eventLabel->setFont(font);
eventLabel->setCharacterSize(characterSize);
eventLabel->setPosition(pos);
eventLabel->setText("Event: ");

pos.x() = eventLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> eventValue = new osgText::Text;
geode->addDrawable( eventValue.get() );

eventValue->setColor(colorUpdate);
eventValue->setFont(font);
eventValue->setCharacterSize(characterSize);
eventValue->setPosition(pos);
eventValue->setText("0.0");

eventValue->setDrawCallback(new AveragedValueTextDrawCallback(viewer->getViewerStats(),"Event traversal time taken",-1, false, 1000.0));

pos.x() = startBlocks;
osg::Geometry* geometry = createGeometry(pos, characterSize *0.8, colorUpdateAlpha, _numBlocks);
geometry->setDrawCallback(new BlockDrawCallback(this, startBlocks, viewer->getViewerStats(), viewer->getViewerStats(), "Event traversal begin time", "Event traversal end time", -1, _numBlocks));
geode->addDrawable(geometry);

pos.y() -= characterSize*1.5f;
}

{
pos.x() = leftPos;

osg::ref_ptr<osgText::Text> updateLabel = new osgText::Text;
geode->addDrawable( updateLabel.get() );

updateLabel->setColor(colorUpdate);
updateLabel->setFont(font);
updateLabel->setCharacterSize(characterSize);
updateLabel->setPosition(pos);
updateLabel->setText("Update: ");

pos.x() = updateLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> updateValue = new osgText::Text;
geode->addDrawable( updateValue.get() );

updateValue->setColor(colorUpdate);
updateValue->setFont(font);
updateValue->setCharacterSize(characterSize);
updateValue->setPosition(pos);
updateValue->setText("0.0");

updateValue->setDrawCallback(new AveragedValueTextDrawCallback(viewer->getViewerStats(),"Update traversal time taken",-1, false, 1000.0));

pos.x() = startBlocks;
osg::Geometry* geometry = createGeometry(pos, characterSize *0.8, colorUpdateAlpha, _numBlocks);
geometry->setDrawCallback(new BlockDrawCallback(this, startBlocks, viewer->getViewerStats(), viewer->getViewerStats(), "Update traversal begin time", "Update traversal end time", -1, _numBlocks));
geode->addDrawable(geometry);

pos.y() -= characterSize*1.5f;
}

pos.x() = leftPos;

// add camera stats
for(ViewerBase::Cameras::iterator citr = cameras.begin();
citr != cameras.end();
++citr)
{
group->addChild(createCameraTimeStats(font, pos, startBlocks, acquireGPUStats, characterSize, viewer->getViewerStats(), *citr));
}

// add frame ticks
{
osg::Geode* geode = new osg::Geode;
group->addChild(geode);

osg::Vec4 colourTicks(1.0f,1.0f,1.0f, 0.5f);

pos.x() = startBlocks;
pos.y() += characterSize;
float height = topOfViewerStats - pos.y();

osg::Geometry* ticks = createTick(pos, 5.0f, colourTicks, 100);
geode->addDrawable(ticks);

osg::Geometry* frameMarkers = createFrameMarkers(pos, height, colourTicks, _numBlocks + 1);
frameMarkers->setDrawCallback(new FrameMarkerDrawCallback(this, startBlocks, viewer->getViewerStats(), 0, _numBlocks + 1));
geode->addDrawable(frameMarkers);

pos.x() = leftPos;
}

// Stats line graph
{
pos.y() -= (backgroundSpacing + 2 * backgroundMargin);
float width = _camera->getViewport()->width() - 4 * backgroundMargin;
float height = 5 * characterSize;

// Create a stats graph and add any stats we want to track with it.
StatsGraph* statsGraph = new StatsGraph(pos, width, height);
group->addChild(statsGraph);

statsGraph->addStatGraph(viewer->getViewerStats(), viewer->getViewerStats(), colorFR, 100, "Frame rate");
statsGraph->addStatGraph(viewer->getViewerStats(), viewer->getViewerStats(), colorEvent, 0.016, "Event traversal time taken");
statsGraph->addStatGraph(viewer->getViewerStats(), viewer->getViewerStats(), colorUpdate, 0.016, "Update traversal time taken");

for(ViewerBase::Cameras::iterator citr = cameras.begin();
citr != cameras.end();
++citr)
{
statsGraph->addStatGraph(viewer->getViewerStats(), (*citr)->getStats(), colorCull, 0.016, "Cull traversal time taken");
statsGraph->addStatGraph(viewer->getViewerStats(), (*citr)->getStats(), colorDraw, 0.016, "Draw traversal time taken");
statsGraph->addStatGraph(viewer->getViewerStats(), (*citr)->getStats(), colorGPU, 0.016, "GPU draw time taken");
}

geode->addDrawable(createBackgroundRectangle( pos + osg::Vec3(-backgroundMargin, backgroundMargin, 0),
width + 2 * backgroundMargin,
height + 2 * backgroundMargin,
backgroundColor) );

pos.x() = leftPos;
pos.y() -= height + 2 * backgroundMargin;
}

// Databasepager stats
ViewerBase::Scenes scenes;
viewer->getScenes(scenes);
for(ViewerBase::Scenes::iterator itr = scenes.begin();
itr != scenes.end();
++itr)
{
Scene* scene = *itr;
osgDB::DatabasePager* dp = scene->getDatabasePager();
if (dp && dp->isRunning())
{
pos.y() -= (characterSize + backgroundSpacing);

geode->addDrawable(createBackgroundRectangle( pos + osg::Vec3(-backgroundMargin, characterSize + backgroundMargin, 0),
_camera->getViewport()->width() - 2 * backgroundMargin,
characterSize + 2 * backgroundMargin,
backgroundColor));

osg::ref_ptr<osgText::Text> averageLabel = new osgText::Text;
geode->addDrawable( averageLabel.get() );

averageLabel->setColor(colorDP);
averageLabel->setFont(font);
averageLabel->setCharacterSize(characterSize);
averageLabel->setPosition(pos);
averageLabel->setText("DatabasePager time to merge new tiles - average: ");

pos.x() = averageLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> averageValue = new osgText::Text;
geode->addDrawable( averageValue.get() );

averageValue->setColor(colorDP);
averageValue->setFont(font);
averageValue->setCharacterSize(characterSize);
averageValue->setPosition(pos);
averageValue->setText("1000");

pos.x() = averageValue->getBound().xMax() + 2.0f*characterSize;


osg::ref_ptr<osgText::Text> minLabel = new osgText::Text;
geode->addDrawable( minLabel.get() );

minLabel->setColor(colorDP);
minLabel->setFont(font);
minLabel->setCharacterSize(characterSize);
minLabel->setPosition(pos);
minLabel->setText("min: ");

pos.x() = minLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> minValue = new osgText::Text;
geode->addDrawable( minValue.get() );

minValue->setColor(colorDP);
minValue->setFont(font);
minValue->setCharacterSize(characterSize);
minValue->setPosition(pos);
minValue->setText("1000");

pos.x() = minValue->getBound().xMax() + 2.0f*characterSize;

osg::ref_ptr<osgText::Text> maxLabel = new osgText::Text;
geode->addDrawable( maxLabel.get() );

maxLabel->setColor(colorDP);
maxLabel->setFont(font);
maxLabel->setCharacterSize(characterSize);
maxLabel->setPosition(pos);
maxLabel->setText("max: ");

pos.x() = maxLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> maxValue = new osgText::Text;
geode->addDrawable( maxValue.get() );

maxValue->setColor(colorDP);
maxValue->setFont(font);
maxValue->setCharacterSize(characterSize);
maxValue->setPosition(pos);
maxValue->setText("1000");

pos.x() = maxValue->getBound().xMax();

osg::ref_ptr<osgText::Text> requestsLabel = new osgText::Text;
geode->addDrawable( requestsLabel.get() );

requestsLabel->setColor(colorDP);
requestsLabel->setFont(font);
requestsLabel->setCharacterSize(characterSize);
requestsLabel->setPosition(pos);
requestsLabel->setText("requests: ");

pos.x() = requestsLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> requestList = new osgText::Text;
geode->addDrawable( requestList.get() );

requestList->setColor(colorDP);
requestList->setFont(font);
requestList->setCharacterSize(characterSize);
requestList->setPosition(pos);
requestList->setText("0");

pos.x() = requestList->getBound().xMax() + 2.0f*characterSize;;

osg::ref_ptr<osgText::Text> compileLabel = new osgText::Text;
geode->addDrawable( compileLabel.get() );

compileLabel->setColor(colorDP);
compileLabel->setFont(font);
compileLabel->setCharacterSize(characterSize);
compileLabel->setPosition(pos);
compileLabel->setText("tocompile: ");

pos.x() = compileLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> compileList = new osgText::Text;
geode->addDrawable( compileList.get() );

compileList->setColor(colorDP);
compileList->setFont(font);
compileList->setCharacterSize(characterSize);
compileList->setPosition(pos);
compileList->setText("0");

pos.x() = maxLabel->getBound().xMax();

geode->setCullCallback(new PagerCallback(dp, minValue.get(), maxValue.get(), averageValue.get(), requestList.get(), compileList.get(), 1000.0));
}

pos.x() = leftPos;
}
}

// Camera scene stats
{
pos.y() -= (characterSize + backgroundSpacing + 2 * backgroundMargin);

osg::Group* group = new osg::Group;
_cameraSceneChildNum = _switch->getNumChildren();
_switch->addChild(group, false);

osg::Geode* geode = new osg::Geode();
geode->setCullingActive(false);
group->addChild(geode);
geode->addDrawable(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, characterSize + backgroundMargin, 0),
7 * characterSize + 2 * backgroundMargin,
19 * characterSize + 2 * backgroundMargin,
backgroundColor));

// Camera scene & primitive stats static text
osg::ref_ptr<osgText::Text> camStaticText = new osgText::Text;
geode->addDrawable( camStaticText.get() );
camStaticText->setColor(staticTextColor);
camStaticText->setFont(font);
camStaticText->setCharacterSize(characterSize);
camStaticText->setPosition(pos);

std::ostringstream viewStr;
viewStr.clear();
viewStr.setf(std::ios::left, std::ios::adjustfield);
viewStr.width(14);
viewStr << "Camera" << std::endl;
viewStr << "" << std::endl; // placeholder for Camera name
viewStr << "Vertices" << std::endl;
viewStr << "Drawables" << std::endl;
viewStr << "Lights" << std::endl;
viewStr << "Bins" << std::endl;
viewStr << "Depth" << std::endl;
viewStr << "Matrices" << std::endl;
viewStr << "Imposters" << std::endl;
viewStr << "Points" << std::endl;
viewStr << "Lines" << std::endl;
viewStr << "Line strips" << std::endl;
viewStr << "Line loops" << std::endl;
viewStr << "Triangles" << std::endl;
viewStr << "Tri. strips" << std::endl;
viewStr << "Tri. fans" << std::endl;
viewStr << "Quads" << std::endl;
viewStr << "Quad strips" << std::endl;
viewStr << "Polygons" << std::endl;
viewStr.setf(std::ios::right,std::ios::adjustfield);
camStaticText->setText(viewStr.str());

// Move camera block to the right
pos.x() += 7 * characterSize + 2 * backgroundMargin + backgroundSpacing;

// Add camera scene stats, one block per camera
int cameraCounter = 0;
for(ViewerBase::Cameras::iterator citr = cameras.begin(); citr != cameras.end(); ++citr)
{
geode->addDrawable(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, characterSize + backgroundMargin, 0),
5 * characterSize + 2 * backgroundMargin,
19 * characterSize + 2 * backgroundMargin,
backgroundColor));

// Camera scene stats
osg::ref_ptr<osgText::Text> camStatsText = new osgText::Text;
geode->addDrawable( camStatsText.get() );

camStatsText->setColor(dynamicTextColor);
camStatsText->setFont(font);
camStatsText->setCharacterSize(characterSize);
camStatsText->setPosition(pos);
camStatsText->setText("");
camStatsText->setDrawCallback(new CameraSceneStatsTextDrawCallback(*citr, cameraCounter));

// Move camera block to the right
pos.x() += 5 * characterSize + 2 * backgroundMargin + backgroundSpacing;
cameraCounter++;
}
}

// Viewer scene stats
{
osg::Group* group = new osg::Group;
_viewerSceneChildNum = _switch->getNumChildren();
_switch->addChild(group, false);

osg::Geode* geode = new osg::Geode();
geode->setCullingActive(false);
group->addChild(geode);

geode->addDrawable(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, characterSize + backgroundMargin, 0),
6 * characterSize + 2 * backgroundMargin,
12 * characterSize + 2 * backgroundMargin,
backgroundColor));

// View scene stats static text
osg::ref_ptr<osgText::Text> camStaticText = new osgText::Text;
geode->addDrawable( camStaticText.get() );
camStaticText->setColor(staticTextColor);
camStaticText->setFont(font);
camStaticText->setCharacterSize(characterSize);
camStaticText->setPosition(pos);

std::ostringstream viewStr;
viewStr.clear();
viewStr.setf(std::ios::left, std::ios::adjustfield);
viewStr.width(14);
viewStr << "View" << std::endl;
viewStr << " " << std::endl;
viewStr << "Stateset" << std::endl;
viewStr << "Group" << std::endl;
viewStr << "Transform" << std::endl;
viewStr << "LOD" << std::endl;
viewStr << "Switch" << std::endl;
viewStr << "Geode" << std::endl;
viewStr << "Drawable" << std::endl;
viewStr << "Geometry" << std::endl;
viewStr << "Vertices" << std::endl;
viewStr << "Primitives" << std::endl;
viewStr.setf(std::ios::right, std::ios::adjustfield);
camStaticText->setText(viewStr.str());

// Move viewer block to the right
pos.x() += 6 * characterSize + 2 * backgroundMargin + backgroundSpacing;

std::vector<osgViewer::View*> views;
viewer->getViews(views);

std::vector<osgViewer::View*>::iterator it;
int viewCounter = 0;
for (it = views.begin(); it != views.end(); ++it)
{
geode->addDrawable(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, characterSize + backgroundMargin, 0),
11 * characterSize + 2 * backgroundMargin,
12 * characterSize + 2 * backgroundMargin,
backgroundColor));

// Text for scene statistics
osgText::Text* text = new osgText::Text;
geode->addDrawable( text );

text->setColor(dynamicTextColor);
text->setFont(font);
text->setCharacterSize(characterSize);
text->setPosition(pos);
text->setDrawCallback(new ViewSceneStatsTextDrawCallback(*it, viewCounter));

pos.x() += 11 * characterSize + 2 * backgroundMargin + backgroundSpacing;
viewCounter++;
}
}
}

osg::Node* StatsHandler::createCameraTimeStats(const std::string& font, osg::Vec3& pos, float startBlocks, bool acquireGPUStats, float characterSize, osg::Stats* viewerStats, osg::Camera* camera)
{
osg::Stats* stats = camera->getStats();
if (!stats) return 0;

osg::Group* group = new osg::Group;

osg::Geode* geode = new osg::Geode();
group->addChild(geode);

float leftPos = pos.x();

osg::Vec4 colorCull( 0.0f,1.0f,1.0f,1.0f);
osg::Vec4 colorCullAlpha( 0.0f,1.0f,1.0f,0.5f);
osg::Vec4 colorDraw( 1.0f,1.0f,0.0f,1.0f);
osg::Vec4 colorDrawAlpha( 1.0f,1.0f,0.0f,0.5f);
osg::Vec4 colorGPU( 1.0f,0.5f,0.0f,1.0f);
osg::Vec4 colorGPUAlpha( 1.0f,0.5f,0.0f,0.5f);

{
pos.x() = leftPos;

osg::ref_ptr<osgText::Text> cullLabel = new osgText::Text;
geode->addDrawable( cullLabel.get() );

cullLabel->setColor(colorCull);
cullLabel->setFont(font);
cullLabel->setCharacterSize(characterSize);
cullLabel->setPosition(pos);
cullLabel->setText("Cull: ");

pos.x() = cullLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> cullValue = new osgText::Text;
geode->addDrawable( cullValue.get() );

cullValue->setColor(colorCull);
cullValue->setFont(font);
cullValue->setCharacterSize(characterSize);
cullValue->setPosition(pos);
cullValue->setText("0.0");

cullValue->setDrawCallback(new AveragedValueTextDrawCallback(stats,"Cull traversal time taken",-1, false, 1000.0));

pos.x() = startBlocks;
osg::Geometry* geometry = createGeometry(pos, characterSize *0.8, colorCullAlpha, _numBlocks);
geometry->setDrawCallback(new BlockDrawCallback(this, startBlocks, viewerStats, stats, "Cull traversal begin time", "Cull traversal end time", -1, _numBlocks));
geode->addDrawable(geometry);

pos.y() -= characterSize*1.5f;
}

{
pos.x() = leftPos;

osg::ref_ptr<osgText::Text> drawLabel = new osgText::Text;
geode->addDrawable( drawLabel.get() );

drawLabel->setColor(colorDraw);
drawLabel->setFont(font);
drawLabel->setCharacterSize(characterSize);
drawLabel->setPosition(pos);
drawLabel->setText("Draw: ");

pos.x() = drawLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> drawValue = new osgText::Text;
geode->addDrawable( drawValue.get() );

drawValue->setColor(colorDraw);
drawValue->setFont(font);
drawValue->setCharacterSize(characterSize);
drawValue->setPosition(pos);
drawValue->setText("0.0");

drawValue->setDrawCallback(new AveragedValueTextDrawCallback(stats,"Draw traversal time taken",-1, false, 1000.0));


pos.x() = startBlocks;
osg::Geometry* geometry = createGeometry(pos, characterSize *0.8, colorDrawAlpha, _numBlocks);
geometry->setDrawCallback(new BlockDrawCallback(this, startBlocks, viewerStats, stats, "Draw traversal begin time", "Draw traversal end time", -1, _numBlocks));
geode->addDrawable(geometry);

pos.y() -= characterSize*1.5f;
}

if (acquireGPUStats)
{
pos.x() = leftPos;

osg::ref_ptr<osgText::Text> gpuLabel = new osgText::Text;
geode->addDrawable( gpuLabel.get() );

gpuLabel->setColor(colorGPU);
gpuLabel->setFont(font);
gpuLabel->setCharacterSize(characterSize);
gpuLabel->setPosition(pos);
gpuLabel->setText("GPU: ");

pos.x() = gpuLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> gpuValue = new osgText::Text;
geode->addDrawable( gpuValue.get() );

gpuValue->setColor(colorGPU);
gpuValue->setFont(font);
gpuValue->setCharacterSize(characterSize);
gpuValue->setPosition(pos);
gpuValue->setText("0.0");

gpuValue->setDrawCallback(new AveragedValueTextDrawCallback(stats,"GPU draw time taken",-1, false, 1000.0));

pos.x() = startBlocks;
osg::Geometry* geometry = createGeometry(pos, characterSize *0.8, colorGPUAlpha, _numBlocks);
geometry->setDrawCallback(new BlockDrawCallback(this, startBlocks, viewerStats, stats, "GPU draw begin time", "GPU draw end time", -1, _numBlocks));
geode->addDrawable(geometry);

pos.y() -= characterSize*1.5f;
}


pos.x() = leftPos;

return group;
}


void StatsHandler::getUsage(osg::ApplicationUsage& usage) const
{
usage.addKeyboardMouseBinding("s","On screen stats.");
usage.addKeyboardMouseBinding("S","Output stats to console.");
}

}

/* OpenSceneGraph example, osgcompositeviewer.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include <osgUtil/Optimizer>
#include <osgDB/ReadFile>

#include <osg/Material>
#include <osg/Geode>
#include <osg/BlendFunc>
#include <osg/Depth>
#include <osg/Projection>
#include <osg/PolygonOffset>
#include <osg/MatrixTransform>
#include <osg/Camera>
#include <osg/FrontFace>

#include <osgText/Text>

#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/StateSetManipulator>
#include <osgViewer/ViewerEventHandlers>

#include <osgViewer/CompositeViewer>

#include <osgFX/Scribe>

#include <osg/io_utils>

// class to handle events with a pick
class PickHandler : public osgGA::GUIEventHandler {
public:

PickHandler():
_mx(0.0f),
_my(0.0f) {}

~PickHandler() {}

bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
{
osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
if (!view) return false;

switch(ea.getEventType())
{
case(osgGA::GUIEventAdapter::PUSH):
{
_mx = ea.getX();
_my = ea.getY();
break;
}
case(osgGA::GUIEventAdapter::RELEASE):
{
if (_mx==ea.getX() && _my==ea.getY())
{
pick(view, ea.getX(), ea.getY());
}
break;
}
default:
break;
}
return false;
}

void pick(osgViewer::View* view, float x, float y)
{
osg::Node* node = 0;
osg::Group* parent = 0;

osgUtil::LineSegmentIntersector::Intersections intersections;
if (view->computeIntersections(x, y, intersections))
{
osgUtil::LineSegmentIntersector::Intersection intersection = *intersections.begin();
osg::NodePath& nodePath = intersection.nodePath;
node = (nodePath.size()>=1)?nodePath[nodePath.size()-1]:0;
parent = (nodePath.size()>=2)?dynamic_cast<osg::Group*>(nodePath[nodePath.size()-2]):0;
}

// now we try to decorate the hit node by the osgFX::Scribe to show that its been "picked"
if (parent && node)
{

osgFX::Scribe* parentAsScribe = dynamic_cast<osgFX::Scribe*>(parent);
if (!parentAsScribe)
{
// node not already picked, so highlight it with an osgFX::Scribe
osgFX::Scribe* scribe = new osgFX::Scribe();
scribe->addChild(node);
parent->replaceChild(node,scribe);
}
else
{
// node already picked so we want to remove scribe to unpick it.
osg::Node::ParentList parentList = parentAsScribe->getParents();
for(osg::Node::ParentList::iterator itr=parentList.begin();
itr!=parentList.end();
++itr)
{
(*itr)->replaceChild(parentAsScribe,node);
}
}
}

}

float _mx, _my;

};


int main( int argc, char **argv )
{

// use an ArgumentParser object to manage the program arguments.
osg::ArgumentParser arguments(&argc,argv);

// read the scene from the list of file specified commandline args.
osg::ref_ptr<osg::Node> scene = osgDB::readNodeFiles(arguments);

if (!scene) return 1;

// construct the viewer.
osgViewer::CompositeViewer viewer(arguments);




if (arguments.read("-1"))
{
{
osgViewer::View* view = new osgViewer::View;
view->setName("Single view");
view->setSceneData(osgDB::readNodeFile("fountain.osg"));

view->addEventHandler( new osgViewer::StatsHandler );

view->setUpViewAcrossAllScreens();
view->setCameraManipulator(new osgGA::TrackballManipulator);
viewer.addView(view);
}
}

if (arguments.read("-2"))
{

// view one
{
osgViewer::View* view = new osgViewer::View;
view->setName("View one");
viewer.addView(view);

view->setUpViewOnSingleScreen(0);
view->setSceneData(scene.get());
view->setCameraManipulator(new osgGA::TrackballManipulator);

// add the state manipulator
osg::ref_ptr<osgGA::StateSetManipulator> statesetManipulator = new osgGA::StateSetManipulator;
statesetManipulator->setStateSet(view->getCamera()->getOrCreateStateSet());

view->addEventHandler( statesetManipulator.get() );
}

// view two
{
osgViewer::View* view = new osgViewer::View;
view->setName("View two");
viewer.addView(view);

view->setUpViewOnSingleScreen(1);
view->setSceneData(scene.get());
view->setCameraManipulator(new osgGA::TrackballManipulator);

view->addEventHandler( new osgViewer::StatsHandler );


// add the handler for doing the picking
view->addEventHandler(new PickHandler());
}
}


if (arguments.read("-3") || viewer.getNumViews()==0)
{

osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
if (!wsi)
{
osg::notify(osg::NOTICE)<<"Error, no WindowSystemInterface available, cannot create windows."<<std::endl;
return 1;
}

unsigned int width, height;
wsi->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0), width, height);

osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
traits->x = 100;
traits->y = 100;
traits->width = 1000;
traits->height = 800;
traits->windowDecoration = true;
traits->doubleBuffer = true;
traits->sharedContext = 0;

osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
if (gc.valid())
{
osg::notify(osg::INFO)<<" GraphicsWindow has been created successfully."<<std::endl;

// need to ensure that the window is cleared make sure that the complete window is set the correct colour
// rather than just the parts of the window that are under the camera's viewports
gc->setClearColor(osg::Vec4f(0.2f,0.2f,0.6f,1.0f));
gc->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
else
{
osg::notify(osg::NOTICE)<<" GraphicsWindow has not been created successfully."<<std::endl;
}

// view one
{
osgViewer::View* view = new osgViewer::View;
view->setName("View one");
viewer.addView(view);

view->setSceneData(scene.get());
view->getCamera()->setName("Cam one");
view->getCamera()->setViewport(new osg::Viewport(0,0, traits->width/2, traits->height/2));
view->getCamera()->setGraphicsContext(gc.get());
view->setCameraManipulator(new osgGA::TrackballManipulator);

// add the state manipulator
osg::ref_ptr<osgGA::StateSetManipulator> statesetManipulator = new osgGA::StateSetManipulator;
statesetManipulator->setStateSet(view->getCamera()->getOrCreateStateSet());

view->addEventHandler( statesetManipulator.get() );

view->addEventHandler( new osgViewer::StatsHandler );
view->addEventHandler( new osgViewer::HelpHandler );
view->addEventHandler( new osgViewer::WindowSizeHandler );
view->addEventHandler( new osgViewer::ThreadingHandler );
view->addEventHandler( new osgViewer::RecordCameraPathHandler );
}

// view two
{
osgViewer::View* view = new osgViewer::View;
view->setName("View two");
viewer.addView(view);

view->setSceneData(scene.get());
view->getCamera()->setName("Cam two");
view->getCamera()->setViewport(new osg::Viewport(traits->width/2,0, traits->width/2, traits->height/2));
view->getCamera()->setGraphicsContext(gc.get());
view->setCameraManipulator(new osgGA::TrackballManipulator);

// add the handler for doing the picking
view->addEventHandler(new PickHandler());

}

// view three
{
osgViewer::View* view = new osgViewer::View;
view->setName("View three");
viewer.addView(view);

view->setSceneData(osgDB::readNodeFile("cessnafire.osg"));

view->getCamera()->setName("Cam three");
view->getCamera()->setProjectionMatrixAsPerspective(30.0, double(traits->width) / double(traits->height/2), 1.0, 1000.0);
view->getCamera()->setViewport(new osg::Viewport(0, traits->height/2, traits->width, traits->height/2));
view->getCamera()->setGraphicsContext(gc.get());
view->setCameraManipulator(new osgGA::TrackballManipulator);
}

}


while (arguments.read("-s")) { viewer.setThreadingModel(osgViewer::CompositeViewer::SingleThreaded); }
while (arguments.read("-g")) { viewer.setThreadingModel(osgViewer::CompositeViewer::CullDrawThreadPerContext); }
while (arguments.read("-c")) { viewer.setThreadingModel(osgViewer::CompositeViewer::CullThreadPerCameraDrawThreadPerContext); }

// run the viewer's main frame loop
return viewer.run();
}



------------------
Post generated by Mail2Forum
Back to top
Robert Osfield
Guest





PostPosted: Wed Jan 28, 2009 9:25 am    Post subject:
Statshandler layout fixes
Reply with quote

Thanks Paul, changes now merged and submitted to SVN.

I have been able to reproduce the crash in osgcompositeviewer here so
I'll go see if I can fix.

On Tue, Jan 27, 2009 at 8:21 PM, Paul Melis
<> wrote:
Quote:
Hi Robert,

Here is an updated osgViewer::StatsHandler. It has the following changes:
- The text and dark background rectangles are now correctly placed, and
slightly resized here and there.
- All counters (vertices, etc) now use a fixed formatting with 0 digits
precision, to prevent the text from being shown in scientific notation
when the number get large (e.g. 6.34344e+6). I tested with a scene
containing roughly 4 million vertices, to make sure its stats would
display correctly.

I also made slight changes to osgcompositeviewer (attached) to aid in
testing the stats display, specifically displaying of camera and view
names. Unfortunately, I get a segfault when trying to switch on the View
statistics (i.e. when pressing 's' for the 4th time) with
"osgcompositeviewer cow.osg". Here's the stack trace, looks like a null
pointer somewhere. I looked at the problem briefly but decided I don't
know enough to fix it...

#0 osg::Stats::setAttribute (this=0x0, frameNumber=1556,
attributeName=@0xbff9f7fc, value=1) at
/home/melis/c/osg/svn/trunk/include/osg/Stats:41
#1 0xb7aa6aa1 in osgViewer::ViewerBase::renderingTraversals
(this=0xbff9f9d8) at
/home/melis/c/osg/svn/trunk/src/osgViewer/ViewerBase.cpp:670
#2 0xb7aa5083 in osgViewer::ViewerBase::frame (this=0xbff9f9d8,
simulationTime=1.7976931348623157e+308) at
/home/melis/c/osg/svn/trunk/src/osgViewer/ViewerBase.cpp:609
#3 0xb7aa51c1 in osgViewer::ViewerBase::run (this=0xbff9f9d8) at
/home/melis/c/osg/svn/trunk/src/osgViewer/ViewerBase.cpp:581
#4 0xb7a52fd0 in osgViewer::CompositeViewer::run (this=0xbff9f9d8) at
/home/melis/c/osg/svn/trunk/src/osgViewer/CompositeViewer.cpp:232
#5 0x0804c476 in main (argc=Cannot access memory at address 0x0
) at
/home/melis/c/osg/svn/trunk/examples/osgcompositeviewer/osgcompositeviewer.cpp:301

Regards,
Paul

/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library 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. See the
* OpenSceneGraph Public License for more details.
*/

#include <sstream>
#include <iomanip>
#include <stdio.h>

#include <osg/io_utils>

#include <osg/MatrixTransform>

#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/Renderer>

#include <osg/PolygonMode>
#include <osg/Geometry>

namespace osgViewer
{


StatsHandler::StatsHandler():
_keyEventTogglesOnScreenStats('s'),
_keyEventPrintsOutStats('S'),
_statsType(NO_STATS),
_initialized(false),
_threadingModel(ViewerBase::SingleThreaded),
_frameRateChildNum(0),
_viewerChildNum(0),
_cameraSceneChildNum(0),
_viewerSceneChildNum(0),
_numBlocks(Cool,
_blockMultiplier(10000.0)
{
_camera = new osg::Camera;
_camera->setRenderer(new Renderer(_camera.get()));
_camera->setProjectionResizePolicy(osg::Camera::FIXED);
}

bool StatsHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{

osgViewer::View* myview = dynamic_cast<osgViewer::View*>(&aa);
if (!myview) return false;

osgViewer::ViewerBase* viewer = myview->getViewerBase();
if (viewer && _threadingModelText.valid() && viewer->getThreadingModel()!=_threadingModel)
{
_threadingModel = viewer->getThreadingModel();
updateThreadingModelText();
}


if (ea.getHandled()) return false;

switch(ea.getEventType())
{
case(osgGA::GUIEventAdapter::KEYDOWN):
{
if (ea.getKey()==_keyEventTogglesOnScreenStats)
{
if (viewer->getViewerStats())
{
if (!_initialized)
{
setUpHUDCamera(viewer);
setUpScene(viewer);
}

++_statsType;

if (_statsType==LAST) _statsType = NO_STATS;

osgViewer::ViewerBase::Cameras cameras;
viewer->getCameras(cameras);

switch(_statsType)
{
case(NO_STATS):
{
viewer->getViewerStats()->collectStats("frame_rate",false);
viewer->getViewerStats()->collectStats("event",false);
viewer->getViewerStats()->collectStats("update",false);

for(osgViewer::ViewerBase::Cameras::iterator itr = cameras.begin();
itr != cameras.end();
++itr)
{
osg::Stats* stats = (*itr)->getStats();
if (stats)
{
stats->collectStats("rendering",false);
stats->collectStats("gpu",false);
stats->collectStats("scene",false);
}
}

viewer->getViewerStats()->collectStats("scene",false);

_camera->setNodeMask(0x0);
_switch->setAllChildrenOff();
break;
}
case(FRAME_RATE):
{
viewer->getViewerStats()->collectStats("frame_rate",true);

_camera->setNodeMask(0xffffffff);
_switch->setValue(_frameRateChildNum, true);
break;
}
case(VIEWER_STATS):
{
ViewerBase::Scenes scenes;
viewer->getScenes(scenes);
for(ViewerBase::Scenes::iterator itr = scenes.begin();
itr != scenes.end();
++itr)
{
Scene* scene = *itr;
osgDB::DatabasePager* dp = scene->getDatabasePager();
if (dp && dp->isRunning())
{
dp->resetStats();
}
}

viewer->getViewerStats()->collectStats("event",true);
viewer->getViewerStats()->collectStats("update",true);

for(osgViewer::ViewerBase::Cameras::iterator itr = cameras.begin();
itr != cameras.end();
++itr)
{
if ((*itr)->getStats()) (*itr)->getStats()->collectStats("rendering",true);
if ((*itr)->getStats()) (*itr)->getStats()->collectStats("gpu",true);
}

_camera->setNodeMask(0xffffffff);
_switch->setValue(_viewerChildNum, true);
break;
}
case(CAMERA_SCENE_STATS):
{
_camera->setNodeMask(0xffffffff);
_switch->setValue(_cameraSceneChildNum, true);

for(osgViewer::ViewerBase::Cameras::iterator itr = cameras.begin();
itr != cameras.end();
++itr)
{
osg::Stats* stats = (*itr)->getStats();
if (stats)
{
stats->collectStats("scene",true);
}
}

break;
}
case(VIEWER_SCENE_STATS):
{
_camera->setNodeMask(0xffffffff);
_switch->setValue(_viewerSceneChildNum, true);

viewer->getViewerStats()->collectStats("scene",true);

break;
}
default:
break;
}


}
return true;
}
if (ea.getKey()==_keyEventPrintsOutStats)
{
if (viewer->getViewerStats())
{
osg::notify(osg::NOTICE)<<std::endl<<"Stats report:"<<std::endl;
typedef std::vector<osg::Stats*> StatsList;
StatsList statsList;
statsList.push_back(viewer->getViewerStats());

osgViewer::ViewerBase::Contexts contexts;
viewer->getContexts(contexts);
for(osgViewer::ViewerBase::Contexts::iterator gcitr = contexts.begin();
gcitr != contexts.end();
++gcitr)
{
osg::GraphicsContext::Cameras& cameras = (*gcitr)->getCameras();
for(osg::GraphicsContext::Cameras::iterator itr = cameras.begin();
itr != cameras.end();
++itr)
{
if ((*itr)->getStats())
{
statsList.push_back((*itr)->getStats());
}
}
}

for(int i = viewer->getViewerStats()->getEarliestFrameNumber(); i<= viewer->getViewerStats()->getLatestFrameNumber()-1; ++i)
{
for(StatsList::iterator itr = statsList.begin();
itr != statsList.end();
++itr)
{
if (itr==statsList.begin()) (*itr)->report(osg::notify(osg::NOTICE), i);
else (*itr)->report(osg::notify(osg::NOTICE), i, " ");
}
osg::notify(osg::NOTICE)<<std::endl;
}

}
return true;
}
}
default: break;
}

return false;

}

void StatsHandler::updateThreadingModelText()
{
switch(_threadingModel)
{
case(osgViewer::Viewer::SingleThreaded): _threadingModelText->setText("ThreadingModel: SingleThreaded"); break;
case(osgViewer::Viewer::CullDrawThreadPerContext): _threadingModelText->setText("ThreadingModel: CullDrawThreadPerContext"); break;
case(osgViewer::Viewer::DrawThreadPerContext): _threadingModelText->setText("ThreadingModel: DrawThreadPerContext"); break;
case(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext): _threadingModelText->setText("ThreadingModel: CullThreadPerCameraDrawThreadPerContext"); break;
case(osgViewer::Viewer::AutomaticSelection): _threadingModelText->setText("ThreadingModel: AutomaticSelection"); break;
default:
_threadingModelText->setText("ThreadingModel: unknown"); break;
}
}

void StatsHandler::reset()
{
_initialized = false;
_camera->setGraphicsContext(0);
_camera->removeChildren( 0, _camera->getNumChildren() );
}

void StatsHandler::setUpHUDCamera(osgViewer::ViewerBase* viewer)
{
osgViewer::GraphicsWindow* window = dynamic_cast<osgViewer::GraphicsWindow*>(_camera->getGraphicsContext());

if (!window)
{
osgViewer::Viewer::Windows windows;
viewer->getWindows(windows);

if (windows.empty()) return;

window = windows.front();
}

_camera->setGraphicsContext(window);

_camera->setViewport(0, 0, window->getTraits()->width, window->getTraits()->height);
_camera->setRenderOrder(osg::Camera::POST_RENDER, 10);

_camera->setProjectionMatrix(osg::Matrix::ortho2D(0,1280,0,1024));
_camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
_camera->setViewMatrix(osg::Matrix::identity());

// only clear the depth buffer
_camera->setClearMask(0);

_camera->setRenderer(new Renderer(_camera.get()));

_initialized = true;
}

// Drawcallback to draw averaged attribute
struct AveragedValueTextDrawCallback : public virtual osg::Drawable::DrawCallback
{
AveragedValueTextDrawCallback(osg::Stats* stats, const std::string& name, int frameDelta, bool averageInInverseSpace, double multiplier):
_stats(stats),
_attributeName(name),
_frameDelta(frameDelta),
_averageInInverseSpace(averageInInverseSpace),
_multiplier(multiplier),
_tickLastUpdated(0)
{
}

/** do customized draw code.*/
virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
{
osgText::Text* text = (osgText::Text*)drawable;

osg::Timer_t tick = osg::Timer::instance()->tick();
double delta = osg::Timer::instance()->delta_m(_tickLastUpdated, tick);

if (delta>50) // update every 50ms
{
_tickLastUpdated = tick;
double value;
if (_stats->getAveragedAttribute( _attributeName, value, _averageInInverseSpace))
{
sprintf(_tmpText,"%4.2f",value * _multiplier);
text->setText(_tmpText);
}
else
{
text->setText("");
}
}
text->drawImplementation(renderInfo);
}

osg::ref_ptr<osg::Stats> _stats;
std::string _attributeName;
int _frameDelta;
bool _averageInInverseSpace;
double _multiplier;
mutable char _tmpText[128];
mutable osg::Timer_t _tickLastUpdated;
};

struct CameraSceneStatsTextDrawCallback : public virtual osg::Drawable::DrawCallback
{
CameraSceneStatsTextDrawCallback(osg::Camera* camera, int cameraNumber):
_camera(camera),
_tickLastUpdated(0),
_cameraNumber(cameraNumber)
{
}

/** do customized draw code.*/
virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
{
if (!_camera) return;

osgText::Text* text = (osgText::Text*)drawable;

osg::Timer_t tick = osg::Timer::instance()->tick();
double delta = osg::Timer::instance()->delta_m(_tickLastUpdated, tick);

if (delta > 100) // update every 100ms
{
_tickLastUpdated = tick;
std::ostringstream viewStr;
viewStr.clear();

osg::Stats* stats = _camera->getStats();
osgViewer::Renderer* renderer = dynamic_cast<osgViewer::Renderer*>(_camera->getRenderer());

if (stats && renderer)
{
viewStr.setf(std::ios::left, std::ios::adjustfield);
viewStr.width(14);
// Used fixed formatting, as scientific will switch to "...e+.." notation for
// large numbers of vertices/drawables/etc.
viewStr.setf(std::ios::fixed);
viewStr.precision(0);

viewStr << std::setw(1) << "#" << _cameraNumber << std::endl;

// Camera name
if (!_camera->getName().empty())
viewStr << _camera->getName();
viewStr << std::endl;

int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();
if (!(renderer->getGraphicsThreadDoesCull()))
{
--frameNumber;
}

#define STATS_ATTRIBUTE(str) \
if (stats->getAttribute(frameNumber, str, value)) \
viewStr << std::setw(Cool << value << std::endl; \
else \
viewStr << std::setw(Cool << "." << std::endl; \

double value = 0.0;

STATS_ATTRIBUTE("Visible vertex count")
STATS_ATTRIBUTE("Visible number of drawables")
STATS_ATTRIBUTE("Visible number of lights")
STATS_ATTRIBUTE("Visible number of render bins")
STATS_ATTRIBUTE("Visible depth")
STATS_ATTRIBUTE("Visible number of materials")
STATS_ATTRIBUTE("Visible number of impostors")

STATS_ATTRIBUTE("Visible number of GL_POINTS")
STATS_ATTRIBUTE("Visible number of GL_LINES")
STATS_ATTRIBUTE("Visible number of GL_LINE_STRIP")
STATS_ATTRIBUTE("Visible number of GL_LINE_LOOP")
STATS_ATTRIBUTE("Visible number of GL_TRIANGLES")
STATS_ATTRIBUTE("Visible number of GL_TRIANGLE_STRIP")
STATS_ATTRIBUTE("Visible number of GL_TRIANGLE_FAN")
STATS_ATTRIBUTE("Visible number of GL_QUADS")
STATS_ATTRIBUTE("Visible number of GL_QUAD_STRIP")
STATS_ATTRIBUTE("Visible number of GL_POLYGON")

text->setText(viewStr.str());
}
}
text->drawImplementation(renderInfo);
}

osg::observer_ptr<osg::Camera> _camera;
mutable osg::Timer_t _tickLastUpdated;
int _cameraNumber;
};


struct ViewSceneStatsTextDrawCallback : public virtual osg::Drawable::DrawCallback
{
ViewSceneStatsTextDrawCallback(osgViewer::View* view, int viewNumber):
_view(view),
_tickLastUpdated(0),
_viewNumber(viewNumber)
{
}

/** do customized draw code.*/
virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
{
if (!_view) return;

osgText::Text* text = (osgText::Text*)drawable;

osg::Timer_t tick = osg::Timer::instance()->tick();
double delta = osg::Timer::instance()->delta_m(_tickLastUpdated, tick);

if (delta > 200) // update every 100ms
{
_tickLastUpdated = tick;
osg::Stats* stats = _view->getStats();
if (stats)
{
std::ostringstream viewStr;
viewStr.clear();
viewStr.setf(std::ios::left, std::ios::adjustfield);
viewStr.width(20);
viewStr.setf(std::ios::fixed);
viewStr.precision(0);

viewStr << std::setw(1) << "#" << _viewNumber;

// View name
if (!_view->getName().empty())
viewStr << ": " << _view->getName();
viewStr << std::endl;

int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();
// if (!(renderer->getGraphicsThreadDoesCull()))
{
--frameNumber;
}

#define STATS_ATTRIBUTE_PAIR(str1, str2) \
if (stats->getAttribute(frameNumber, str1, value)) \
viewStr << std::setw(10) << value; \
else \
viewStr << std::setw(10) << "."; \
if (stats->getAttribute(frameNumber, str2, value)) \
viewStr << std::setw(10) << value << std::endl; \
else \
viewStr << std::setw(10) << "." << std::endl; \

double value = 0.0;

// header
viewStr << std::setw(10) << "Unique" << std::setw(10) << "Instanced" << std::endl;

STATS_ATTRIBUTE_PAIR("Number of unique StateSet","Number of instanced Stateset")
STATS_ATTRIBUTE_PAIR("Number of unique Group","Number of instanced Group")
STATS_ATTRIBUTE_PAIR("Number of unique Transform","Number of instanced Transform")
STATS_ATTRIBUTE_PAIR("Number of unique LOD","Number of instanced LOD")
STATS_ATTRIBUTE_PAIR("Number of unique Switch","Number of instanced Switch")
STATS_ATTRIBUTE_PAIR("Number of unique Geode","Number of instanced Geode")
STATS_ATTRIBUTE_PAIR("Number of unique Drawable","Number of instanced Drawable")
STATS_ATTRIBUTE_PAIR("Number of unique Geometry","Number of instanced Geometry")
STATS_ATTRIBUTE_PAIR("Number of unique Vertices","Number of instanced Vertices")
STATS_ATTRIBUTE_PAIR("Number of unique Primitives","Number of instanced Primitives")


text->setText(viewStr.str());
}
else
{
osg::notify(osg::WARN)<<std::endl<<"No valid view to collect scene stats from"<<std::endl;

text->setText("");
}
}
text->drawImplementation(renderInfo);
}

osg::observer_ptr<osgViewer::View> _view;
mutable osg::Timer_t _tickLastUpdated;
int _viewNumber;
};

struct BlockDrawCallback : public virtual osg::Drawable::DrawCallback
{
BlockDrawCallback(StatsHandler* statsHandler, float xPos, osg::Stats* viewerStats, osg::Stats* stats, const std::string& beginName, const std::string& endName, int frameDelta, int numFrames):
_statsHandler(statsHandler),
_xPos(xPos),
_viewerStats(viewerStats),
_stats(stats),
_beginName(beginName),
_endName(endName),
_frameDelta(frameDelta),
_numFrames(numFrames) {}

/** do customized draw code.*/
virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
{
osg::Geometry* geom = (osg::Geometry*)drawable;
osg::Vec3Array* vertices = (osg::Vec3Array*)geom->getVertexArray();

int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();

int startFrame = frameNumber + _frameDelta - _numFrames + 1;
int endFrame = frameNumber + _frameDelta;
double referenceTime;
if (!_viewerStats->getAttribute( startFrame, "Reference time", referenceTime))
{
return;
}

unsigned int vi = 0;
double beginValue, endValue;
for(int i = startFrame; i <= endFrame; ++i)
{
if (_stats->getAttribute( i, _beginName, beginValue) &&
_stats->getAttribute( i, _endName, endValue) )
{
(*vertices)[vi++].x() = _xPos + (beginValue - referenceTime) * _statsHandler->getBlockMultiplier();
(*vertices)[vi++].x() = _xPos + (beginValue - referenceTime) * _statsHandler->getBlockMultiplier();
(*vertices)[vi++].x() = _xPos + (endValue - referenceTime) * _statsHandler->getBlockMultiplier();
(*vertices)[vi++].x() = _xPos + (endValue - referenceTime) * _statsHandler->getBlockMultiplier();
}
}

drawable->drawImplementation(renderInfo);
}

StatsHandler* _statsHandler;
float _xPos;
osg::ref_ptr<osg::Stats> _viewerStats;
osg::ref_ptr<osg::Stats> _stats;
std::string _beginName;
std::string _endName;
int _frameDelta;
int _numFrames;
};

osg::Geometry* StatsHandler::createBackgroundRectangle(const osg::Vec3& pos, const float width, const float height, osg::Vec4& color)
{
osg::StateSet *ss = new osg::StateSet;

osg::Geometry* geometry = new osg::Geometry;

geometry->setUseDisplayList(false);
geometry->setStateSet(ss);

osg::Vec3Array* vertices = new osg::Vec3Array;
geometry->setVertexArray(vertices);

vertices->push_back(osg::Vec3(pos.x(), pos.y(), 0));
vertices->push_back(osg::Vec3(pos.x(), pos.y()-height,0));
vertices->push_back(osg::Vec3(pos.x()+width, pos.y()-height,0));
vertices->push_back(osg::Vec3(pos.x()+width, pos.y(),0));

osg::Vec4Array* colors = new osg::Vec4Array;
colors->push_back(color);
geometry->setColorArray(colors);
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);

osg::DrawElementsUInt *base = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS,0);
base->push_back(0);
base->push_back(1);
base->push_back(2);
base->push_back(3);

geometry->addPrimitiveSet(base);

return geometry;
}


struct StatsGraph : public osg::MatrixTransform
{
StatsGraph(osg::Vec3 pos, float width, float height)
: _pos(pos), _width(width), _height(height),
_statsGraphGeode(new osg::Geode)
{
_pos -= osg::Vec3(0, height, 0.1);
this->setMatrix(osg::Matrix::translate(_pos));
this->addChild(_statsGraphGeode.get());
}

void addStatGraph(osg::Stats* viewerStats, osg::Stats* stats, const osg::Vec4& color, float max, const std::string& nameBegin, const std::string& nameEnd = "")
{
_statsGraphGeode->addDrawable(new Graph(_width, _height, viewerStats, stats, color, max, nameBegin, nameEnd));
}

osg::Vec3 _pos;
float _width;
float _height;

osg::ref_ptr<osg::Geode> _statsGraphGeode;

protected:
struct Graph : public osg::Geometry
{
Graph(float width, float height, osg::Stats* viewerStats, osg::Stats* stats,
const osg::Vec4& color, float max, const std::string& nameBegin, const std::string& nameEnd = "")
{
this->setUseDisplayList(false);

this->setVertexArray(new osg::Vec3Array);

osg::Vec4Array* colors = new osg::Vec4Array;
colors->push_back(color);
this->setColorArray(colors);
this->setColorBinding(osg::Geometry::BIND_OVERALL);

this->setDrawCallback(new GraphUpdateCallback(width, height, viewerStats, stats, max, nameBegin, nameEnd));
}
};

struct GraphUpdateCallback : public osg::Drawable::DrawCallback
{
GraphUpdateCallback(float width, float height, osg::Stats* viewerStats, osg::Stats* stats,
float max, const std::string& nameBegin, const std::string& nameEnd = "")
: _width((unsigned int)width), _height((unsigned int)height), _curX(0),
_viewerStats(viewerStats), _stats(stats), _max(max), _nameBegin(nameBegin), _nameEnd(nameEnd)
{
}

virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
{
osg::Geometry* geometry = const_cast<osg::Geometry*>(drawable->asGeometry());
if (!geometry) return;
osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
if (!vertices) return;

int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();

// Get stats
double value;
if (_nameEnd.empty())
{
if (!_stats->getAveragedAttribute( _nameBegin, value, true ))
{
value = 0.0;
}
}
else
{
double beginValue, endValue;
if (_stats->getAttribute( frameNumber, _nameBegin, beginValue) &&
_stats->getAttribute( frameNumber, _nameEnd, endValue) )
{
value = endValue - beginValue;
}
else
{
value = 0.0;
}
}

// Add new vertex for this frame.
value = osg::clampTo(value, 0.0, double(_max));
vertices->push_back(osg::Vec3(float(_curX), float(_height) / _max * value, 0));

// One vertex per pixel in X.
if (vertices->size() > _width)
{
unsigned int excedent = vertices->size() - _width;
vertices->erase(vertices->begin(), vertices->begin() + excedent);

// Make the graph scroll when there is enough data.
// Note: We check the frame number so that even if we have
// many graphs, the transform is translated only once per
// frame.
static const float increment = -1.0;
if (GraphUpdateCallback::_frameNumber != frameNumber)
{
// We know the exact layout of this part of the scene
// graph, so this is OK...
osg::MatrixTransform* transform =
geometry->getParent(0)->getParent(0)->asTransform()->asMatrixTransform();
if (transform)
{
transform->setMatrix(transform->getMatrix() * osg::Matrix::translate(osg::Vec3(increment, 0, 0)));
}
}
}
else
{
// Create primitive set if none exists.
if (geometry->getNumPrimitiveSets() == 0)
geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, 0, 0));

// Update primitive set.
osg::DrawArrays* drawArrays = dynamic_cast<osg::DrawArrays*>(geometry->getPrimitiveSet(0));
if (!drawArrays) return;
drawArrays->setFirst(0);
drawArrays->setCount(vertices->size());
}

_curX++;
GraphUpdateCallback::_frameNumber = frameNumber;

geometry->dirtyBound();

drawable->drawImplementation(renderInfo);
}

const unsigned int _width;
const unsigned int _height;
mutable unsigned int _curX;
osg::Stats* _viewerStats;
osg::Stats* _stats;
const float _max;
const std::string _nameBegin;
const std::string _nameEnd;
static int _frameNumber;
};
};

int StatsGraph::GraphUpdateCallback::_frameNumber = 0;


osg::Geometry* StatsHandler::createGeometry(const osg::Vec3& pos, float height, const osg::Vec4& colour, unsigned int numBlocks)
{
osg::Geometry* geometry = new osg::Geometry;

geometry->setUseDisplayList(false);

osg::Vec3Array* vertices = new osg::Vec3Array;
geometry->setVertexArray(vertices);
vertices->reserve(numBlocks*4);

for(unsigned int i=0; i<numBlocks; ++i)
{
vertices->push_back(pos+osg::Vec3(i*20, height, 0.0));
vertices->push_back(pos+osg::Vec3(i*20, 0.0, 0.0));
vertices->push_back(pos+osg::Vec3(i*20+10.0, 0.0, 0.0));
vertices->push_back(pos+osg::Vec3(i*20+10.0, height, 0.0));
}

osg::Vec4Array* colours = new osg::Vec4Array;
colours->push_back(colour);
geometry->setColorArray(colours);
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);

geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, numBlocks*4));

return geometry;
}


struct FrameMarkerDrawCallback : public virtual osg::Drawable::DrawCallback
{
FrameMarkerDrawCallback(StatsHandler* statsHandler, float xPos, osg::Stats* viewerStats, int frameDelta, int numFrames):
_statsHandler(statsHandler),
_xPos(xPos),
_viewerStats(viewerStats),
_frameDelta(frameDelta),
_numFrames(numFrames) {}

/** do customized draw code.*/
virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
{
osg::Geometry* geom = (osg::Geometry*)drawable;
osg::Vec3Array* vertices = (osg::Vec3Array*)geom->getVertexArray();

int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();

int startFrame = frameNumber + _frameDelta - _numFrames + 1;
int endFrame = frameNumber + _frameDelta;
double referenceTime;
if (!_viewerStats->getAttribute( startFrame, "Reference time", referenceTime))
{
return;
}

unsigned int vi = 0;
double currentReferenceTime;
for(int i = startFrame; i <= endFrame; ++i)
{
if (_viewerStats->getAttribute( i, "Reference time", currentReferenceTime))
{
(*vertices)[vi++].x() = _xPos + (currentReferenceTime - referenceTime) * _statsHandler->getBlockMultiplier();
(*vertices)[vi++].x() = _xPos + (currentReferenceTime - referenceTime) * _statsHandler->getBlockMultiplier();
}
}

drawable->drawImplementation(renderInfo);
}

StatsHandler* _statsHandler;
float _xPos;
osg::ref_ptr<osg::Stats> _viewerStats;
std::string _endName;
int _frameDelta;
int _numFrames;
};

struct PagerCallback : public virtual osg::NodeCallback
{

PagerCallback( osgDB::DatabasePager* dp,
osgText::Text* minValue,
osgText::Text* maxValue,
osgText::Text* averageValue,
osgText::Text* filerequestlist,
osgText::Text* compilelist,
double multiplier):
_dp(dp),
_minValue(minValue),
_maxValue(maxValue),
_averageValue(averageValue),
_filerequestlist(filerequestlist),
_compilelist(compilelist),
_multiplier(multiplier)
{
}

virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (_dp.valid())
{
double value = _dp->getAverageTimeToMergeTiles();
if (value>= 0.0 && value <= 1000)
{
sprintf(_tmpText,"%4.0f",value * _multiplier);
_averageValue->setText(_tmpText);
}
else
{
_averageValue->setText("");
}

value = _dp->getMinimumTimeToMergeTile();
if (value>= 0.0 && value <= 1000)
{
sprintf(_tmpText,"%4.0f",value * _multiplier);
_minValue->setText(_tmpText);
}
else
{
_minValue->setText("");
}

value = _dp->getMaximumTimeToMergeTile();
if (value>= 0.0 && value <= 1000)
{
sprintf(_tmpText,"%4.0f",value * _multiplier);
_maxValue->setText(_tmpText);
}
else
{
_maxValue->setText("");
}

sprintf(_tmpText,"%4d", _dp->getFileRequestListSize());
_filerequestlist->setText(_tmpText);

sprintf(_tmpText,"%4d", _dp->getDataToCompileListSize());
_compilelist->setText(_tmpText);
}

traverse(node,nv);
}

osg::observer_ptr<osgDB::DatabasePager> _dp;

osg::ref_ptr<osgText::Text> _minValue;
osg::ref_ptr<osgText::Text> _maxValue;
osg::ref_ptr<osgText::Text> _averageValue;
osg::ref_ptr<osgText::Text> _filerequestlist;
osg::ref_ptr<osgText::Text> _compilelist;
double _multiplier;
char _tmpText[128];
osg::Timer_t _tickLastUpdated;
};


osg::Geometry* StatsHandler::createFrameMarkers(const osg::Vec3& pos, float height, const osg::Vec4& colour, unsigned int numBlocks)
{
osg::Geometry* geometry = new osg::Geometry;

geometry->setUseDisplayList(false);

osg::Vec3Array* vertices = new osg::Vec3Array;
geometry->setVertexArray(vertices);
vertices->reserve(numBlocks*2);

for(unsigned int i=0; i<numBlocks; ++i)
{
vertices->push_back(pos+osg::Vec3(double(i)*_blockMultiplier*0.01, height, 0.0));
vertices->push_back(pos+osg::Vec3(double(i)*_blockMultiplier*0.01, 0.0, 0.0));
}

osg::Vec4Array* colours = new osg::Vec4Array;
colours->push_back(colour);
geometry->setColorArray(colours);
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);

geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, numBlocks*2));

return geometry;
}

osg::Geometry* StatsHandler::createTick(const osg::Vec3& pos, float height, const osg::Vec4& colour, unsigned int numTicks)
{
osg::Geometry* geometry = new osg::Geometry;

geometry->setUseDisplayList(false);

osg::Vec3Array* vertices = new osg::Vec3Array;
geometry->setVertexArray(vertices);
vertices->reserve(numTicks*2);

for(unsigned int i=0; i<numTicks; ++i)
{
float tickHeight = (i%10) ? height : height * 2.0;
vertices->push_back(pos+osg::Vec3(double(i)*_blockMultiplier*0.001, tickHeight , 0.0));
vertices->push_back(pos+osg::Vec3(double(i)*_blockMultiplier*0.001, 0.0, 0.0));
}

osg::Vec4Array* colours = new osg::Vec4Array;
colours->push_back(colour);
geometry->setColorArray(colours);
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);

geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, numTicks*2));

return geometry;
}

void StatsHandler::setUpScene(osgViewer::ViewerBase* viewer)
{
_switch = new osg::Switch;

_camera->addChild(_switch.get());

osg::StateSet* stateset = _switch->getOrCreateStateSet();
stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
stateset->setMode(GL_BLEND,osg::StateAttribute:ShockedN);
stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
stateset->setAttribute(new osg::PolygonMode(), osg::StateAttribute::PROTECTED);

std::string font("fonts/arial.ttf");


// collect all the relevant cameras
ViewerBase::Cameras validCameras;
viewer->getCameras(validCameras);

ViewerBase::Cameras cameras;
for(ViewerBase::Cameras::iterator itr = validCameras.begin();
itr != validCameras.end();
++itr)
{
if ((*itr)->getStats())
{
cameras.push_back(*itr);
}
}

// check for query time support
unsigned int numCamrasWithTimerQuerySupport = 0;
for(ViewerBase::Cameras::iterator citr = cameras.begin();
citr != cameras.end();
++citr)
{
if ((*citr)->getGraphicsContext())
{
unsigned int contextID = (*citr)->getGraphicsContext()->getState()->getContextID();
const osg::Drawable::Extensions* extensions = osg::Drawable::getExtensions(contextID, false);
if (extensions && extensions->isTimerQuerySupported())
{
++numCamrasWithTimerQuerySupport;
}
}
}

bool acquireGPUStats = numCamrasWithTimerQuerySupport==cameras.size();

float leftPos = 10.0f;
float startBlocks = 150.0f;
float characterSize = 20.0f;

osg::Vec3 pos(leftPos,1000.0f,0.0f);

osg::Vec4 colorFR(1.0f,1.0f,1.0f,1.0f);
osg::Vec4 colorFRAlpha(1.0f,1.0f,1.0f,0.5f);
osg::Vec4 colorUpdate( 0.0f,1.0f,0.0f,1.0f);
osg::Vec4 colorUpdateAlpha( 0.0f,1.0f,0.0f,0.5f);
osg::Vec4 colorEvent(0.0f, 1.0f, 0.5f, 1.0f);
osg::Vec4 colorEventAlpha(0.0f, 1.0f, 0.5f, 0.5f);
osg::Vec4 colorCull( 0.0f,1.0f,1.0f,1.0f);
osg::Vec4 colorCullAlpha( 0.0f,1.0f,1.0f,0.5f);
osg::Vec4 colorDraw( 1.0f,1.0f,0.0f,1.0f);
osg::Vec4 colorDrawAlpha( 1.0f,1.0f,0.0f,0.5f);
osg::Vec4 colorGPU( 1.0f,0.5f,0.0f,1.0f);
osg::Vec4 colorGPUAlpha( 1.0f,0.5f,0.0f,0.5f);

osg::Vec4 colorDP( 1.0f,1.0f,0.5f,1.0f);


// frame rate stats
{
osg::Geode* geode = new osg::Geode();
_frameRateChildNum = _switch->getNumChildren();
_switch->addChild(geode, false);

osg::ref_ptr<osgText::Text> frameRateLabel = new osgText::Text;
geode->addDrawable( frameRateLabel.get() );

frameRateLabel->setColor(colorFR);
frameRateLabel->setFont(font);
frameRateLabel->setCharacterSize(characterSize);
frameRateLabel->setPosition(pos);
frameRateLabel->setText("Frame Rate: ");

pos.x() = frameRateLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> frameRateValue = new osgText::Text;
geode->addDrawable( frameRateValue.get() );

frameRateValue->setColor(colorFR);
frameRateValue->setFont(font);
frameRateValue->setCharacterSize(characterSize);
frameRateValue->setPosition(pos);
frameRateValue->setText("0.0");

frameRateValue->setDrawCallback(new AveragedValueTextDrawCallback(viewer->getViewerStats(),"Frame rate",-1, true, 1.0));

pos.y() -= characterSize*1.5f;

}

osg::Vec4 backgroundColor(0.0, 0.0, 0.0f, 0.3);
osg::Vec4 staticTextColor(1.0, 1.0, 0.0f, 1.0);
osg::Vec4 dynamicTextColor(1.0, 1.0, 1.0f, 1.0);
float backgroundMargin = 5;
float backgroundSpacing = 3;


// viewer stats
{
osg::Group* group = new osg::Group;
_viewerChildNum = _switch->getNumChildren();
_switch->addChild(group, false);

osg::Geode* geode = new osg::Geode();
group->addChild(geode);


{
pos.x() = leftPos;

_threadingModelText = new osgText::Text;
geode->addDrawable( _threadingModelText.get() );

_threadingModelText->setColor(colorFR);
_threadingModelText->setFont(font);
_threadingModelText->setCharacterSize(characterSize);
_threadingModelText->setPosition(pos);

updateThreadingModelText();

pos.y() -= characterSize*1.5f;
}

float topOfViewerStats = pos.y() + characterSize;

geode->addDrawable(createBackgroundRectangle( pos + osg::Vec3(-backgroundMargin, characterSize + backgroundMargin, 0),
_camera->getViewport()->width() - 2 * backgroundMargin,
(3 + 4.5 * cameras.size()) * characterSize + 2 * backgroundMargin,
backgroundColor) );

{
pos.x() = leftPos;

osg::ref_ptr<osgText::Text> eventLabel = new osgText::Text;
geode->addDrawable( eventLabel.get() );

eventLabel->setColor(colorUpdate);
eventLabel->setFont(font);
eventLabel->setCharacterSize(characterSize);
eventLabel->setPosition(pos);
eventLabel->setText("Event: ");

pos.x() = eventLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> eventValue = new osgText::Text;
geode->addDrawable( eventValue.get() );

eventValue->setColor(colorUpdate);
eventValue->setFont(font);
eventValue->setCharacterSize(characterSize);
eventValue->setPosition(pos);
eventValue->setText("0.0");

eventValue->setDrawCallback(new AveragedValueTextDrawCallback(viewer->getViewerStats(),"Event traversal time taken",-1, false, 1000.0));

pos.x() = startBlocks;
osg::Geometry* geometry = createGeometry(pos, characterSize *0.8, colorUpdateAlpha, _numBlocks);
geometry->setDrawCallback(new BlockDrawCallback(this, startBlocks, viewer->getViewerStats(), viewer->getViewerStats(), "Event traversal begin time", "Event traversal end time", -1, _numBlocks));
geode->addDrawable(geometry);

pos.y() -= characterSize*1.5f;
}

{
pos.x() = leftPos;

osg::ref_ptr<osgText::Text> updateLabel = new osgText::Text;
geode->addDrawable( updateLabel.get() );

updateLabel->setColor(colorUpdate);
updateLabel->setFont(font);
updateLabel->setCharacterSize(characterSize);
updateLabel->setPosition(pos);
updateLabel->setText("Update: ");

pos.x() = updateLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> updateValue = new osgText::Text;
geode->addDrawable( updateValue.get() );

updateValue->setColor(colorUpdate);
updateValue->setFont(font);
updateValue->setCharacterSize(characterSize);
updateValue->setPosition(pos);
updateValue->setText("0.0");

updateValue->setDrawCallback(new AveragedValueTextDrawCallback(viewer->getViewerStats(),"Update traversal time taken",-1, false, 1000.0));

pos.x() = startBlocks;
osg::Geometry* geometry = createGeometry(pos, characterSize *0.8, colorUpdateAlpha, _numBlocks);
geometry->setDrawCallback(new BlockDrawCallback(this, startBlocks, viewer->getViewerStats(), viewer->getViewerStats(), "Update traversal begin time", "Update traversal end time", -1, _numBlocks));
geode->addDrawable(geometry);

pos.y() -= characterSize*1.5f;
}

pos.x() = leftPos;

// add camera stats
for(ViewerBase::Cameras::iterator citr = cameras.begin();
citr != cameras.end();
++citr)
{
group->addChild(createCameraTimeStats(font, pos, startBlocks, acquireGPUStats, characterSize, viewer->getViewerStats(), *citr));
}

// add frame ticks
{
osg::Geode* geode = new osg::Geode;
group->addChild(geode);

osg::Vec4 colourTicks(1.0f,1.0f,1.0f, 0.5f);

pos.x() = startBlocks;
pos.y() += characterSize;
float height = topOfViewerStats - pos.y();

osg::Geometry* ticks = createTick(pos, 5.0f, colourTicks, 100);
geode->addDrawable(ticks);

osg::Geometry* frameMarkers = createFrameMarkers(pos, height, colourTicks, _numBlocks + 1);
frameMarkers->setDrawCallback(new FrameMarkerDrawCallback(this, startBlocks, viewer->getViewerStats(), 0, _numBlocks + 1));
geode->addDrawable(frameMarkers);

pos.x() = leftPos;
}

// Stats line graph
{
pos.y() -= (backgroundSpacing + 2 * backgroundMargin);
float width = _camera->getViewport()->width() - 4 * backgroundMargin;
float height = 5 * characterSize;

// Create a stats graph and add any stats we want to track with it.
StatsGraph* statsGraph = new StatsGraph(pos, width, height);
group->addChild(statsGraph);

statsGraph->addStatGraph(viewer->getViewerStats(), viewer->getViewerStats(), colorFR, 100, "Frame rate");
statsGraph->addStatGraph(viewer->getViewerStats(), viewer->getViewerStats(), colorEvent, 0.016, "Event traversal time taken");
statsGraph->addStatGraph(viewer->getViewerStats(), viewer->getViewerStats(), colorUpdate, 0.016, "Update traversal time taken");

for(ViewerBase::Cameras::iterator citr = cameras.begin();
citr != cameras.end();
++citr)
{
statsGraph->addStatGraph(viewer->getViewerStats(), (*citr)->getStats(), colorCull, 0.016, "Cull traversal time taken");
statsGraph->addStatGraph(viewer->getViewerStats(), (*citr)->getStats(), colorDraw, 0.016, "Draw traversal time taken");
statsGraph->addStatGraph(viewer->getViewerStats(), (*citr)->getStats(), colorGPU, 0.016, "GPU draw time taken");
}

geode->addDrawable(createBackgroundRectangle( pos + osg::Vec3(-backgroundMargin, backgroundMargin, 0),
width + 2 * backgroundMargin,
height + 2 * backgroundMargin,
backgroundColor) );

pos.x() = leftPos;
pos.y() -= height + 2 * backgroundMargin;
}

// Databasepager stats
ViewerBase::Scenes scenes;
viewer->getScenes(scenes);
for(ViewerBase::Scenes::iterator itr = scenes.begin();
itr != scenes.end();
++itr)
{
Scene* scene = *itr;
osgDB::DatabasePager* dp = scene->getDatabasePager();
if (dp && dp->isRunning())
{
pos.y() -= (characterSize + backgroundSpacing);

geode->addDrawable(createBackgroundRectangle( pos + osg::Vec3(-backgroundMargin, characterSize + backgroundMargin, 0),
_camera->getViewport()->width() - 2 * backgroundMargin,
characterSize + 2 * backgroundMargin,
backgroundColor));

osg::ref_ptr<osgText::Text> averageLabel = new osgText::Text;
geode->addDrawable( averageLabel.get() );

averageLabel->setColor(colorDP);
averageLabel->setFont(font);
averageLabel->setCharacterSize(characterSize);
averageLabel->setPosition(pos);
averageLabel->setText("DatabasePager time to merge new tiles - average: ");

pos.x() = averageLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> averageValue = new osgText::Text;
geode->addDrawable( averageValue.get() );

averageValue->setColor(colorDP);
averageValue->setFont(font);
averageValue->setCharacterSize(characterSize);
averageValue->setPosition(pos);
averageValue->setText("1000");

pos.x() = averageValue->getBound().xMax() + 2.0f*characterSize;


osg::ref_ptr<osgText::Text> minLabel = new osgText::Text;
geode->addDrawable( minLabel.get() );

minLabel->setColor(colorDP);
minLabel->setFont(font);
minLabel->setCharacterSize(characterSize);
minLabel->setPosition(pos);
minLabel->setText("min: ");

pos.x() = minLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> minValue = new osgText::Text;
geode->addDrawable( minValue.get() );

minValue->setColor(colorDP);
minValue->setFont(font);
minValue->setCharacterSize(characterSize);
minValue->setPosition(pos);
minValue->setText("1000");

pos.x() = minValue->getBound().xMax() + 2.0f*characterSize;

osg::ref_ptr<osgText::Text> maxLabel = new osgText::Text;
geode->addDrawable( maxLabel.get() );

maxLabel->setColor(colorDP);
maxLabel->setFont(font);
maxLabel->setCharacterSize(characterSize);
maxLabel->setPosition(pos);
maxLabel->setText("max: ");

pos.x() = maxLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> maxValue = new osgText::Text;
geode->addDrawable( maxValue.get() );

maxValue->setColor(colorDP);
maxValue->setFont(font);
maxValue->setCharacterSize(characterSize);
maxValue->setPosition(pos);
maxValue->setText("1000");

pos.x() = maxValue->getBound().xMax();

osg::ref_ptr<osgText::Text> requestsLabel = new osgText::Text;
geode->addDrawable( requestsLabel.get() );

requestsLabel->setColor(colorDP);
requestsLabel->setFont(font);
requestsLabel->setCharacterSize(characterSize);
requestsLabel->setPosition(pos);
requestsLabel->setText("requests: ");

pos.x() = requestsLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> requestList = new osgText::Text;
geode->addDrawable( requestList.get() );

requestList->setColor(colorDP);
requestList->setFont(font);
requestList->setCharacterSize(characterSize);
requestList->setPosition(pos);
requestList->setText("0");

pos.x() = requestList->getBound().xMax() + 2.0f*characterSize;;

osg::ref_ptr<osgText::Text> compileLabel = new osgText::Text;
geode->addDrawable( compileLabel.get() );

compileLabel->setColor(colorDP);
compileLabel->setFont(font);
compileLabel->setCharacterSize(characterSize);
compileLabel->setPosition(pos);
compileLabel->setText("tocompile: ");

pos.x() = compileLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> compileList = new osgText::Text;
geode->addDrawable( compileList.get() );

compileList->setColor(colorDP);
compileList->setFont(font);
compileList->setCharacterSize(characterSize);
compileList->setPosition(pos);
compileList->setText("0");

pos.x() = maxLabel->getBound().xMax();

geode->setCullCallback(new PagerCallback(dp, minValue.get(), maxValue.get(), averageValue.get(), requestList.get(), compileList.get(), 1000.0));
}

pos.x() = leftPos;
}
}

// Camera scene stats
{
pos.y() -= (characterSize + backgroundSpacing + 2 * backgroundMargin);

osg::Group* group = new osg::Group;
_cameraSceneChildNum = _switch->getNumChildren();
_switch->addChild(group, false);

osg::Geode* geode = new osg::Geode();
geode->setCullingActive(false);
group->addChild(geode);
geode->addDrawable(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, characterSize + backgroundMargin, 0),
7 * characterSize + 2 * backgroundMargin,
19 * characterSize + 2 * backgroundMargin,
backgroundColor));

// Camera scene & primitive stats static text
osg::ref_ptr<osgText::Text> camStaticText = new osgText::Text;
geode->addDrawable( camStaticText.get() );
camStaticText->setColor(staticTextColor);
camStaticText->setFont(font);
camStaticText->setCharacterSize(characterSize);
camStaticText->setPosition(pos);

std::ostringstream viewStr;
viewStr.clear();
viewStr.setf(std::ios::left, std::ios::adjustfield);
viewStr.width(14);
viewStr << "Camera" << std::endl;
viewStr << "" << std::endl; // placeholder for Camera name
viewStr << "Vertices" << std::endl;
viewStr << "Drawables" << std::endl;
viewStr << "Lights" << std::endl;
viewStr << "Bins" << std::endl;
viewStr << "Depth" << std::endl;
viewStr << "Matrices" << std::endl;
viewStr << "Imposters" << std::endl;
viewStr << "Points" << std::endl;
viewStr << "Lines" << std::endl;
viewStr << "Line strips" << std::endl;
viewStr << "Line loops" << std::endl;
viewStr << "Triangles" << std::endl;
viewStr << "Tri. strips" << std::endl;
viewStr << "Tri. fans" << std::endl;
viewStr << "Quads" << std::endl;
viewStr << "Quad strips" << std::endl;
viewStr << "Polygons" << std::endl;
viewStr.setf(std::ios::right,std::ios::adjustfield);
camStaticText->setText(viewStr.str());

// Move camera block to the right
pos.x() += 7 * characterSize + 2 * backgroundMargin + backgroundSpacing;

// Add camera scene stats, one block per camera
int cameraCounter = 0;
for(ViewerBase::Cameras::iterator citr = cameras.begin(); citr != cameras.end(); ++citr)
{
geode->addDrawable(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, characterSize + backgroundMargin, 0),
5 * characterSize + 2 * backgroundMargin,
19 * characterSize + 2 * backgroundMargin,
backgroundColor));

// Camera scene stats
osg::ref_ptr<osgText::Text> camStatsText = new osgText::Text;
geode->addDrawable( camStatsText.get() );

camStatsText->setColor(dynamicTextColor);
camStatsText->setFont(font);
camStatsText->setCharacterSize(characterSize);
camStatsText->setPosition(pos);
camStatsText->setText("");
camStatsText->setDrawCallback(new CameraSceneStatsTextDrawCallback(*citr, cameraCounter));

// Move camera block to the right
pos.x() += 5 * characterSize + 2 * backgroundMargin + backgroundSpacing;
cameraCounter++;
}
}

// Viewer scene stats
{
osg::Group* group = new osg::Group;
_viewerSceneChildNum = _switch->getNumChildren();
_switch->addChild(group, false);

osg::Geode* geode = new osg::Geode();
geode->setCullingActive(false);
group->addChild(geode);

geode->addDrawable(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, characterSize + backgroundMargin, 0),
6 * characterSize + 2 * backgroundMargin,
12 * characterSize + 2 * backgroundMargin,
backgroundColor));

// View scene stats static text
osg::ref_ptr<osgText::Text> camStaticText = new osgText::Text;
geode->addDrawable( camStaticText.get() );
camStaticText->setColor(staticTextColor);
camStaticText->setFont(font);
camStaticText->setCharacterSize(characterSize);
camStaticText->setPosition(pos);

std::ostringstream viewStr;
viewStr.clear();
viewStr.setf(std::ios::left, std::ios::adjustfield);
viewStr.width(14);
viewStr << "View" << std::endl;
viewStr << " " << std::endl;
viewStr << "Stateset" << std::endl;
viewStr << "Group" << std::endl;
viewStr << "Transform" << std::endl;
viewStr << "LOD" << std::endl;
viewStr << "Switch" << std::endl;
viewStr << "Geode" << std::endl;
viewStr << "Drawable" << std::endl;
viewStr << "Geometry" << std::endl;
viewStr << "Vertices" << std::endl;
viewStr << "Primitives" << std::endl;
viewStr.setf(std::ios::right, std::ios::adjustfield);
camStaticText->setText(viewStr.str());

// Move viewer block to the right
pos.x() += 6 * characterSize + 2 * backgroundMargin + backgroundSpacing;

std::vector<osgViewer::View*> views;
viewer->getViews(views);

std::vector<osgViewer::View*>::iterator it;
int viewCounter = 0;
for (it = views.begin(); it != views.end(); ++it)
{
geode->addDrawable(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, characterSize + backgroundMargin, 0),
11 * characterSize + 2 * backgroundMargin,
12 * characterSize + 2 * backgroundMargin,
backgroundColor));

// Text for scene statistics
osgText::Text* text = new osgText::Text;
geode->addDrawable( text );

text->setColor(dynamicTextColor);
text->setFont(font);
text->setCharacterSize(characterSize);
text->setPosition(pos);
text->setDrawCallback(new ViewSceneStatsTextDrawCallback(*it, viewCounter));

pos.x() += 11 * characterSize + 2 * backgroundMargin + backgroundSpacing;
viewCounter++;
}
}
}

osg::Node* StatsHandler::createCameraTimeStats(const std::string& font, osg::Vec3& pos, float startBlocks, bool acquireGPUStats, float characterSize, osg::Stats* viewerStats, osg::Camera* camera)
{
osg::Stats* stats = camera->getStats();
if (!stats) return 0;

osg::Group* group = new osg::Group;

osg::Geode* geode = new osg::Geode();
group->addChild(geode);

float leftPos = pos.x();

osg::Vec4 colorCull( 0.0f,1.0f,1.0f,1.0f);
osg::Vec4 colorCullAlpha( 0.0f,1.0f,1.0f,0.5f);
osg::Vec4 colorDraw( 1.0f,1.0f,0.0f,1.0f);
osg::Vec4 colorDrawAlpha( 1.0f,1.0f,0.0f,0.5f);
osg::Vec4 colorGPU( 1.0f,0.5f,0.0f,1.0f);
osg::Vec4 colorGPUAlpha( 1.0f,0.5f,0.0f,0.5f);

{
pos.x() = leftPos;

osg::ref_ptr<osgText::Text> cullLabel = new osgText::Text;
geode->addDrawable( cullLabel.get() );

cullLabel->setColor(colorCull);
cullLabel->setFont(font);
cullLabel->setCharacterSize(characterSize);
cullLabel->setPosition(pos);
cullLabel->setText("Cull: ");

pos.x() = cullLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> cullValue = new osgText::Text;
geode->addDrawable( cullValue.get() );

cullValue->setColor(colorCull);
cullValue->setFont(font);
cullValue->setCharacterSize(characterSize);
cullValue->setPosition(pos);
cullValue->setText("0.0");

cullValue->setDrawCallback(new AveragedValueTextDrawCallback(stats,"Cull traversal time taken",-1, false, 1000.0));

pos.x() = startBlocks;
osg::Geometry* geometry = createGeometry(pos, characterSize *0.8, colorCullAlpha, _numBlocks);
geometry->setDrawCallback(new BlockDrawCallback(this, startBlocks, viewerStats, stats, "Cull traversal begin time", "Cull traversal end time", -1, _numBlocks));
geode->addDrawable(geometry);

pos.y() -= characterSize*1.5f;
}

{
pos.x() = leftPos;

osg::ref_ptr<osgText::Text> drawLabel = new osgText::Text;
geode->addDrawable( drawLabel.get() );

drawLabel->setColor(colorDraw);
drawLabel->setFont(font);
drawLabel->setCharacterSize(characterSize);
drawLabel->setPosition(pos);
drawLabel->setText("Draw: ");

pos.x() = drawLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> drawValue = new osgText::Text;
geode->addDrawable( drawValue.get() );

drawValue->setColor(colorDraw);
drawValue->setFont(font);
drawValue->setCharacterSize(characterSize);
drawValue->setPosition(pos);
drawValue->setText("0.0");

drawValue->setDrawCallback(new AveragedValueTextDrawCallback(stats,"Draw traversal time taken",-1, false, 1000.0));


pos.x() = startBlocks;
osg::Geometry* geometry = createGeometry(pos, characterSize *0.8, colorDrawAlpha, _numBlocks);
geometry->setDrawCallback(new BlockDrawCallback(this, startBlocks, viewerStats, stats, "Draw traversal begin time", "Draw traversal end time", -1, _numBlocks));
geode->addDrawable(geometry);

pos.y() -= characterSize*1.5f;
}

if (acquireGPUStats)
{
pos.x() = leftPos;

osg::ref_ptr<osgText::Text> gpuLabel = new osgText::Text;
geode->addDrawable( gpuLabel.get() );

gpuLabel->setColor(colorGPU);
gpuLabel->setFont(font);
gpuLabel->setCharacterSize(characterSize);
gpuLabel->setPosition(pos);
gpuLabel->setText("GPU: ");

pos.x() = gpuLabel->getBound().xMax();

osg::ref_ptr<osgText::Text> gpuValue = new osgText::Text;
geode->addDrawable( gpuValue.get() );

gpuValue->setColor(colorGPU);
gpuValue->setFont(font);
gpuValue->setCharacterSize(characterSize);
gpuValue->setPosition(pos);
gpuValue->setText("0.0");

gpuValue->setDrawCallback(new AveragedValueTextDrawCallback(stats,"GPU draw time taken",-1, false, 1000.0));

pos.x() = startBlocks;
osg::Geometry* geometry = createGeometry(pos, characterSize *0.8, colorGPUAlpha, _numBlocks);
geometry->setDrawCallback(new BlockDrawCallback(this, startBlocks, viewerStats, stats, "GPU draw begin time", "GPU draw end time", -1, _numBlocks));
geode->addDrawable(geometry);

pos.y() -= characterSize*1.5f;
}


pos.x() = leftPos;

return group;
}


void StatsHandler::getUsage(osg::ApplicationUsage& usage) const
{
usage.addKeyboardMouseBinding("s","On screen stats.");
usage.addKeyboardMouseBinding("S","Output stats to console.");
}

}

/* OpenSceneGraph example, osgcompositeviewer.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include <osgUtil/Optimizer>
#include <osgDB/ReadFile>

#include <osg/Material>
#include <osg/Geode>
#include <osg/BlendFunc>
#include <osg/Depth>
#include <osg/Projection>
#include <osg/PolygonOffset>
#include <osg/MatrixTransform>
#include <osg/Camera>
#include <osg/FrontFace>

#include <osgText/Text>

#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/StateSetManipulator>
#include <osgViewer/ViewerEventHandlers>

#include <osgViewer/CompositeViewer>

#include <osgFX/Scribe>

#include <osg/io_utils>

// class to handle events with a pick
class PickHandler : public osgGA::GUIEventHandler {
public:

PickHandler():
_mx(0.0f),
_my(0.0f) {}

~PickHandler() {}

bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
{
osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
if (!view) return false;

switch(ea.getEventType())
{
case(osgGA::GUIEventAdapter::PUSH):
{
_mx = ea.getX();
_my = ea.getY();
break;
}
case(osgGA::GUIEventAdapter::RELEASE):
{
if (_mx==ea.getX() && _my==ea.getY())
{
pick(view, ea.getX(), ea.getY());
}
break;
}
default:
break;
}
return false;
}

void pick(osgViewer::View* view, float x, float y)
{
osg::Node* node = 0;
osg::Group* parent = 0;

osgUtil::LineSegmentIntersector::Intersections intersections;
if (view->computeIntersections(x, y, intersections))
{
osgUtil::LineSegmentIntersector::Intersection intersection = *intersections.begin();
osg::NodePath& nodePath = intersection.nodePath;
node = (nodePath.size()>=1)?nodePath[nodePath.size()-1]:0;
parent = (nodePath.size()>=2)?dynamic_cast<osg::Group*>(nodePath[nodePath.size()-2]):0;
}

// now we try to decorate the hit node by the osgFX::Scribe to show that its been "picked"
if (parent && node)
{

osgFX::Scribe* parentAsScribe = dynamic_cast<osgFX::Scribe*>(parent);
if (!parentAsScribe)
{
// node not already picked, so highlight it with an osgFX::Scribe
osgFX::Scribe* scribe = new osgFX::Scribe();
scribe->addChild(node);
parent->replaceChild(node,scribe);
}
else
{
// node already picked so we want to remove scribe to unpick it.
osg::Node::ParentList parentList = parentAsScribe->getParents();
for(osg::Node::ParentList::iterator itr=parentList.begin();
itr!=parentList.end();
++itr)
{
(*itr)->replaceChild(parentAsScribe,node);
}
}
}

}

float _mx, _my;

};


int main( int argc, char **argv )
{

// use an ArgumentParser object to manage the program arguments.
osg::ArgumentParser arguments(&argc,argv);

// read the scene from the list of file specified commandline args.
osg::ref_ptr<osg::Node> scene = osgDB::readNodeFiles(arguments);

if (!scene) return 1;

// construct the viewer.
osgViewer::CompositeViewer viewer(arguments);




if (arguments.read("-1"))
{
{
osgViewer::View* view = new osgViewer::View;
view->setName("Single view");
view->setSceneData(osgDB::readNodeFile("fountain.osg"));

view->addEventHandler( new osgViewer::StatsHandler );

view->setUpViewAcrossAllScreens();
view->setCameraManipulator(new osgGA::TrackballManipulator);
viewer.addView(view);
}
}

if (arguments.read("-2"))
{

// view one
{
osgViewer::View* view = new osgViewer::View;
view->setName("View one");
viewer.addView(view);

view->setUpViewOnSingleScreen(0);
view->setSceneData(scene.get());
view->setCameraManipulator(new osgGA::TrackballManipulator);

// add the state manipulator
osg::ref_ptr<osgGA::StateSetManipulator> statesetManipulator = new osgGA::StateSetManipulator;
statesetManipulator->setStateSet(view->getCamera()->getOrCreateStateSet());

view->addEventHandler( statesetManipulator.get() );
}

// view two
{
osgViewer::View* view = new osgViewer::View;
view->setName("View two");
viewer.addView(view);

view->setUpViewOnSingleScreen(1);
view->setSceneData(scene.get());
view->setCameraManipulator(new osgGA::TrackballManipulator);

view->addEventHandler( new osgViewer::StatsHandler );


// add the handler for doing the picking
view->addEventHandler(new PickHandler());
}
}


if (arguments.read("-3") || viewer.getNumViews()==0)
{

osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
if (!wsi)
{
osg::notify(osg::NOTICE)<<"Error, no WindowSystemInterface available, cannot create windows."<<std::endl;
return 1;
}

unsigned int width, height;
wsi->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0), width, height);

osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
traits->x = 100;
traits->y = 100;
traits->width = 1000;
traits->height = 800;
traits->windowDecoration = true;
traits->doubleBuffer = true;
traits->sharedContext = 0;

osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
if (gc.valid())
{
osg::notify(osg::INFO)<<" GraphicsWindow has been created successfully."<<std::endl;

// need to ensure that the window is cleared make sure that the complete window is set the correct colour
// rather than just the parts of the window that are under the camera's viewports
gc->setClearColor(osg::Vec4f(0.2f,0.2f,0.6f,1.0f));
gc->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
else
{
osg::notify(osg::NOTICE)<<" GraphicsWindow has not been created successfully."<<std::endl;
}

// view one
{
osgViewer::View* view = new osgViewer::View;
view->setName("View one");
viewer.addView(view);

view->setSceneData(scene.get());
view->getCamera()->setName("Cam one");
view->getCamera()->setViewport(new osg::Viewport(0,0, traits->width/2, traits->height/2));
view->getCamera()->setGraphicsContext(gc.get());
view->setCameraManipulator(new osgGA::TrackballManipulator);

// add the state manipulator
osg::ref_ptr<osgGA::StateSetManipulator> statesetManipulator = new osgGA::StateSetManipulator;
statesetManipulator->setStateSet(view->getCamera()->getOrCreateStateSet());

view->addEventHandler( statesetManipulator.get() );

view->addEventHandler( new osgViewer::StatsHandler );
view->addEventHandler( new osgViewer::HelpHandler );
view->addEventHandler( new osgViewer::WindowSizeHandler );
view->addEventHandler( new osgViewer::ThreadingHandler );
view->addEventHandler( new osgViewer::RecordCameraPathHandler );
}

// view two
{
osgViewer::View* view = new osgViewer::View;
view->setName("View two");
viewer.addView(view);

view->setSceneData(scene.get());
view->getCamera()->setName("Cam two");
view->getCamera()->setViewport(new osg::Viewport(traits->width/2,0, traits->width/2, traits->height/2));
view->getCamera()->setGraphicsContext(gc.get());
view->setCameraManipulator(new osgGA::TrackballManipulator);

// add the handler for doing the picking
view->addEventHandler(new PickHandler());

}

// view three
{
osgViewer::View* view = new osgViewer::View;
view->setName("View three");
viewer.addView(view);

view->setSceneData(osgDB::readNodeFile("cessnafire.osg"));

view->getCamera()->setName("Cam three");
view->getCamera()->setProjectionMatrixAsPerspective(30.0, double(traits->width) / double(traits->height/2), 1.0, 1000.0);
view->getCamera()->setViewport(new osg::Viewport(0, traits->height/2, traits->width, traits->height/2));
view->getCamera()->setGraphicsContext(gc.get());
view->setCameraManipulator(new osgGA::TrackballManipulator);
}

}


while (arguments.read("-s")) { viewer.setThreadingModel(osgViewer::CompositeViewer::SingleThreaded); }
while (arguments.read("-g")) { viewer.setThreadingModel(osgViewer::CompositeViewer::CullDrawThreadPerContext); }
while (arguments.read("-c")) { viewer.setThreadingModel(osgViewer::CompositeViewer::CullThreadPerCameraDrawThreadPerContext); }

// run the viewer's main frame loop
return viewer.run();
}






------------------
Post generated by Mail2Forum
Back to top
Robert Osfield
Guest





PostPosted: Wed Jan 28, 2009 10:07 am    Post subject:
Statshandler layout fixes
Reply with quote

Hi Paul,

On Wed, Jan 28, 2009 at 9:25 AM, Robert Osfield
<> wrote:
Quote:
I have been able to reproduce the crash in osgcompositeviewer here so
I'll go see if I can fix.

This is now fixed and checked in.

osgcompositeviewer does reveal some the the top stats rectangle
doesn't scale correctly though.... fix one bug uncover another... The
unique vertex and primitive counts on the view are also not working
for some reason. I've added these to the BugResolution page as could
items as they won't break software by them not being perfect.

http://www.openscenegraph.org/projects/osg/wiki/Community/Tasks/BugResolution

I'm going to get back onto reviewing the two Should items, and will
leave the above could items till I've addressed these, others are
welcome to dive in a fix them though :-)

Robert.


------------------
Post generated by Mail2Forum
Back to top
osg-users
Guest





PostPosted: Wed Jan 28, 2009 12:07 pm    Post subject:
Statshandler layout fixes
Reply with quote

Quote:
Hi Paul,

On Wed, Jan 28, 2009 at 9:25 AM, Robert Osfield
<> wrote:
Quote:
I have been able to reproduce the crash in osgcompositeviewer here so
I'll go see if I can fix.

This is now fixed and checked in.

osgcompositeviewer does reveal some the the top stats rectangle
doesn't scale correctly though.... fix one bug uncover another... The
unique vertex and primitive counts on the view are also not working
for some reason. I've added these to the BugResolution page as could
items as they won't break software by them not being perfect.

Ok

Here's an updated version that
1) Changes the order of the camera stats slightly, to be more in line with
the view stats
2) Uses a slightly smaller block for view statistics

Paul


------------------
Post generated by Mail2Forum
Back to top
Robert Osfield
Guest





PostPosted: Wed Jan 28, 2009 1:38 pm    Post subject:
Statshandler layout fixes
Reply with quote

Thanks Paul, changes now merged and submitted to svn.

On Wed, Jan 28, 2009 at 12:07 PM, <> wrote:
Quote:
Quote:
Hi Paul,

On Wed, Jan 28, 2009 at 9:25 AM, Robert Osfield
<> wrote:
Quote:
I have been able to reproduce the crash in osgcompositeviewer here so
I'll go see if I can fix.

This is now fixed and checked in.

osgcompositeviewer does reveal some the the top stats rectangle
doesn't scale correctly though.... fix one bug uncover another... The
unique vertex and primitive counts on the view are also not working
for some reason. I've added these to the BugResolution page as could
items as they won't break software by them not being perfect.

Ok

Here's an updated version that
1) Changes the order of the camera stats slightly, to be more in line with
the view stats
2) Uses a slightly smaller block for view statistics

Paul





------------------
Post generated by Mail2Forum
Back to top
Display posts from previous:   
Post new topic   Reply to topic    OpenSceneGraph Forum Forum Index -> Submission All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum

Similar Topics
Topic Author Forum Replies Posted
No new posts [vpb] Command-line fixes robertosfield Submission 0 Mon Mar 12, 2018 4:11 pm View latest post
No new posts [vpb] Command-line fixes Andreas Ekstrand Submission 0 Sat Sep 30, 2017 2:56 pm View latest post
No new posts using modern shaders with osg - setti... antiro42 General 18 Fri Sep 01, 2017 9:30 am View latest post
No new posts Using StatsHandler rendering method Riccardo Corsi General 1 Tue Nov 29, 2016 3:59 pm View latest post
No new posts Typo fixes robertosfield Submission 0 Mon May 30, 2016 11:41 am View latest post


Board Security Anti Bot Question MOD - phpBB MOD against Spam Bots
Powered by phpBB © 2001, 2005 phpBB Group
Protected by Anti-Spam ACP