mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 07:56:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			316 lines
		
	
	
	
		
			9.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			316 lines
		
	
	
	
		
			9.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "stats.hpp"
 | 
						|
 | 
						|
#include <sstream>
 | 
						|
#include <iomanip>
 | 
						|
 | 
						|
#include <osg/PolygonMode>
 | 
						|
 | 
						|
#include <osgText/Text>
 | 
						|
 | 
						|
#include <osgViewer/Viewer>
 | 
						|
#include <osgViewer/Renderer>
 | 
						|
 | 
						|
namespace Resource
 | 
						|
{
 | 
						|
 | 
						|
StatsHandler::StatsHandler():
 | 
						|
    _key(osgGA::GUIEventAdapter::KEY_F4),
 | 
						|
    _initialized(false),
 | 
						|
    _statsType(false),
 | 
						|
    _statsWidth(1280.0f),
 | 
						|
    _statsHeight(1024.0f),
 | 
						|
    _font("fonts/arial.ttf"),
 | 
						|
    _characterSize(20.0f)
 | 
						|
{
 | 
						|
    _camera = new osg::Camera;
 | 
						|
    _camera->getOrCreateStateSet()->setGlobalDefaults();
 | 
						|
    _camera->setRenderer(new osgViewer::Renderer(_camera.get()));
 | 
						|
    _camera->setProjectionResizePolicy(osg::Camera::FIXED);
 | 
						|
 | 
						|
    _resourceStatsChildNum = 0;
 | 
						|
}
 | 
						|
 | 
						|
bool StatsHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa)
 | 
						|
{
 | 
						|
    if (ea.getHandled()) return false;
 | 
						|
 | 
						|
    switch(ea.getEventType())
 | 
						|
    {
 | 
						|
        case(osgGA::GUIEventAdapter::KEYDOWN):
 | 
						|
        {
 | 
						|
            if (ea.getKey()== _key)
 | 
						|
            {
 | 
						|
                osgViewer::View* myview = dynamic_cast<osgViewer::View*>(&aa);
 | 
						|
                if (!myview) return false;
 | 
						|
 | 
						|
                osgViewer::ViewerBase* viewer = myview->getViewerBase();
 | 
						|
 | 
						|
                toggle(viewer);
 | 
						|
 | 
						|
                aa.requestRedraw();
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        case osgGA::GUIEventAdapter::RESIZE:
 | 
						|
        {
 | 
						|
            setWindowSize(ea.getWindowWidth(), ea.getWindowHeight());
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        default:
 | 
						|
            break;
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
void StatsHandler::setWindowSize(int width, int height)
 | 
						|
{
 | 
						|
    if (width <= 0 || height <= 0)
 | 
						|
        return;
 | 
						|
 | 
						|
    _camera->setViewport(0, 0, width, height);
 | 
						|
    if (fabs(height*_statsWidth) <= fabs(width*_statsHeight))
 | 
						|
    {
 | 
						|
        _camera->setProjectionMatrix(osg::Matrix::ortho2D(_statsWidth - width*_statsHeight/height, _statsWidth,0.0,_statsHeight));
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        _camera->setProjectionMatrix(osg::Matrix::ortho2D(0.0,_statsWidth,_statsHeight-height*_statsWidth/width,_statsHeight));
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
void StatsHandler::toggle(osgViewer::ViewerBase *viewer)
 | 
						|
{
 | 
						|
    if (!_initialized)
 | 
						|
    {
 | 
						|
        setUpHUDCamera(viewer);
 | 
						|
        setUpScene(viewer);
 | 
						|
    }
 | 
						|
 | 
						|
    _statsType = !_statsType;
 | 
						|
 | 
						|
    if (!_statsType)
 | 
						|
    {
 | 
						|
        _camera->setNodeMask(0);
 | 
						|
        _switch->setAllChildrenOff();
 | 
						|
 | 
						|
        viewer->getViewerStats()->collectStats("resource", false);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        _camera->setNodeMask(0xffffffff);
 | 
						|
        _switch->setSingleChildOn(_resourceStatsChildNum);
 | 
						|
 | 
						|
        viewer->getViewerStats()->collectStats("resource", true);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void StatsHandler::setUpHUDCamera(osgViewer::ViewerBase* viewer)
 | 
						|
{
 | 
						|
    // Try GraphicsWindow first so we're likely to get the main viewer window
 | 
						|
    osg::GraphicsContext* context = dynamic_cast<osgViewer::GraphicsWindow*>(_camera->getGraphicsContext());
 | 
						|
 | 
						|
    if (!context)
 | 
						|
    {
 | 
						|
        osgViewer::Viewer::Windows windows;
 | 
						|
        viewer->getWindows(windows);
 | 
						|
 | 
						|
        if (!windows.empty()) context = windows.front();
 | 
						|
        else
 | 
						|
        {
 | 
						|
            // No GraphicsWindows were found, so let's try to find a GraphicsContext
 | 
						|
            context = _camera->getGraphicsContext();
 | 
						|
 | 
						|
            if (!context)
 | 
						|
            {
 | 
						|
                osgViewer::Viewer::Contexts contexts;
 | 
						|
                viewer->getContexts(contexts);
 | 
						|
 | 
						|
                if (contexts.empty()) return;
 | 
						|
 | 
						|
                context = contexts.front();
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    _camera->setGraphicsContext(context);
 | 
						|
 | 
						|
    _camera->setRenderOrder(osg::Camera::POST_RENDER, 11);
 | 
						|
 | 
						|
    _camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
 | 
						|
    _camera->setViewMatrix(osg::Matrix::identity());
 | 
						|
    setWindowSize(context->getTraits()->width, context->getTraits()->height);
 | 
						|
 | 
						|
    // only clear the depth buffer
 | 
						|
    _camera->setClearMask(0);
 | 
						|
    _camera->setAllowEventFocus(false);
 | 
						|
 | 
						|
    _camera->setRenderer(new osgViewer::Renderer(_camera.get()));
 | 
						|
 | 
						|
    _initialized = true;
 | 
						|
}
 | 
						|
 | 
						|
osg::Geometry* 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, osg::Array::BIND_OVERALL);
 | 
						|
 | 
						|
    osg::DrawElementsUShort *base =  new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_FAN,0);
 | 
						|
    base->push_back(0);
 | 
						|
    base->push_back(1);
 | 
						|
    base->push_back(2);
 | 
						|
    base->push_back(3);
 | 
						|
 | 
						|
    geometry->addPrimitiveSet(base);
 | 
						|
 | 
						|
    return geometry;
 | 
						|
}
 | 
						|
 | 
						|
class ResourceStatsTextDrawCallback : public osg::Drawable::DrawCallback
 | 
						|
{
 | 
						|
public:
 | 
						|
    ResourceStatsTextDrawCallback(osg::Stats* stats, const std::vector<std::string>& statNames)
 | 
						|
        : _stats(stats)
 | 
						|
        , _statNames(statNames)
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
 | 
						|
    {
 | 
						|
        if (!_stats) return;
 | 
						|
 | 
						|
        osgText::Text* text = (osgText::Text*)(drawable);
 | 
						|
 | 
						|
        std::ostringstream viewStr;
 | 
						|
        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);
 | 
						|
 | 
						|
        unsigned int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber()-1;
 | 
						|
 | 
						|
        for (std::vector<std::string>::const_iterator it = _statNames.begin(); it != _statNames.end(); ++it)
 | 
						|
        {
 | 
						|
            if (it->empty())
 | 
						|
                viewStr << std::endl;
 | 
						|
            else
 | 
						|
            {
 | 
						|
                double value = 0.0;
 | 
						|
                if (_stats->getAttribute(frameNumber, *it, value))
 | 
						|
                    viewStr << std::setw(8) << value << std::endl;
 | 
						|
                else
 | 
						|
                    viewStr << std::setw(8) << "." << std::endl;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        text->setText(viewStr.str());
 | 
						|
 | 
						|
        text->drawImplementation(renderInfo);
 | 
						|
    }
 | 
						|
 | 
						|
    osg::ref_ptr<osg::Stats> _stats;
 | 
						|
    std::vector<std::string> _statNames;
 | 
						|
};
 | 
						|
 | 
						|
void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer)
 | 
						|
{
 | 
						|
    _switch = new osg::Switch;
 | 
						|
 | 
						|
    _camera->addChild(_switch);
 | 
						|
 | 
						|
    osg::StateSet* stateset = _switch->getOrCreateStateSet();
 | 
						|
    stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
 | 
						|
    stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
 | 
						|
    stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
 | 
						|
#ifdef OSG_GL1_AVAILABLE
 | 
						|
    stateset->setAttribute(new osg::PolygonMode(), osg::StateAttribute::PROTECTED);
 | 
						|
#endif
 | 
						|
 | 
						|
    osg::Vec3 pos(_statsWidth-300.f, _statsHeight-500.0f,0.0f);
 | 
						|
    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;
 | 
						|
 | 
						|
    // resource stats
 | 
						|
    {
 | 
						|
        osg::Group* group = new osg::Group;
 | 
						|
        group->setCullingActive(false);
 | 
						|
        _resourceStatsChildNum = _switch->getNumChildren();
 | 
						|
        _switch->addChild(group, false);
 | 
						|
 | 
						|
        const char* statNames[] = {"Compiling", "WorkQueue", "WorkThread", "", "Texture", "StateSet", "Node", "Node Instance", "Shape", "Shape Instance", "Image", "Nif", "Keyframe", "", "Terrain Chunk", "Terrain Texture", "Land", "Composite", "", "UnrefQueue"};
 | 
						|
 | 
						|
        int numLines = sizeof(statNames) / sizeof(statNames[0]);
 | 
						|
 | 
						|
        group->addChild(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0),
 | 
						|
                                                        10 * _characterSize + 2 * backgroundMargin,
 | 
						|
                                                        numLines * _characterSize + 2 * backgroundMargin,
 | 
						|
                                                        backgroundColor));
 | 
						|
 | 
						|
        osg::ref_ptr<osgText::Text> staticText = new osgText::Text;
 | 
						|
        group->addChild( staticText.get() );
 | 
						|
        staticText->setColor(staticTextColor);
 | 
						|
        staticText->setFont(_font);
 | 
						|
        staticText->setCharacterSize(_characterSize);
 | 
						|
        staticText->setPosition(pos);
 | 
						|
 | 
						|
        std::ostringstream viewStr;
 | 
						|
        viewStr.clear();
 | 
						|
        viewStr.setf(std::ios::left, std::ios::adjustfield);
 | 
						|
        viewStr.width(14);
 | 
						|
        for (size_t i = 0; i<sizeof(statNames)/sizeof(statNames[0]); ++i)
 | 
						|
        {
 | 
						|
            viewStr << statNames[i] << std::endl;
 | 
						|
        }
 | 
						|
 | 
						|
        staticText->setText(viewStr.str());
 | 
						|
 | 
						|
        pos.x() += 10 * _characterSize + 2 * backgroundMargin + backgroundSpacing;
 | 
						|
 | 
						|
        group->addChild(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0),
 | 
						|
                                                        5 * _characterSize + 2 * backgroundMargin,
 | 
						|
                                                        numLines * _characterSize + 2 * backgroundMargin,
 | 
						|
                                                        backgroundColor));
 | 
						|
 | 
						|
        osg::ref_ptr<osgText::Text> statsText = new osgText::Text;
 | 
						|
        group->addChild( statsText.get() );
 | 
						|
 | 
						|
        statsText->setColor(dynamicTextColor);
 | 
						|
        statsText->setFont(_font);
 | 
						|
        statsText->setCharacterSize(_characterSize);
 | 
						|
        statsText->setPosition(pos);
 | 
						|
        statsText->setText("");
 | 
						|
        statsText->setDrawCallback(new ResourceStatsTextDrawCallback(viewer->getViewerStats(), std::vector<std::string>(statNames, statNames + numLines)));
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void StatsHandler::getUsage(osg::ApplicationUsage &usage) const
 | 
						|
{
 | 
						|
    usage.addKeyboardMouseBinding(_key, "On screen resource usage stats.");
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
}
 |