| | 596 | struct StatsGraph : public osg::MatrixTransform |
| | 597 | { |
| | 598 | StatsGraph(osg::Vec3 pos, float width, float height) |
| | 599 | : _pos(pos), _width(width), _height(height), |
| | 600 | _statsGraphGeode(new osg::Geode) |
| | 601 | { |
| | 602 | _pos -= osg::Vec3(0, height, 0.1); |
| | 603 | this->setMatrix(osg::Matrix::translate(_pos)); |
| | 604 | this->addChild(_statsGraphGeode.get()); |
| | 605 | } |
| | 606 | |
| | 607 | void addStatGraph(osg::Stats* viewerStats, osg::Stats* stats, const osg::Vec4& color, float max, const std::string& nameBegin, const std::string& nameEnd = "") |
| | 608 | { |
| | 609 | _statsGraphGeode->addDrawable(new Graph(_width, _height, viewerStats, stats, color, max, nameBegin, nameEnd)); |
| | 610 | } |
| | 611 | |
| | 612 | osg::Vec3 _pos; |
| | 613 | float _width; |
| | 614 | float _height; |
| | 615 | |
| | 616 | osg::ref_ptr<osg::Geode> _statsGraphGeode; |
| | 617 | |
| | 618 | protected: |
| | 619 | struct Graph : public osg::Geometry |
| | 620 | { |
| | 621 | Graph(float width, float height, osg::Stats* viewerStats, osg::Stats* stats, |
| | 622 | const osg::Vec4& color, float max, const std::string& nameBegin, const std::string& nameEnd = "") |
| | 623 | { |
| | 624 | this->setUseDisplayList(false); |
| | 625 | |
| | 626 | this->setVertexArray(new osg::Vec3Array); |
| | 627 | |
| | 628 | osg::Vec4Array* colors = new osg::Vec4Array; |
| | 629 | colors->push_back(color); |
| | 630 | this->setColorArray(colors); |
| | 631 | this->setColorBinding(osg::Geometry::BIND_OVERALL); |
| | 632 | |
| | 633 | this->setDrawCallback(new GraphUpdateCallback(width, height, viewerStats, stats, max, nameBegin, nameEnd)); |
| | 634 | } |
| | 635 | }; |
| | 636 | |
| | 637 | struct GraphUpdateCallback : public osg::Drawable::DrawCallback |
| | 638 | { |
| | 639 | GraphUpdateCallback(float width, float height, osg::Stats* viewerStats, osg::Stats* stats, |
| | 640 | float max, const std::string& nameBegin, const std::string& nameEnd = "") |
| | 641 | : _width((unsigned int)width), _height((unsigned int)height), _curX(0), |
| | 642 | _viewerStats(viewerStats), _stats(stats), _max(max), _nameBegin(nameBegin), _nameEnd(nameEnd) |
| | 643 | { |
| | 644 | } |
| | 645 | |
| | 646 | virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const |
| | 647 | { |
| | 648 | osg::Geometry* geometry = const_cast<osg::Geometry*>(drawable->asGeometry()); |
| | 649 | if (!geometry) return; |
| | 650 | osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray()); |
| | 651 | if (!vertices) return; |
| | 652 | |
| | 653 | int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber(); |
| | 654 | |
| | 655 | // Get stats |
| | 656 | double value; |
| | 657 | if (_nameEnd.empty()) |
| | 658 | { |
| | 659 | if (!_stats->getAveragedAttribute( _nameBegin, value, true )) |
| | 660 | { |
| | 661 | value = 0.0; |
| | 662 | } |
| | 663 | } |
| | 664 | else |
| | 665 | { |
| | 666 | double beginValue, endValue; |
| | 667 | if (_stats->getAttribute( frameNumber, _nameBegin, beginValue) && |
| | 668 | _stats->getAttribute( frameNumber, _nameEnd, endValue) ) |
| | 669 | { |
| | 670 | value = endValue - beginValue; |
| | 671 | } |
| | 672 | else |
| | 673 | { |
| | 674 | value = 0.0; |
| | 675 | } |
| | 676 | } |
| | 677 | |
| | 678 | // Add new vertex for this frame. |
| | 679 | value = osg::clampTo(value, 0.0, double(_max)); |
| | 680 | vertices->push_back(osg::Vec3(float(_curX), float(_height) / _max * value, 0)); |
| | 681 | |
| | 682 | // One vertex per pixel in X. |
| | 683 | if (vertices->size() > _width) |
| | 684 | { |
| | 685 | unsigned int excedent = vertices->size() - _width; |
| | 686 | vertices->erase(vertices->begin(), vertices->begin() + excedent); |
| | 687 | |
| | 688 | // Make the graph scroll when there is enough data. |
| | 689 | // Note: We check the frame number so that even if we have |
| | 690 | // many graphs, the transform is translated only once per |
| | 691 | // frame. |
| | 692 | static const float increment = -1.0; |
| | 693 | if (GraphUpdateCallback::_frameNumber != frameNumber) |
| | 694 | { |
| | 695 | // We know the exact layout of this part of the scene |
| | 696 | // graph, so this is OK... |
| | 697 | osg::MatrixTransform* transform = |
| | 698 | geometry->getParent(0)->getParent(0)->asTransform()->asMatrixTransform(); |
| | 699 | if (transform) |
| | 700 | { |
| | 701 | transform->setMatrix(transform->getMatrix() * osg::Matrix::translate(osg::Vec3(increment, 0, 0))); |
| | 702 | } |
| | 703 | } |
| | 704 | } |
| | 705 | else |
| | 706 | { |
| | 707 | // Create primitive set if none exists. |
| | 708 | if (geometry->getNumPrimitiveSets() == 0) |
| | 709 | geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, 0, 0)); |
| | 710 | |
| | 711 | // Update primitive set. |
| | 712 | osg::DrawArrays* drawArrays = dynamic_cast<osg::DrawArrays*>(geometry->getPrimitiveSet(0)); |
| | 713 | if (!drawArrays) return; |
| | 714 | drawArrays->setFirst(0); |
| | 715 | drawArrays->setCount(vertices->size()); |
| | 716 | } |
| | 717 | |
| | 718 | _curX++; |
| | 719 | GraphUpdateCallback::_frameNumber = frameNumber; |
| | 720 | |
| | 721 | geometry->dirtyBound(); |
| | 722 | |
| | 723 | drawable->drawImplementation(renderInfo); |
| | 724 | } |
| | 725 | |
| | 726 | const unsigned int _width; |
| | 727 | const unsigned int _height; |
| | 728 | mutable unsigned int _curX; |
| | 729 | osg::Stats* _viewerStats; |
| | 730 | osg::Stats* _stats; |
| | 731 | const float _max; |
| | 732 | const std::string _nameBegin; |
| | 733 | const std::string _nameEnd; |
| | 734 | static int _frameNumber; |
| | 735 | }; |
| | 736 | }; |
| | 737 | |
| | 738 | int StatsGraph::GraphUpdateCallback::_frameNumber = 0; |
| | 739 | |
| | 740 | |
| | 1182 | |
| | 1183 | pos.x() = leftPos; |
| | 1184 | } |
| | 1185 | |
| | 1186 | // Stats line graph |
| | 1187 | { |
| | 1188 | pos.y() -= (backgroundSpacing + 2 * backgroundMargin); |
| | 1189 | float width = _camera->getViewport()->width() - 4 * backgroundMargin; |
| | 1190 | float height = 5 * characterSize; |
| | 1191 | |
| | 1192 | // Create a stats graph and add any stats we want to track with it. |
| | 1193 | StatsGraph* statsGraph = new StatsGraph(pos, width, height); |
| | 1194 | group->addChild(statsGraph); |
| | 1195 | |
| | 1196 | statsGraph->addStatGraph(viewer->getStats(), viewer->getStats(), colorFRAlpha, 100, "Frame rate"); |
| | 1197 | statsGraph->addStatGraph(viewer->getStats(), viewer->getStats(), colorEventAlpha, 0.016, "Event traversal time taken"); |
| | 1198 | statsGraph->addStatGraph(viewer->getStats(), viewer->getStats(), colorUpdateAlpha, 0.016, "Update traversal time taken"); |
| | 1199 | |
| | 1200 | for(ViewerBase::Cameras::iterator citr = cameras.begin(); |
| | 1201 | citr != cameras.end(); |
| | 1202 | ++citr) |
| | 1203 | { |
| | 1204 | statsGraph->addStatGraph(viewer->getStats(), (*citr)->getStats(), colorCullAlpha, 0.016, "Cull traversal time taken"); |
| | 1205 | statsGraph->addStatGraph(viewer->getStats(), (*citr)->getStats(), colorDrawAlpha, 0.016, "Draw traversal time taken"); |
| | 1206 | statsGraph->addStatGraph(viewer->getStats(), (*citr)->getStats(), colorGPUAlpha, 0.016, "GPU draw time taken"); |
| | 1207 | } |
| | 1208 | |
| | 1209 | geode->addDrawable(createBackgroundRectangle( pos + osg::Vec3(-backgroundMargin, backgroundMargin, 0), |
| | 1210 | width + 2 * backgroundMargin, |
| | 1211 | height + 2 * backgroundMargin, |
| | 1212 | backgroundColor) ); |
| | 1213 | |
| | 1214 | pos.x() = leftPos; |
| | 1215 | pos.y() -= height + 2 * backgroundMargin; |