root/OpenSceneGraph/trunk/src/osgViewer/StatsHandler.cpp @ 13041

Revision 13041, 64.3 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#include <sstream>
15#include <iomanip>
16#include <stdio.h>
17
18#include <osg/io_utils>
19
20#include <osg/MatrixTransform>
21
22#include <osgViewer/ViewerEventHandlers>
23#include <osgViewer/Renderer>
24
25#include <osg/PolygonMode>
26#include <osg/Geometry>
27
28namespace osgViewer
29{
30
31
32StatsHandler::StatsHandler():
33    _keyEventTogglesOnScreenStats('s'),
34    _keyEventPrintsOutStats('S'),
35    _statsType(NO_STATS),
36    _initialized(false),
37    _threadingModel(ViewerBase::SingleThreaded),
38    _frameRateChildNum(0),
39    _viewerChildNum(0),
40    _cameraSceneChildNum(0),
41    _viewerSceneChildNum(0),
42    _numBlocks(8),
43    _blockMultiplier(10000.0),
44    _statsWidth(1280.0f),
45    _statsHeight(1024.0f),
46    _font("fonts/arial.ttf"),
47    _startBlocks(150.0f),
48    _leftPos(10.0f),
49    _characterSize(20.0f),
50    _lineHeight(1.5f)
51{
52    _camera = new osg::Camera;
53    _camera->setRenderer(new Renderer(_camera.get()));
54    _camera->setProjectionResizePolicy(osg::Camera::FIXED);
55}
56
57bool StatsHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
58{
59
60    osgViewer::View* myview = dynamic_cast<osgViewer::View*>(&aa);
61    if (!myview) return false;
62
63    osgViewer::ViewerBase* viewer = myview->getViewerBase();
64    if (viewer && _threadingModelText.valid() && viewer->getThreadingModel()!=_threadingModel)
65    {
66        _threadingModel = viewer->getThreadingModel();
67        updateThreadingModelText();
68    }
69
70
71    if (ea.getHandled()) return false;
72
73    switch(ea.getEventType())
74    {
75        case(osgGA::GUIEventAdapter::KEYDOWN):
76        {
77            if (ea.getKey()==_keyEventTogglesOnScreenStats)
78            {
79                if (viewer->getViewerStats())
80                {
81                    if (!_initialized)
82                    {
83                        setUpHUDCamera(viewer);
84                        setUpScene(viewer);
85                    }
86
87                    ++_statsType;
88
89                    if (_statsType==LAST) _statsType = NO_STATS;
90
91                    osgViewer::ViewerBase::Cameras cameras;
92                    viewer->getCameras(cameras);
93
94                    switch(_statsType)
95                    {
96                        case(NO_STATS):
97                        {
98                            viewer->getViewerStats()->collectStats("frame_rate",false);
99                            viewer->getViewerStats()->collectStats("event",false);
100                            viewer->getViewerStats()->collectStats("update",false);
101
102                            for(osgViewer::ViewerBase::Cameras::iterator itr = cameras.begin();
103                                itr != cameras.end();
104                                ++itr)
105                            {
106                                osg::Stats* stats = (*itr)->getStats();
107                                if (stats)
108                                {
109                                    stats->collectStats("rendering",false);
110                                    stats->collectStats("gpu",false);
111                                    stats->collectStats("scene",false);
112                                }
113                            }
114
115                            viewer->getViewerStats()->collectStats("scene",false);
116
117                            _camera->setNodeMask(0x0);
118                            _switch->setAllChildrenOff();
119                            break;
120                        }
121                        case(FRAME_RATE):
122                        {
123                            viewer->getViewerStats()->collectStats("frame_rate",true);
124
125                            _camera->setNodeMask(0xffffffff);
126                            _switch->setValue(_frameRateChildNum, true);
127                            break;
128                        }
129                        case(VIEWER_STATS):
130                        {
131                            ViewerBase::Scenes scenes;
132                            viewer->getScenes(scenes);
133                            for(ViewerBase::Scenes::iterator itr = scenes.begin();
134                                itr != scenes.end();
135                                ++itr)
136                            {
137                                Scene* scene = *itr;
138                                osgDB::DatabasePager* dp = scene->getDatabasePager();
139                                if (dp && dp->isRunning())
140                                {
141                                    dp->resetStats();
142                                }
143                            }
144
145                            viewer->getViewerStats()->collectStats("event",true);
146                            viewer->getViewerStats()->collectStats("update",true);
147
148                            for(osgViewer::ViewerBase::Cameras::iterator itr = cameras.begin();
149                                itr != cameras.end();
150                                ++itr)
151                            {
152                                if ((*itr)->getStats()) (*itr)->getStats()->collectStats("rendering",true);
153                                if ((*itr)->getStats()) (*itr)->getStats()->collectStats("gpu",true);
154                            }
155
156                            _camera->setNodeMask(0xffffffff);
157                            _switch->setValue(_viewerChildNum, true);
158                            break;
159                        }
160                        case(CAMERA_SCENE_STATS):
161                        {
162                            _camera->setNodeMask(0xffffffff);
163                            _switch->setValue(_cameraSceneChildNum, true);
164
165                            for(osgViewer::ViewerBase::Cameras::iterator itr = cameras.begin();
166                                itr != cameras.end();
167                                ++itr)
168                            {
169                                osg::Stats* stats = (*itr)->getStats();
170                                if (stats)
171                                {
172                                    stats->collectStats("scene",true);
173                                }
174                            }
175
176                            break;
177                        }
178                        case(VIEWER_SCENE_STATS):
179                        {
180                            _camera->setNodeMask(0xffffffff);
181                            _switch->setValue(_viewerSceneChildNum, true);
182
183                            viewer->getViewerStats()->collectStats("scene",true);
184
185                            break;
186                        }
187                        default:
188                            break;
189                    }
190
191                    aa.requestRedraw();
192                }
193                return true;
194            }
195            if (ea.getKey()==_keyEventPrintsOutStats)
196            {
197                if (viewer->getViewerStats())
198                {
199                    OSG_NOTICE<<std::endl<<"Stats report:"<<std::endl;
200                    typedef std::vector<osg::Stats*> StatsList;
201                    StatsList statsList;
202                    statsList.push_back(viewer->getViewerStats());
203
204                    osgViewer::ViewerBase::Contexts contexts;
205                    viewer->getContexts(contexts);
206                    for(osgViewer::ViewerBase::Contexts::iterator gcitr = contexts.begin();
207                        gcitr != contexts.end();
208                        ++gcitr)
209                    {
210                        osg::GraphicsContext::Cameras& cameras = (*gcitr)->getCameras();
211                        for(osg::GraphicsContext::Cameras::iterator itr = cameras.begin();
212                            itr != cameras.end();
213                            ++itr)
214                        {
215                            if ((*itr)->getStats())
216                            {
217                                statsList.push_back((*itr)->getStats());
218                            }
219                        }
220                    }
221
222                    for(unsigned int i = viewer->getViewerStats()->getEarliestFrameNumber(); i< viewer->getViewerStats()->getLatestFrameNumber(); ++i)
223                    {
224                        for(StatsList::iterator itr = statsList.begin();
225                            itr != statsList.end();
226                            ++itr)
227                        {
228                            if (itr==statsList.begin()) (*itr)->report(osg::notify(osg::NOTICE), i);
229                            else (*itr)->report(osg::notify(osg::NOTICE), i, "    ");
230                        }
231                        OSG_NOTICE<<std::endl;
232                    }
233
234                }
235                return true;
236            }
237        }
238        case(osgGA::GUIEventAdapter::RESIZE):
239            setWindowSize(ea.getWindowWidth(), ea.getWindowHeight());
240            break;
241        default: break;
242    }
243
244    return false;
245
246}
247
248void StatsHandler::updateThreadingModelText()
249{
250    switch(_threadingModel)
251    {
252        case(osgViewer::Viewer::SingleThreaded): _threadingModelText->setText("ThreadingModel: SingleThreaded"); break;
253        case(osgViewer::Viewer::CullDrawThreadPerContext): _threadingModelText->setText("ThreadingModel: CullDrawThreadPerContext"); break;
254        case(osgViewer::Viewer::DrawThreadPerContext): _threadingModelText->setText("ThreadingModel: DrawThreadPerContext"); break;
255        case(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext): _threadingModelText->setText("ThreadingModel: CullThreadPerCameraDrawThreadPerContext"); break;
256        case(osgViewer::Viewer::AutomaticSelection): _threadingModelText->setText("ThreadingModel: AutomaticSelection"); break;
257        default:
258            _threadingModelText->setText("ThreadingModel: unknown"); break;
259    }
260}
261
262void StatsHandler::reset()
263{
264    _initialized = false;
265    _camera->setGraphicsContext(0);
266    _camera->removeChildren( 0, _camera->getNumChildren() );
267}
268
269void StatsHandler::addUserStatsLine(const std::string& label, const osg::Vec4& textColor, const osg::Vec4& barColor,
270                                    const std::string& timeTakenName, float multiplier, bool average, bool averageInInverseSpace,
271                                    const std::string& beginTimeName, const std::string& endTimeName, float maxValue)
272{
273    _userStatsLines.push_back(UserStatsLine(label, textColor, barColor, timeTakenName, multiplier, average, averageInInverseSpace, beginTimeName, endTimeName, maxValue));
274    reset();        // Rebuild the stats display with the new user stats line.
275}
276
277void StatsHandler::removeUserStatsLine(const std::string& label)
278{
279    // Hopefully the labels are unique... This could be enforced.
280    for (unsigned int i = 0; i < _userStatsLines.size(); ++i)
281    {
282        if (_userStatsLines[i].label == label)
283        {
284            _userStatsLines.erase(_userStatsLines.begin() + i);
285            reset();        // Rebuild the stats display without the removed user stats line.
286            break;
287        }
288    }
289}
290
291void StatsHandler::setUpHUDCamera(osgViewer::ViewerBase* viewer)
292{
293    // Try GraphicsWindow first so we're likely to get the main viewer window
294    osg::GraphicsContext* context = dynamic_cast<osgViewer::GraphicsWindow*>(_camera->getGraphicsContext());
295
296    if (!context)
297    {
298        osgViewer::Viewer::Windows windows;
299        viewer->getWindows(windows);
300
301        if (!windows.empty()) context = windows.front();
302        else
303        {
304            // No GraphicsWindows were found, so let's try to find a GraphicsContext
305            context = _camera->getGraphicsContext();
306
307            if (!context)
308            {
309                osgViewer::Viewer::Contexts contexts;
310                viewer->getContexts(contexts);
311
312                if (contexts.empty()) return;
313
314                context = contexts.front();
315            }
316        }
317    }
318
319    _camera->setGraphicsContext(context);
320
321    _camera->setRenderOrder(osg::Camera::POST_RENDER, 10);
322
323    _camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
324    _camera->setViewMatrix(osg::Matrix::identity());
325    setWindowSize(context->getTraits()->width, context->getTraits()->height);
326
327    // only clear the depth buffer
328    _camera->setClearMask(0);
329
330    _camera->setRenderer(new Renderer(_camera.get()));
331
332    _initialized = true;
333}
334
335void StatsHandler::setWindowSize(int width, int height)
336{
337    if (width <= 0 || height <= 0)
338        return;
339
340    _camera->setViewport(0, 0, width, height);
341    if (fabs(height*_statsWidth) <= fabs(width*_statsHeight))
342    {
343        _camera->setProjectionMatrix(osg::Matrix::ortho2D(0.0,width*_statsHeight/height,0.0,_statsHeight));
344    }
345    else
346    {
347        _camera->setProjectionMatrix(osg::Matrix::ortho2D(0.0,_statsWidth,_statsHeight-height*_statsWidth/width,_statsHeight));
348    }
349}
350
351// Drawcallback to draw averaged attribute
352struct AveragedValueTextDrawCallback : public virtual osg::Drawable::DrawCallback
353{
354    AveragedValueTextDrawCallback(osg::Stats* stats, const std::string& name, int frameDelta, bool averageInInverseSpace, double multiplier):
355        _stats(stats),
356        _attributeName(name),
357        _frameDelta(frameDelta),
358        _averageInInverseSpace(averageInInverseSpace),
359        _multiplier(multiplier),
360        _tickLastUpdated(0)
361    {
362    }
363
364    /** do customized draw code.*/
365    virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
366    {
367        osgText::Text* text = (osgText::Text*)drawable;
368
369        osg::Timer_t tick = osg::Timer::instance()->tick();
370        double delta = osg::Timer::instance()->delta_m(_tickLastUpdated, tick);
371
372        if (delta>50) // update every 50ms
373        {
374            _tickLastUpdated = tick;
375            double value;
376            if (_stats->getAveragedAttribute( _attributeName, value, _averageInInverseSpace))
377            {
378                char tmpText[128];
379                sprintf(tmpText,"%4.2f",value * _multiplier);
380                text->setText(tmpText);
381            }
382            else
383            {
384                text->setText("");
385            }
386        }
387        text->drawImplementation(renderInfo);
388    }
389
390    osg::ref_ptr<osg::Stats>    _stats;
391    std::string                 _attributeName;
392    int                         _frameDelta;
393    bool                        _averageInInverseSpace;
394    double                      _multiplier;
395    mutable osg::Timer_t        _tickLastUpdated;
396};
397
398// Drawcallback to draw raw attribute
399struct RawValueTextDrawCallback : public virtual osg::Drawable::DrawCallback
400{
401    RawValueTextDrawCallback(osg::Stats* stats, const std::string& name, int frameDelta, double multiplier):
402        _stats(stats),
403        _attributeName(name),
404        _frameDelta(frameDelta),
405        _multiplier(multiplier),
406        _tickLastUpdated(0)
407    {
408    }
409
410    /** do customized draw code.*/
411    virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
412    {
413        osgText::Text* text = (osgText::Text*)drawable;
414
415        osg::Timer_t tick = osg::Timer::instance()->tick();
416        double delta = osg::Timer::instance()->delta_m(_tickLastUpdated, tick);
417
418        if (delta>50) // update every 50ms
419        {
420            _tickLastUpdated = tick;
421
422            unsigned int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();
423            double value;
424            if (_stats->getAttribute(frameNumber, _attributeName, value))
425            {
426                char tmpText[128];
427                sprintf(tmpText,"%4.2f",value * _multiplier);
428                text->setText(tmpText);
429            }
430            else
431            {
432                text->setText("");
433            }
434        }
435        text->drawImplementation(renderInfo);
436    }
437
438    osg::ref_ptr<osg::Stats>    _stats;
439    std::string                 _attributeName;
440    int                         _frameDelta;
441    double                      _multiplier;
442    mutable osg::Timer_t        _tickLastUpdated;
443};
444
445struct CameraSceneStatsTextDrawCallback : public virtual osg::Drawable::DrawCallback
446{
447    CameraSceneStatsTextDrawCallback(osg::Camera* camera, int cameraNumber):
448        _camera(camera),
449        _tickLastUpdated(0),
450        _cameraNumber(cameraNumber)
451    {
452    }
453
454    /** do customized draw code.*/
455    virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
456    {
457        if (!_camera) return;
458
459        osgText::Text* text = (osgText::Text*)drawable;
460
461        osg::Timer_t tick = osg::Timer::instance()->tick();
462        double delta = osg::Timer::instance()->delta_m(_tickLastUpdated, tick);
463
464        if (delta > 100) // update every 100ms
465        {
466            _tickLastUpdated = tick;
467            std::ostringstream viewStr;
468            viewStr.clear();
469
470            osg::Stats* stats = _camera->getStats();
471            osgViewer::Renderer* renderer = dynamic_cast<osgViewer::Renderer*>(_camera->getRenderer());
472
473            if (stats && renderer)
474            {
475                viewStr.setf(std::ios::left, std::ios::adjustfield);
476                viewStr.width(14);
477                // Used fixed formatting, as scientific will switch to "...e+.." notation for
478                // large numbers of vertices/drawables/etc.
479                viewStr.setf(std::ios::fixed);
480                viewStr.precision(0);
481
482                viewStr << std::setw(1) << "#" << _cameraNumber << std::endl;
483
484                // Camera name
485                if (!_camera->getName().empty())
486                    viewStr << _camera->getName();
487                viewStr << std::endl;
488
489                unsigned int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();
490                if (!(renderer->getGraphicsThreadDoesCull()))
491                {
492                    --frameNumber;
493                }
494
495                #define STATS_ATTRIBUTE(str) \
496                    if (stats->getAttribute(frameNumber, str, value)) \
497                        viewStr << std::setw(8) << value << std::endl; \
498                    else \
499                        viewStr << std::setw(8) << "." << std::endl; \
500
501                double value = 0.0;
502
503                STATS_ATTRIBUTE("Visible number of lights")
504                STATS_ATTRIBUTE("Visible number of render bins")
505                STATS_ATTRIBUTE("Visible depth")
506                STATS_ATTRIBUTE("Number of StateGraphs")
507                STATS_ATTRIBUTE("Visible number of impostors")
508                STATS_ATTRIBUTE("Visible number of drawables")
509                STATS_ATTRIBUTE("Number of ordered leaves")
510                STATS_ATTRIBUTE("Visible number of fast drawables")
511                STATS_ATTRIBUTE("Visible vertex count")
512
513                STATS_ATTRIBUTE("Visible number of PrimitiveSets")
514                STATS_ATTRIBUTE("Visible number of GL_POINTS")
515                STATS_ATTRIBUTE("Visible number of GL_LINES")
516                STATS_ATTRIBUTE("Visible number of GL_LINE_STRIP")
517                STATS_ATTRIBUTE("Visible number of GL_LINE_LOOP")
518                STATS_ATTRIBUTE("Visible number of GL_TRIANGLES")
519                STATS_ATTRIBUTE("Visible number of GL_TRIANGLE_STRIP")
520                STATS_ATTRIBUTE("Visible number of GL_TRIANGLE_FAN")
521                STATS_ATTRIBUTE("Visible number of GL_QUADS")
522                STATS_ATTRIBUTE("Visible number of GL_QUAD_STRIP")
523                STATS_ATTRIBUTE("Visible number of GL_POLYGON")
524
525                text->setText(viewStr.str());
526            }
527        }
528        text->drawImplementation(renderInfo);
529    }
530
531    osg::observer_ptr<osg::Camera>  _camera;
532    mutable osg::Timer_t            _tickLastUpdated;
533    int                             _cameraNumber;
534};
535
536
537struct ViewSceneStatsTextDrawCallback : public virtual osg::Drawable::DrawCallback
538{
539    ViewSceneStatsTextDrawCallback(osgViewer::View* view, int viewNumber):
540        _view(view),
541        _tickLastUpdated(0),
542        _viewNumber(viewNumber)
543    {
544    }
545
546    /** do customized draw code.*/
547    virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
548    {
549        if (!_view) return;
550
551        osgText::Text* text = (osgText::Text*)drawable;
552
553        osg::Timer_t tick = osg::Timer::instance()->tick();
554        double delta = osg::Timer::instance()->delta_m(_tickLastUpdated, tick);
555
556        if (delta > 200) // update every 100ms
557        {
558            _tickLastUpdated = tick;
559            osg::Stats* stats = _view->getStats();
560            if (stats)
561            {
562                std::ostringstream viewStr;
563                viewStr.clear();
564                viewStr.setf(std::ios::left, std::ios::adjustfield);
565                viewStr.width(20);
566                viewStr.setf(std::ios::fixed);
567                viewStr.precision(0);
568
569                viewStr << std::setw(1) << "#" << _viewNumber;
570
571                // View name
572                if (!_view->getName().empty())
573                    viewStr << ": " << _view->getName();
574                viewStr << std::endl;
575
576                unsigned int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();
577                // if (!(renderer->getGraphicsThreadDoesCull()))
578                {
579                    --frameNumber;
580                }
581
582                #define STATS_ATTRIBUTE_PAIR(str1, str2) \
583                    if (stats->getAttribute(frameNumber, str1, value)) \
584                        viewStr << std::setw(9) << value; \
585                    else \
586                        viewStr << std::setw(9) << "."; \
587                    if (stats->getAttribute(frameNumber, str2, value)) \
588                        viewStr << std::setw(9) << value << std::endl; \
589                    else \
590                        viewStr << std::setw(9) << "." << std::endl; \
591
592                double value = 0.0;
593
594                // header
595                viewStr << std::setw(9) << "Unique" << std::setw(9) << "Instance" << std::endl;
596
597                STATS_ATTRIBUTE_PAIR("Number of unique StateSet","Number of instanced Stateset")
598                STATS_ATTRIBUTE_PAIR("Number of unique Group","Number of instanced Group")
599                STATS_ATTRIBUTE_PAIR("Number of unique Transform","Number of instanced Transform")
600                STATS_ATTRIBUTE_PAIR("Number of unique LOD","Number of instanced LOD")
601                STATS_ATTRIBUTE_PAIR("Number of unique Switch","Number of instanced Switch")
602                STATS_ATTRIBUTE_PAIR("Number of unique Geode","Number of instanced Geode")
603                STATS_ATTRIBUTE_PAIR("Number of unique Drawable","Number of instanced Drawable")
604                STATS_ATTRIBUTE_PAIR("Number of unique Geometry","Number of instanced Geometry")
605                STATS_ATTRIBUTE_PAIR("Number of unique Vertices","Number of instanced Vertices")
606                STATS_ATTRIBUTE_PAIR("Number of unique Primitives","Number of instanced Primitives")
607
608
609                text->setText(viewStr.str());
610            }
611            else
612            {
613                OSG_WARN<<std::endl<<"No valid view to collect scene stats from"<<std::endl;
614
615                text->setText("");
616            }
617        }
618        text->drawImplementation(renderInfo);
619    }
620
621    osg::observer_ptr<osgViewer::View>  _view;
622    mutable osg::Timer_t                _tickLastUpdated;
623    int                                 _viewNumber;
624};
625
626struct BlockDrawCallback : public virtual osg::Drawable::DrawCallback
627{
628    BlockDrawCallback(StatsHandler* statsHandler, float xPos, osg::Stats* viewerStats, osg::Stats* stats, const std::string& beginName, const std::string& endName, int frameDelta, int numFrames):
629        _statsHandler(statsHandler),
630        _xPos(xPos),
631        _viewerStats(viewerStats),
632        _stats(stats),
633        _beginName(beginName),
634        _endName(endName),
635        _frameDelta(frameDelta),
636        _numFrames(numFrames) {}
637
638    /** do customized draw code.*/
639    virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
640    {
641        osg::Geometry* geom = (osg::Geometry*)drawable;
642        osg::Vec3Array* vertices = (osg::Vec3Array*)geom->getVertexArray();
643
644        int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();
645        int startFrame = frameNumber + _frameDelta - _numFrames + 1;
646        int endFrame = frameNumber + _frameDelta;
647        double referenceTime;
648        if (!_viewerStats->getAttribute( startFrame, "Reference time", referenceTime))
649        {
650            return;
651        }
652
653        unsigned int vi = 0;
654        double beginValue, endValue;
655        for(int i = startFrame; i <= endFrame; ++i)
656        {
657            if (_stats->getAttribute( i, _beginName, beginValue) &&
658                _stats->getAttribute( i, _endName, endValue) )
659            {
660                (*vertices)[vi++].x() = _xPos + (beginValue - referenceTime) * _statsHandler->getBlockMultiplier();
661                (*vertices)[vi++].x() = _xPos + (beginValue - referenceTime) * _statsHandler->getBlockMultiplier();
662                (*vertices)[vi++].x() = _xPos + (endValue - referenceTime) * _statsHandler->getBlockMultiplier();
663                (*vertices)[vi++].x() = _xPos + (endValue - referenceTime) * _statsHandler->getBlockMultiplier();
664            }
665        }
666
667        osg::DrawArrays* drawArrays = static_cast<osg::DrawArrays*>(geom->getPrimitiveSet(0));
668        drawArrays->setCount(vi);
669
670        drawable->drawImplementation(renderInfo);
671    }
672
673    StatsHandler*               _statsHandler;
674    float                       _xPos;
675    osg::ref_ptr<osg::Stats>    _viewerStats;
676    osg::ref_ptr<osg::Stats>    _stats;
677    std::string                 _beginName;
678    std::string                 _endName;
679    int                         _frameDelta;
680    int                         _numFrames;
681};
682
683osg::Geometry* StatsHandler::createBackgroundRectangle(const osg::Vec3& pos, const float width, const float height, osg::Vec4& color)
684{
685    osg::StateSet *ss = new osg::StateSet;
686
687    osg::Geometry* geometry = new osg::Geometry;
688
689    geometry->setUseDisplayList(false);
690    geometry->setStateSet(ss);
691
692    osg::Vec3Array* vertices = new osg::Vec3Array;
693    geometry->setVertexArray(vertices);
694
695    vertices->push_back(osg::Vec3(pos.x(), pos.y(), 0));
696    vertices->push_back(osg::Vec3(pos.x(), pos.y()-height,0));
697    vertices->push_back(osg::Vec3(pos.x()+width, pos.y()-height,0));
698    vertices->push_back(osg::Vec3(pos.x()+width, pos.y(),0));
699
700    osg::Vec4Array* colors = new osg::Vec4Array;
701    colors->push_back(color);
702    geometry->setColorArray(colors);
703    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
704
705    osg::DrawElementsUShort *base =  new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_FAN,0);
706    base->push_back(0);
707    base->push_back(1);
708    base->push_back(2);
709    base->push_back(3);
710
711    geometry->addPrimitiveSet(base);
712
713    return geometry;
714}
715
716
717struct StatsGraph : public osg::MatrixTransform
718{
719    StatsGraph(osg::Vec3 pos, float width, float height)
720        : _pos(pos), _width(width), _height(height),
721          _statsGraphGeode(new osg::Geode)
722    {
723        _pos -= osg::Vec3(0, height, 0.1);
724        setMatrix(osg::Matrix::translate(_pos));
725        addChild(_statsGraphGeode.get());
726    }
727
728    void addStatGraph(osg::Stats* viewerStats, osg::Stats* stats, const osg::Vec4& color, float max, const std::string& nameBegin, const std::string& nameEnd = "")
729    {
730        _statsGraphGeode->addDrawable(new Graph(_pos, _width, _height, viewerStats, stats, color, max, nameBegin, nameEnd));
731    }
732
733    osg::Vec3           _pos;
734    float               _width;
735    float               _height;
736
737    osg::ref_ptr<osg::Geode> _statsGraphGeode;
738
739protected:
740    struct Graph : public osg::Geometry
741    {
742        Graph(const osg::Vec3& pos, float width, float height, osg::Stats* viewerStats, osg::Stats* stats,
743              const osg::Vec4& color, float max, const std::string& nameBegin, const std::string& nameEnd = "")
744        {
745            setUseDisplayList(false);
746
747            setVertexArray(new osg::Vec3Array);
748
749            osg::Vec4Array* colors = new osg::Vec4Array;
750            colors->push_back(color);
751            setColorArray(colors);
752            setColorBinding(osg::Geometry::BIND_OVERALL);
753
754            setDrawCallback(new GraphUpdateCallback(pos, width, height, viewerStats, stats, max, nameBegin, nameEnd));
755        }
756    };
757
758    struct GraphUpdateCallback : public osg::Drawable::DrawCallback
759    {
760        GraphUpdateCallback(const osg::Vec3& pos, float width, float height, osg::Stats* viewerStats, osg::Stats* stats,
761                            float max, const std::string& nameBegin, const std::string& nameEnd = "")
762            : _pos(pos), _width((unsigned int)width), _height((unsigned int)height), _curX(0),
763              _viewerStats(viewerStats), _stats(stats), _max(max), _nameBegin(nameBegin), _nameEnd(nameEnd)
764        {
765        }
766
767        virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
768        {
769            osg::Geometry* geometry = const_cast<osg::Geometry*>(drawable->asGeometry());
770            if (!geometry) return;
771            osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
772            if (!vertices) return;
773
774            unsigned int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();
775
776            // Get stats
777            double value;
778            if (_nameEnd.empty())
779            {
780                if (!_stats->getAveragedAttribute( _nameBegin, value, true ))
781                {
782                    value = 0.0;
783                }
784            }
785            else
786            {
787                double beginValue, endValue;
788                if (_stats->getAttribute( frameNumber, _nameBegin, beginValue) &&
789                    _stats->getAttribute( frameNumber, _nameEnd, endValue) )
790                {
791                    value = endValue - beginValue;
792                }
793                else
794                {
795                    value = 0.0;
796                }
797            }
798
799            // Add new vertex for this frame.
800            value = osg::clampTo(value, 0.0, double(_max));
801            vertices->push_back(osg::Vec3(float(_curX), float(_height) / _max * value, 0));
802
803            // One vertex per pixel in X.
804            int excedent = vertices->size() - _width;
805            if (excedent > 0)
806            {
807                vertices->erase(vertices->begin(), vertices->begin() + excedent);
808            }
809
810            // Create primitive set if none exists.
811            if (geometry->getNumPrimitiveSets() == 0)
812                geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, 0, 0));
813
814            // Update primitive set.
815            osg::DrawArrays* drawArrays = dynamic_cast<osg::DrawArrays*>(geometry->getPrimitiveSet(0));
816            if (!drawArrays) return;
817            drawArrays->setFirst(0);
818            drawArrays->setCount(vertices->size());
819
820            // Make the graph scroll when there is enough data.
821            // Note: We check the frame number so that even if we have
822            // many graphs, the transform is translated only once per
823            // frame.
824            //static const float increment = -1.0;
825            if (GraphUpdateCallback::_frameNumber != frameNumber)
826            {
827                // We know the exact layout of this part of the scene
828                // graph, so this is OK...
829                osg::MatrixTransform* transform =
830                    geometry->getParent(0)->getParent(0)->asTransform()->asMatrixTransform();
831                if (transform)
832                {
833                    //osg::Matrix matrix = transform->getMatrix();
834                    //matrix.setTrans(-(*vertices)[0].x(), matrix.getTrans().y(), matrix.getTrans().z());
835                    transform->setMatrix(osg::Matrix::translate(_pos + osg::Vec3(-(*vertices)[0].x(), 0, 0)));
836                }
837            }
838
839            _curX++;
840            GraphUpdateCallback::_frameNumber = frameNumber;
841
842            geometry->dirtyBound();
843
844            drawable->drawImplementation(renderInfo);
845        }
846
847        const osg::Vec3         _pos;
848        const unsigned int      _width;
849        const unsigned int      _height;
850        mutable unsigned int    _curX;
851        osg::Stats*             _viewerStats;
852        osg::Stats*             _stats;
853        const float             _max;
854        const std::string       _nameBegin;
855        const std::string       _nameEnd;
856        static unsigned int     _frameNumber;
857    };
858};
859
860unsigned int StatsGraph::GraphUpdateCallback::_frameNumber = 0;
861
862
863osg::Geometry* StatsHandler::createGeometry(const osg::Vec3& pos, float height, const osg::Vec4& colour, unsigned int numBlocks)
864{
865    osg::Geometry* geometry = new osg::Geometry;
866
867    geometry->setUseDisplayList(false);
868
869    osg::Vec3Array* vertices = new osg::Vec3Array;
870    geometry->setVertexArray(vertices);
871    vertices->reserve(numBlocks*4);
872
873    for(unsigned int i=0; i<numBlocks; ++i)
874    {
875        vertices->push_back(pos+osg::Vec3(i*20, height, 0.0));
876        vertices->push_back(pos+osg::Vec3(i*20, 0.0, 0.0));
877        vertices->push_back(pos+osg::Vec3(i*20+10.0, 0.0, 0.0));
878        vertices->push_back(pos+osg::Vec3(i*20+10.0, height, 0.0));
879    }
880
881    osg::Vec4Array* colours = new osg::Vec4Array;
882    colours->push_back(colour);
883    geometry->setColorArray(colours);
884    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
885
886    geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, numBlocks*4));
887
888    return geometry;
889}
890
891
892struct FrameMarkerDrawCallback : public virtual osg::Drawable::DrawCallback
893{
894    FrameMarkerDrawCallback(StatsHandler* statsHandler, float xPos, osg::Stats* viewerStats, int frameDelta, int numFrames):
895        _statsHandler(statsHandler),
896        _xPos(xPos),
897        _viewerStats(viewerStats),
898        _frameDelta(frameDelta),
899        _numFrames(numFrames) {}
900
901    /** do customized draw code.*/
902    virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
903    {
904        osg::Geometry* geom = (osg::Geometry*)drawable;
905        osg::Vec3Array* vertices = (osg::Vec3Array*)geom->getVertexArray();
906
907        int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();
908
909        int startFrame = frameNumber + _frameDelta - _numFrames + 1;
910        int endFrame = frameNumber + _frameDelta;
911        double referenceTime;
912        if (!_viewerStats->getAttribute( startFrame, "Reference time", referenceTime))
913        {
914            return;
915        }
916
917        unsigned int vi = 0;
918        double currentReferenceTime;
919        for(int i = startFrame; i <= endFrame; ++i)
920        {
921            if (_viewerStats->getAttribute( i, "Reference time", currentReferenceTime))
922            {
923                (*vertices)[vi++].x() = _xPos + (currentReferenceTime - referenceTime) * _statsHandler->getBlockMultiplier();
924                (*vertices)[vi++].x() = _xPos + (currentReferenceTime - referenceTime) * _statsHandler->getBlockMultiplier();
925            }
926        }
927
928        drawable->drawImplementation(renderInfo);
929    }
930
931    StatsHandler*               _statsHandler;
932    float                       _xPos;
933    osg::ref_ptr<osg::Stats>    _viewerStats;
934    std::string                 _endName;
935    int                         _frameDelta;
936    int                         _numFrames;
937};
938
939struct PagerCallback : public virtual osg::NodeCallback
940{
941
942    PagerCallback(  osgDB::DatabasePager* dp,
943                    osgText::Text* minValue,
944                    osgText::Text* maxValue,
945                    osgText::Text* averageValue,
946                    osgText::Text* filerequestlist,
947                    osgText::Text* compilelist,
948                    double multiplier):
949        _dp(dp),
950        _minValue(minValue),
951        _maxValue(maxValue),
952        _averageValue(averageValue),
953        _filerequestlist(filerequestlist),
954        _compilelist(compilelist),
955        _multiplier(multiplier)
956    {
957    }
958
959    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
960    {
961        if (_dp.valid())
962        {
963            char tmpText[128];
964
965            double value = _dp->getAverageTimeToMergeTiles();
966            if (value>= 0.0 && value <= 1000)
967            {
968                sprintf(tmpText,"%4.0f",value * _multiplier);
969                _averageValue->setText(tmpText);
970            }
971            else
972            {
973                _averageValue->setText("");
974            }
975
976            value = _dp->getMinimumTimeToMergeTile();
977            if (value>= 0.0 && value <= 1000)
978            {
979                sprintf(tmpText,"%4.0f",value * _multiplier);
980                _minValue->setText(tmpText);
981            }
982            else
983            {
984                _minValue->setText("");
985            }
986
987            value = _dp->getMaximumTimeToMergeTile();
988            if (value>= 0.0 && value <= 1000)
989            {
990                sprintf(tmpText,"%4.0f",value * _multiplier);
991                _maxValue->setText(tmpText);
992            }
993            else
994            {
995                _maxValue->setText("");
996            }
997
998            sprintf(tmpText,"%4d", _dp->getFileRequestListSize());
999            _filerequestlist->setText(tmpText);
1000
1001            sprintf(tmpText,"%4d", _dp->getDataToCompileListSize());
1002            _compilelist->setText(tmpText);
1003        }
1004
1005        traverse(node,nv);
1006    }
1007
1008    osg::observer_ptr<osgDB::DatabasePager> _dp;
1009
1010    osg::ref_ptr<osgText::Text> _minValue;
1011    osg::ref_ptr<osgText::Text> _maxValue;
1012    osg::ref_ptr<osgText::Text> _averageValue;
1013    osg::ref_ptr<osgText::Text> _filerequestlist;
1014    osg::ref_ptr<osgText::Text> _compilelist;
1015    double                      _multiplier;
1016};
1017
1018
1019osg::Geometry* StatsHandler::createFrameMarkers(const osg::Vec3& pos, float height, const osg::Vec4& colour, unsigned int numBlocks)
1020{
1021    osg::Geometry* geometry = new osg::Geometry;
1022
1023    geometry->setUseDisplayList(false);
1024
1025    osg::Vec3Array* vertices = new osg::Vec3Array;
1026    geometry->setVertexArray(vertices);
1027    vertices->reserve(numBlocks*2);
1028
1029    for(unsigned int i=0; i<numBlocks; ++i)
1030    {
1031        vertices->push_back(pos+osg::Vec3(double(i)*_blockMultiplier*0.01, height, 0.0));
1032        vertices->push_back(pos+osg::Vec3(double(i)*_blockMultiplier*0.01, 0.0, 0.0));
1033    }
1034
1035    osg::Vec4Array* colours = new osg::Vec4Array;
1036    colours->push_back(colour);
1037    geometry->setColorArray(colours);
1038    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
1039
1040    geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, numBlocks*2));
1041
1042    return geometry;
1043}
1044
1045osg::Geometry* StatsHandler::createTick(const osg::Vec3& pos, float height, const osg::Vec4& colour, unsigned int numTicks)
1046{
1047    osg::Geometry* geometry = new osg::Geometry;
1048
1049    geometry->setUseDisplayList(false);
1050
1051    osg::Vec3Array* vertices = new osg::Vec3Array;
1052    geometry->setVertexArray(vertices);
1053    vertices->reserve(numTicks*2);
1054
1055    for(unsigned int i=0; i<numTicks; ++i)
1056    {
1057        float tickHeight = (i%10) ? height : height * 2.0;
1058        vertices->push_back(pos+osg::Vec3(double(i)*_blockMultiplier*0.001, tickHeight , 0.0));
1059        vertices->push_back(pos+osg::Vec3(double(i)*_blockMultiplier*0.001, 0.0, 0.0));
1060    }
1061
1062    osg::Vec4Array* colours = new osg::Vec4Array;
1063    colours->push_back(colour);
1064    geometry->setColorArray(colours);
1065    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
1066
1067    geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, numTicks*2));
1068
1069    return geometry;
1070}
1071
1072void StatsHandler::setUpScene(osgViewer::ViewerBase* viewer)
1073{
1074    _switch = new osg::Switch;
1075
1076    _camera->addChild(_switch.get());
1077
1078    osg::StateSet* stateset = _switch->getOrCreateStateSet();
1079    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
1080    stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
1081    stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
1082#ifdef OSG_GL1_AVAILABLE
1083    stateset->setAttribute(new osg::PolygonMode(), osg::StateAttribute::PROTECTED);
1084#endif
1085
1086    // collect all the relevant cameras
1087    ViewerBase::Cameras validCameras;
1088    viewer->getCameras(validCameras);
1089
1090    ViewerBase::Cameras cameras;
1091    for(ViewerBase::Cameras::iterator itr = validCameras.begin();
1092        itr != validCameras.end();
1093        ++itr)
1094    {
1095        if ((*itr)->getStats())
1096        {
1097            cameras.push_back(*itr);
1098        }
1099    }
1100
1101    // check for query time support
1102    unsigned int numCamrasWithTimerQuerySupport = 0;
1103    for(ViewerBase::Cameras::iterator citr = cameras.begin();
1104        citr != cameras.end();
1105        ++citr)
1106    {
1107        if ((*citr)->getGraphicsContext())
1108        {
1109            const osg::State* state = (*citr)->getGraphicsContext()->getState();
1110            unsigned int contextID = state->getContextID();
1111            const osg::Drawable::Extensions* extensions = osg::Drawable::getExtensions(contextID, false);
1112            if (extensions &&
1113                (((extensions->isARBTimerQuerySupported()
1114                  && state->getTimestampBits() > 0))
1115                 || extensions->isTimerQuerySupported()))
1116            {
1117                ++numCamrasWithTimerQuerySupport;
1118            }
1119        }
1120    }
1121
1122    bool acquireGPUStats = numCamrasWithTimerQuerySupport==cameras.size();
1123
1124    osg::Vec3 pos(_leftPos, _statsHeight-24.0f,0.0f);
1125
1126    osg::Vec4 colorFR(1.0f,1.0f,1.0f,1.0f);
1127    osg::Vec4 colorFRAlpha(1.0f,1.0f,1.0f,0.5f);
1128    osg::Vec4 colorUpdate( 0.0f,1.0f,0.0f,1.0f);
1129    osg::Vec4 colorUpdateAlpha( 0.0f,1.0f,0.0f,0.5f);
1130    osg::Vec4 colorEvent(0.0f, 1.0f, 0.5f, 1.0f);
1131    osg::Vec4 colorEventAlpha(0.0f, 1.0f, 0.5f, 0.5f);
1132    osg::Vec4 colorCull( 0.0f,1.0f,1.0f,1.0f);
1133    osg::Vec4 colorCullAlpha( 0.0f,1.0f,1.0f,0.5f);
1134    osg::Vec4 colorDraw( 1.0f,1.0f,0.0f,1.0f);
1135    osg::Vec4 colorDrawAlpha( 1.0f,1.0f,0.0f,0.5f);
1136    osg::Vec4 colorGPU( 1.0f,0.5f,0.0f,1.0f);
1137    osg::Vec4 colorGPUAlpha( 1.0f,0.5f,0.0f,0.5f);
1138
1139    osg::Vec4 colorDP( 1.0f,1.0f,0.5f,1.0f);
1140
1141
1142    // frame rate stats
1143    {
1144        osg::Geode* geode = new osg::Geode();
1145        _frameRateChildNum = _switch->getNumChildren();
1146        _switch->addChild(geode, false);
1147
1148        osg::ref_ptr<osgText::Text> frameRateLabel = new osgText::Text;
1149        geode->addDrawable( frameRateLabel.get() );
1150
1151        frameRateLabel->setColor(colorFR);
1152        frameRateLabel->setFont(_font);
1153        frameRateLabel->setCharacterSize(_characterSize);
1154        frameRateLabel->setPosition(pos);
1155        frameRateLabel->setText("Frame Rate: ");
1156
1157        pos.x() = frameRateLabel->getBound().xMax();
1158
1159        osg::ref_ptr<osgText::Text> frameRateValue = new osgText::Text;
1160        geode->addDrawable( frameRateValue.get() );
1161
1162        frameRateValue->setColor(colorFR);
1163        frameRateValue->setFont(_font);
1164        frameRateValue->setCharacterSize(_characterSize);
1165        frameRateValue->setPosition(pos);
1166        frameRateValue->setText("0.0");
1167
1168        frameRateValue->setDrawCallback(new AveragedValueTextDrawCallback(viewer->getViewerStats(),"Frame rate",-1, true, 1.0));
1169
1170        pos.y() -= _characterSize*_lineHeight;
1171
1172    }
1173
1174    osg::Vec4 backgroundColor(0.0, 0.0, 0.0f, 0.3);
1175    osg::Vec4 staticTextColor(1.0, 1.0, 0.0f, 1.0);
1176    osg::Vec4 dynamicTextColor(1.0, 1.0, 1.0f, 1.0);
1177    float backgroundMargin = 5;
1178    float backgroundSpacing = 3;
1179
1180
1181    // viewer stats
1182    {
1183        osg::Group* group = new osg::Group;
1184        _viewerChildNum = _switch->getNumChildren();
1185        _switch->addChild(group, false);
1186
1187        _statsGeode = new osg::Geode();
1188        group->addChild(_statsGeode.get());
1189
1190
1191        {
1192            pos.x() = _leftPos;
1193
1194            _threadingModelText = new osgText::Text;
1195            _statsGeode->addDrawable( _threadingModelText.get() );
1196
1197            _threadingModelText->setColor(colorFR);
1198            _threadingModelText->setFont(_font);
1199            _threadingModelText->setCharacterSize(_characterSize);
1200            _threadingModelText->setPosition(pos);
1201
1202            updateThreadingModelText();
1203
1204            pos.y() -= _characterSize*_lineHeight;
1205        }
1206
1207        float topOfViewerStats = pos.y() + _characterSize;
1208
1209        double cameraSize = _lineHeight * 3.0 * cameras.size();
1210        if(!acquireGPUStats) //reduce size if GPU stats not needed
1211        {
1212            cameraSize -= _lineHeight * cameras.size();
1213        }
1214
1215        double userStatsLinesSize = _lineHeight * _userStatsLines.size();
1216
1217        _statsGeode->addDrawable(createBackgroundRectangle(
1218            pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0),
1219            _statsWidth - 2 * backgroundMargin,
1220            (3 + cameraSize + userStatsLinesSize) * _characterSize + 2 * backgroundMargin,
1221            backgroundColor) );
1222
1223        // Add user stats lines before the normal viewer and per-camera stats.
1224        for (unsigned int i = 0; i < _userStatsLines.size(); ++i)
1225        {
1226            pos.x() = _leftPos;
1227
1228            UserStatsLine& line = _userStatsLines[i];
1229            createTimeStatsLine(line.label, pos, line.textColor, line.barColor, viewer->getViewerStats(), viewer->getViewerStats(),
1230                line.timeTakenName, line.multiplier, line.average, line.averageInInverseSpace, line.beginTimeName, line.endTimeName);
1231
1232            pos.y() -= _characterSize*_lineHeight;
1233        }
1234
1235        {
1236            pos.x() = _leftPos;
1237
1238            createTimeStatsLine("Event", pos, colorUpdate, colorUpdateAlpha, viewer->getViewerStats(), viewer->getViewerStats(),
1239                "Event traversal time taken", 1000.0, true, false, "Event traversal begin time", "Event traversal end time");
1240
1241            pos.y() -= _characterSize*_lineHeight;
1242        }
1243
1244        {
1245            pos.x() = _leftPos;
1246
1247            createTimeStatsLine("Update", pos, colorUpdate, colorUpdateAlpha, viewer->getViewerStats(), viewer->getViewerStats(),
1248                "Update traversal time taken", 1000.0, true, false, "Update traversal begin time", "Update traversal end time");
1249
1250            pos.y() -= _characterSize*_lineHeight;
1251        }
1252
1253        pos.x() = _leftPos;
1254
1255        // add camera stats
1256        for(ViewerBase::Cameras::iterator citr = cameras.begin();
1257            citr != cameras.end();
1258            ++citr)
1259        {
1260            createCameraTimeStats(pos, acquireGPUStats, viewer->getViewerStats(), *citr);
1261        }
1262
1263        // add frame ticks
1264        {
1265            osg::Geode* geode = new osg::Geode;
1266            group->addChild(geode);
1267
1268            osg::Vec4 colourTicks(1.0f,1.0f,1.0f, 0.5f);
1269
1270            pos.x() = _startBlocks;
1271            pos.y() += _characterSize;
1272            float height = topOfViewerStats - pos.y();
1273
1274            osg::Geometry* ticks = createTick(pos, 5.0f, colourTicks, 100);
1275            geode->addDrawable(ticks);
1276
1277            osg::Geometry* frameMarkers = createFrameMarkers(pos, height, colourTicks, _numBlocks + 1);
1278            frameMarkers->setDrawCallback(new FrameMarkerDrawCallback(this, _startBlocks, viewer->getViewerStats(), 0, _numBlocks + 1));
1279            geode->addDrawable(frameMarkers);
1280
1281            pos.x() = _leftPos;
1282        }
1283
1284        // Stats line graph
1285        {
1286            pos.y() -= (backgroundSpacing + 2 * backgroundMargin);
1287            float width = _statsWidth - 4 * backgroundMargin;
1288            float height = 5 * _characterSize;
1289
1290            // Create a stats graph and add any stats we want to track with it.
1291            StatsGraph* statsGraph = new StatsGraph(pos, width, height);
1292            group->addChild(statsGraph);
1293
1294            statsGraph->addStatGraph(viewer->getViewerStats(), viewer->getViewerStats(), colorFR, 100, "Frame rate");
1295            statsGraph->addStatGraph(viewer->getViewerStats(), viewer->getViewerStats(), colorEvent, 0.016, "Event traversal time taken");
1296            statsGraph->addStatGraph(viewer->getViewerStats(), viewer->getViewerStats(), colorUpdate, 0.016, "Update traversal time taken");
1297
1298            for (unsigned int i = 0; i < _userStatsLines.size(); ++i)
1299            {
1300                UserStatsLine& line = _userStatsLines[i];
1301                if (!line.timeTakenName.empty() && line.average)
1302                {
1303                    statsGraph->addStatGraph(viewer->getViewerStats(), viewer->getViewerStats(), line.textColor, line.maxValue, line.timeTakenName);
1304                }
1305            }
1306
1307            for(ViewerBase::Cameras::iterator citr = cameras.begin();
1308                citr != cameras.end();
1309                ++citr)
1310            {
1311                statsGraph->addStatGraph(viewer->getViewerStats(), (*citr)->getStats(), colorCull, 0.016, "Cull traversal time taken");
1312                statsGraph->addStatGraph(viewer->getViewerStats(), (*citr)->getStats(), colorDraw, 0.016, "Draw traversal time taken");
1313                if(acquireGPUStats)
1314                {
1315                    statsGraph->addStatGraph(viewer->getViewerStats(), (*citr)->getStats(), colorGPU, 0.016, "GPU draw time taken");
1316                }
1317            }
1318
1319            _statsGeode->addDrawable(createBackgroundRectangle( pos + osg::Vec3(-backgroundMargin, backgroundMargin, 0),
1320                                                                width + 2 * backgroundMargin,
1321                                                                height + 2 * backgroundMargin,
1322                                                                backgroundColor) );
1323
1324            pos.x() = _leftPos;
1325            pos.y() -= height + 2 * backgroundMargin;
1326        }
1327
1328        // Databasepager stats
1329        ViewerBase::Scenes scenes;
1330        viewer->getScenes(scenes);
1331        for(ViewerBase::Scenes::iterator itr = scenes.begin();
1332            itr != scenes.end();
1333            ++itr)
1334        {
1335            Scene* scene = *itr;
1336            osgDB::DatabasePager* dp = scene->getDatabasePager();
1337            if (dp && dp->isRunning())
1338            {
1339                pos.y() -= (_characterSize + backgroundSpacing);
1340
1341                _statsGeode->addDrawable(createBackgroundRectangle(    pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0),
1342                                                                       _statsWidth - 2 * backgroundMargin,
1343                                                                       _characterSize + 2 * backgroundMargin,
1344                                                                       backgroundColor));
1345
1346                osg::ref_ptr<osgText::Text> averageLabel = new osgText::Text;
1347                _statsGeode->addDrawable( averageLabel.get() );
1348
1349                averageLabel->setColor(colorDP);
1350                averageLabel->setFont(_font);
1351                averageLabel->setCharacterSize(_characterSize);
1352                averageLabel->setPosition(pos);
1353                averageLabel->setText("DatabasePager time to merge new tiles - average: ");
1354
1355                pos.x() = averageLabel->getBound().xMax();
1356
1357                osg::ref_ptr<osgText::Text> averageValue = new osgText::Text;
1358                _statsGeode->addDrawable( averageValue.get() );
1359
1360                averageValue->setColor(colorDP);
1361                averageValue->setFont(_font);
1362                averageValue->setCharacterSize(_characterSize);
1363                averageValue->setPosition(pos);
1364                averageValue->setText("1000");
1365
1366                pos.x() = averageValue->getBound().xMax() + 2.0f*_characterSize;
1367
1368
1369                osg::ref_ptr<osgText::Text> minLabel = new osgText::Text;
1370                _statsGeode->addDrawable( minLabel.get() );
1371
1372                minLabel->setColor(colorDP);
1373                minLabel->setFont(_font);
1374                minLabel->setCharacterSize(_characterSize);
1375                minLabel->setPosition(pos);
1376                minLabel->setText("min: ");
1377
1378                pos.x() = minLabel->getBound().xMax();
1379
1380                osg::ref_ptr<osgText::Text> minValue = new osgText::Text;
1381                _statsGeode->addDrawable( minValue.get() );
1382
1383                minValue->setColor(colorDP);
1384                minValue->setFont(_font);
1385                minValue->setCharacterSize(_characterSize);
1386                minValue->setPosition(pos);
1387                minValue->setText("1000");
1388
1389                pos.x() = minValue->getBound().xMax() + 2.0f*_characterSize;
1390
1391                osg::ref_ptr<osgText::Text> maxLabel = new osgText::Text;
1392                _statsGeode->addDrawable( maxLabel.get() );
1393
1394                maxLabel->setColor(colorDP);
1395                maxLabel->setFont(_font);
1396                maxLabel->setCharacterSize(_characterSize);
1397                maxLabel->setPosition(pos);
1398                maxLabel->setText("max: ");
1399
1400                pos.x() = maxLabel->getBound().xMax();
1401
1402                osg::ref_ptr<osgText::Text> maxValue = new osgText::Text;
1403                _statsGeode->addDrawable( maxValue.get() );
1404
1405                maxValue->setColor(colorDP);
1406                maxValue->setFont(_font);
1407                maxValue->setCharacterSize(_characterSize);
1408                maxValue->setPosition(pos);
1409                maxValue->setText("1000");
1410
1411                pos.x() = maxValue->getBound().xMax();
1412
1413                osg::ref_ptr<osgText::Text> requestsLabel = new osgText::Text;
1414                _statsGeode->addDrawable( requestsLabel.get() );
1415
1416                requestsLabel->setColor(colorDP);
1417                requestsLabel->setFont(_font);
1418                requestsLabel->setCharacterSize(_characterSize);
1419                requestsLabel->setPosition(pos);
1420                requestsLabel->setText("requests: ");
1421
1422                pos.x() = requestsLabel->getBound().xMax();
1423
1424                osg::ref_ptr<osgText::Text> requestList = new osgText::Text;
1425                _statsGeode->addDrawable( requestList.get() );
1426
1427                requestList->setColor(colorDP);
1428                requestList->setFont(_font);
1429                requestList->setCharacterSize(_characterSize);
1430                requestList->setPosition(pos);
1431                requestList->setText("0");
1432
1433                pos.x() = requestList->getBound().xMax() + 2.0f*_characterSize;;
1434
1435                osg::ref_ptr<osgText::Text> compileLabel = new osgText::Text;
1436                _statsGeode->addDrawable( compileLabel.get() );
1437
1438                compileLabel->setColor(colorDP);
1439                compileLabel->setFont(_font);
1440                compileLabel->setCharacterSize(_characterSize);
1441                compileLabel->setPosition(pos);
1442                compileLabel->setText("tocompile: ");
1443
1444                pos.x() = compileLabel->getBound().xMax();
1445
1446                osg::ref_ptr<osgText::Text> compileList = new osgText::Text;
1447                _statsGeode->addDrawable( compileList.get() );
1448
1449                compileList->setColor(colorDP);
1450                compileList->setFont(_font);
1451                compileList->setCharacterSize(_characterSize);
1452                compileList->setPosition(pos);
1453                compileList->setText("0");
1454
1455                pos.x() = maxLabel->getBound().xMax();
1456
1457                _statsGeode->setCullCallback(new PagerCallback(dp, minValue.get(), maxValue.get(), averageValue.get(), requestList.get(), compileList.get(), 1000.0));
1458            }
1459
1460            pos.x() = _leftPos;
1461        }
1462    }
1463
1464    // Camera scene stats
1465    {
1466        pos.y() -= (_characterSize + backgroundSpacing + 2 * backgroundMargin);
1467
1468        osg::Group* group = new osg::Group;
1469        _cameraSceneChildNum = _switch->getNumChildren();
1470        _switch->addChild(group, false);
1471
1472        osg::Geode* geode = new osg::Geode();
1473        geode->setCullingActive(false);
1474        group->addChild(geode);
1475        geode->addDrawable(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0),
1476                                                        10 * _characterSize + 2 * backgroundMargin,
1477                                                        22 * _characterSize + 2 * backgroundMargin,
1478                                                        backgroundColor));
1479
1480        // Camera scene & primitive stats static text
1481        osg::ref_ptr<osgText::Text> camStaticText = new osgText::Text;
1482        geode->addDrawable( camStaticText.get() );
1483        camStaticText->setColor(staticTextColor);
1484        camStaticText->setFont(_font);
1485        camStaticText->setCharacterSize(_characterSize);
1486        camStaticText->setPosition(pos);
1487
1488        std::ostringstream viewStr;
1489        viewStr.clear();
1490        viewStr.setf(std::ios::left, std::ios::adjustfield);
1491        viewStr.width(14);
1492        viewStr << "Camera" << std::endl;
1493        viewStr << "" << std::endl; // placeholder for Camera name
1494        viewStr << "Lights" << std::endl;
1495        viewStr << "Bins" << std::endl;
1496        viewStr << "Depth" << std::endl;
1497        viewStr << "State graphs" << std::endl;
1498        viewStr << "Imposters" << std::endl;
1499        viewStr << "Drawables" << std::endl;
1500        viewStr << "Sorted Drawables" << std::endl;
1501        viewStr << "Fast Drawables" << std::endl;
1502        viewStr << "Vertices" << std::endl;
1503        viewStr << "PrimitiveSets" << std::endl;
1504        viewStr << "Points" << std::endl;
1505        viewStr << "Lines" << std::endl;
1506        viewStr << "Line strips" << std::endl;
1507        viewStr << "Line loops" << std::endl;
1508        viewStr << "Triangles" << std::endl;
1509        viewStr << "Tri. strips" << std::endl;
1510        viewStr << "Tri. fans" << std::endl;
1511        viewStr << "Quads" << std::endl;
1512        viewStr << "Quad strips" << std::endl;
1513        viewStr << "Polygons" << std::endl;
1514        viewStr.setf(std::ios::right,std::ios::adjustfield);
1515        camStaticText->setText(viewStr.str());
1516
1517        // Move camera block to the right
1518        pos.x() += 10 * _characterSize + 2 * backgroundMargin + backgroundSpacing;
1519
1520        // Add camera scene stats, one block per camera
1521        int cameraCounter = 0;
1522        for(ViewerBase::Cameras::iterator citr = cameras.begin(); citr != cameras.end(); ++citr)
1523        {
1524            geode->addDrawable(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0),
1525                                                            5 * _characterSize + 2 * backgroundMargin,
1526                                                            22 * _characterSize + 2 * backgroundMargin,
1527                                                            backgroundColor));
1528
1529            // Camera scene stats
1530            osg::ref_ptr<osgText::Text> camStatsText = new osgText::Text;
1531            geode->addDrawable( camStatsText.get() );
1532
1533            camStatsText->setColor(dynamicTextColor);
1534            camStatsText->setFont(_font);
1535            camStatsText->setCharacterSize(_characterSize);
1536            camStatsText->setPosition(pos);
1537            camStatsText->setText("");
1538            camStatsText->setDrawCallback(new CameraSceneStatsTextDrawCallback(*citr, cameraCounter));
1539
1540            // Move camera block to the right
1541            pos.x() +=  5 * _characterSize + 2 * backgroundMargin + backgroundSpacing;
1542            cameraCounter++;
1543        }
1544    }
1545
1546    // Viewer scene stats
1547    {
1548        osg::Group* group = new osg::Group;
1549        _viewerSceneChildNum = _switch->getNumChildren();
1550        _switch->addChild(group, false);
1551
1552        osg::Geode* geode = new osg::Geode();
1553        geode->setCullingActive(false);
1554        group->addChild(geode);
1555
1556        geode->addDrawable(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0),
1557                                                        6 * _characterSize + 2 * backgroundMargin,
1558                                                        12 * _characterSize + 2 * backgroundMargin,
1559                                                        backgroundColor));
1560
1561        // View scene stats static text
1562        osg::ref_ptr<osgText::Text> camStaticText = new osgText::Text;
1563        geode->addDrawable( camStaticText.get() );
1564        camStaticText->setColor(staticTextColor);
1565        camStaticText->setFont(_font);
1566        camStaticText->setCharacterSize(_characterSize);
1567        camStaticText->setPosition(pos);
1568
1569        std::ostringstream viewStr;
1570        viewStr.clear();
1571        viewStr.setf(std::ios::left, std::ios::adjustfield);
1572        viewStr.width(14);
1573        viewStr << "View" << std::endl;
1574        viewStr << " " << std::endl;
1575        viewStr << "Stateset" << std::endl;
1576        viewStr << "Group" << std::endl;
1577        viewStr << "Transform" << std::endl;
1578        viewStr << "LOD" << std::endl;
1579        viewStr << "Switch" << std::endl;
1580        viewStr << "Geode" << std::endl;
1581        viewStr << "Drawable" << std::endl;
1582        viewStr << "Geometry" << std::endl;
1583        viewStr << "Vertices" << std::endl;
1584        viewStr << "Primitives" << std::endl;
1585        viewStr.setf(std::ios::right, std::ios::adjustfield);
1586        camStaticText->setText(viewStr.str());
1587
1588        // Move viewer block to the right
1589        pos.x() += 6 * _characterSize + 2 * backgroundMargin + backgroundSpacing;
1590
1591        std::vector<osgViewer::View*> views;
1592        viewer->getViews(views);
1593
1594        std::vector<osgViewer::View*>::iterator it;
1595        int viewCounter = 0;
1596        for (it = views.begin(); it != views.end(); ++it)
1597        {
1598            geode->addDrawable(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0),
1599                                                            10 * _characterSize + 2 * backgroundMargin,
1600                                                            12 * _characterSize + 2 * backgroundMargin,
1601                                                            backgroundColor));
1602
1603            // Text for scene statistics
1604            osgText::Text* text = new  osgText::Text;
1605            geode->addDrawable( text );
1606
1607            text->setColor(dynamicTextColor);
1608            text->setFont(_font);
1609            text->setCharacterSize(_characterSize);
1610            text->setPosition(pos);
1611            text->setDrawCallback(new ViewSceneStatsTextDrawCallback(*it, viewCounter));
1612
1613            pos.x() += 10 * _characterSize + 2 * backgroundMargin + backgroundSpacing;
1614            viewCounter++;
1615        }
1616    }
1617}
1618
1619void StatsHandler::createTimeStatsLine(const std::string& lineLabel,
1620                                       osg::Vec3 pos, const osg::Vec4& textColor, const osg::Vec4& barColor,
1621                                       osg::Stats* viewerStats, osg::Stats* stats,
1622                                       const std::string& timeTakenName, float multiplier, bool average, bool averageInInverseSpace,
1623                                       const std::string& beginTimeName, const std::string& endTimeName)
1624{
1625    osg::ref_ptr<osgText::Text> label = new osgText::Text;
1626    _statsGeode->addDrawable( label.get() );
1627
1628    label->setColor(textColor);
1629    label->setFont(_font);
1630    label->setCharacterSize(_characterSize);
1631    label->setPosition(pos);
1632    label->setText(lineLabel + ": ");
1633
1634    pos.x() = label->getBound().xMax();
1635
1636    osg::ref_ptr<osgText::Text> value = new osgText::Text;
1637    _statsGeode->addDrawable( value.get() );
1638
1639    value->setColor(textColor);
1640    value->setFont(_font);
1641    value->setCharacterSize(_characterSize);
1642    value->setPosition(pos);
1643    value->setText("0.0");
1644
1645    if (!timeTakenName.empty())
1646    {
1647        if (average)
1648        {
1649            value->setDrawCallback(new AveragedValueTextDrawCallback(stats, timeTakenName, -1, averageInInverseSpace, multiplier));
1650        }
1651        else
1652        {
1653            value->setDrawCallback(new RawValueTextDrawCallback(stats, timeTakenName, -1, multiplier));
1654        }
1655    }
1656
1657    if (!beginTimeName.empty() && !endTimeName.empty())
1658    {
1659        pos.x() = _startBlocks;
1660        osg::Geometry* geometry = createGeometry(pos, _characterSize *0.8, barColor, _numBlocks);
1661        geometry->setDrawCallback(new BlockDrawCallback(this, _startBlocks, viewerStats, stats, beginTimeName, endTimeName, -1, _numBlocks));
1662        _statsGeode->addDrawable(geometry);
1663    }
1664}
1665
1666void StatsHandler::createCameraTimeStats(osg::Vec3& pos, bool acquireGPUStats, osg::Stats* viewerStats, osg::Camera* camera)
1667{
1668    osg::Stats* stats = camera->getStats();
1669    if (!stats) return;
1670
1671    osg::Vec4 colorCull( 0.0f,1.0f,1.0f,1.0f);
1672    osg::Vec4 colorCullAlpha( 0.0f,1.0f,1.0f,0.5f);
1673    osg::Vec4 colorDraw( 1.0f,1.0f,0.0f,1.0f);
1674    osg::Vec4 colorDrawAlpha( 1.0f,1.0f,0.0f,0.5f);
1675    osg::Vec4 colorGPU( 1.0f,0.5f,0.0f,1.0f);
1676    osg::Vec4 colorGPUAlpha( 1.0f,0.5f,0.0f,0.5f);
1677
1678    {
1679        pos.x() = _leftPos;
1680
1681        createTimeStatsLine("Cull", pos, colorCull, colorCullAlpha, viewerStats, stats,
1682            "Cull traversal time taken", 1000.0, true, false, "Cull traversal begin time", "Cull traversal end time");
1683
1684        pos.y() -= _characterSize*_lineHeight;
1685    }
1686
1687    {
1688        pos.x() = _leftPos;
1689
1690        createTimeStatsLine("Draw", pos, colorDraw, colorDrawAlpha, viewerStats, stats,
1691            "Draw traversal time taken", 1000.0, true, false, "Draw traversal begin time", "Draw traversal end time");
1692
1693        pos.y() -= _characterSize*_lineHeight;
1694    }
1695
1696    if (acquireGPUStats)
1697    {
1698        pos.x() = _leftPos;
1699
1700        createTimeStatsLine("GPU", pos, colorGPU, colorGPUAlpha, viewerStats, stats,
1701            "GPU draw time taken", 1000.0, true, false, "GPU draw begin time", "GPU draw end time");
1702
1703        pos.y() -= _characterSize*_lineHeight;
1704    }
1705}
1706
1707
1708void StatsHandler::getUsage(osg::ApplicationUsage& usage) const
1709{
1710    usage.addKeyboardMouseBinding("s","On screen stats.");
1711    usage.addKeyboardMouseBinding("S","Output stats to console.");
1712}
1713
1714}
Note: See TracBrowser for help on using the browser.