mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 05:26:39 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			191 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			191 lines
		
	
	
	
		
			5.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "compositemaprenderer.hpp"
 | 
						|
 | 
						|
#include <osg/FrameBufferObject>
 | 
						|
#include <osg/RenderInfo>
 | 
						|
#include <osg/Texture2D>
 | 
						|
 | 
						|
#include <algorithm>
 | 
						|
 | 
						|
namespace Terrain
 | 
						|
{
 | 
						|
 | 
						|
    CompositeMapRenderer::CompositeMapRenderer()
 | 
						|
        : mTargetFrameRate(120)
 | 
						|
        , mMinimumTimeAvailable(0.0025)
 | 
						|
    {
 | 
						|
        setSupportsDisplayList(false);
 | 
						|
        setCullingActive(false);
 | 
						|
 | 
						|
        mFBO = new osg::FrameBufferObject;
 | 
						|
 | 
						|
        getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
 | 
						|
    }
 | 
						|
 | 
						|
    CompositeMapRenderer::~CompositeMapRenderer() {}
 | 
						|
 | 
						|
    void CompositeMapRenderer::drawImplementation(osg::RenderInfo& renderInfo) const
 | 
						|
    {
 | 
						|
        double dt = mTimer.time_s();
 | 
						|
        dt = std::min(dt, 0.2);
 | 
						|
        mTimer.setStartTick();
 | 
						|
        double targetFrameTime = 1.0 / static_cast<double>(mTargetFrameRate);
 | 
						|
        double conservativeTimeRatio(0.75);
 | 
						|
        double availableTime = std::max((targetFrameTime - dt) * conservativeTimeRatio, mMinimumTimeAvailable);
 | 
						|
 | 
						|
        std::lock_guard<std::mutex> lock(mMutex);
 | 
						|
 | 
						|
        if (mImmediateCompileSet.empty() && mCompileSet.empty())
 | 
						|
            return;
 | 
						|
 | 
						|
        while (!mImmediateCompileSet.empty())
 | 
						|
        {
 | 
						|
            osg::ref_ptr<CompositeMap> node = *mImmediateCompileSet.begin();
 | 
						|
            mImmediateCompileSet.erase(node);
 | 
						|
 | 
						|
            mMutex.unlock();
 | 
						|
            compile(*node, renderInfo, nullptr);
 | 
						|
            mMutex.lock();
 | 
						|
        }
 | 
						|
 | 
						|
        double timeLeft = availableTime;
 | 
						|
 | 
						|
        while (!mCompileSet.empty() && timeLeft > 0)
 | 
						|
        {
 | 
						|
            osg::ref_ptr<CompositeMap> node = *mCompileSet.begin();
 | 
						|
            mCompileSet.erase(node);
 | 
						|
 | 
						|
            mMutex.unlock();
 | 
						|
            compile(*node, renderInfo, &timeLeft);
 | 
						|
            mMutex.lock();
 | 
						|
 | 
						|
            if (node->mCompiled < node->mDrawables.size())
 | 
						|
            {
 | 
						|
                // We did not compile the map fully.
 | 
						|
                // Place it back to queue to continue work in the next time.
 | 
						|
                mCompileSet.insert(node);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        mTimer.setStartTick();
 | 
						|
    }
 | 
						|
 | 
						|
    void CompositeMapRenderer::compile(CompositeMap& compositeMap, osg::RenderInfo& renderInfo, double* timeLeft) const
 | 
						|
    {
 | 
						|
        // if there are no more external references we can assume the texture is no longer required
 | 
						|
        if (compositeMap.mTexture->referenceCount() <= 1)
 | 
						|
        {
 | 
						|
            compositeMap.mCompiled = compositeMap.mDrawables.size();
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        osg::Timer timer;
 | 
						|
        osg::State& state = *renderInfo.getState();
 | 
						|
        osg::GLExtensions* ext = state.get<osg::GLExtensions>();
 | 
						|
 | 
						|
        if (!mFBO)
 | 
						|
            return;
 | 
						|
 | 
						|
        if (!ext->isFrameBufferObjectSupported)
 | 
						|
            return;
 | 
						|
 | 
						|
        osg::FrameBufferAttachment attach(compositeMap.mTexture);
 | 
						|
        mFBO->setAttachment(osg::Camera::COLOR_BUFFER, attach);
 | 
						|
        mFBO->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER);
 | 
						|
 | 
						|
        GLenum status = ext->glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
 | 
						|
 | 
						|
        if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
 | 
						|
        {
 | 
						|
            GLuint fboId = state.getGraphicsContext() ? state.getGraphicsContext()->getDefaultFboId() : 0;
 | 
						|
            ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId);
 | 
						|
            OSG_ALWAYS << "Error attaching FBO" << std::endl;
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        // inform State that Texture attribute has changed due to compiling of FBO texture
 | 
						|
        // should OSG be doing this on its own?
 | 
						|
        state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), osg::StateAttribute::TEXTURE);
 | 
						|
 | 
						|
        for (unsigned int i = compositeMap.mCompiled; i < compositeMap.mDrawables.size(); ++i)
 | 
						|
        {
 | 
						|
            osg::Drawable* drw = compositeMap.mDrawables[i];
 | 
						|
            osg::StateSet* stateset = drw->getStateSet();
 | 
						|
 | 
						|
            if (stateset)
 | 
						|
                renderInfo.getState()->pushStateSet(stateset);
 | 
						|
 | 
						|
            renderInfo.getState()->apply();
 | 
						|
 | 
						|
            glViewport(0, 0, compositeMap.mTexture->getTextureWidth(), compositeMap.mTexture->getTextureHeight());
 | 
						|
            drw->drawImplementation(renderInfo);
 | 
						|
 | 
						|
            if (stateset)
 | 
						|
                renderInfo.getState()->popStateSet();
 | 
						|
 | 
						|
            ++compositeMap.mCompiled;
 | 
						|
 | 
						|
            compositeMap.mDrawables[i] = nullptr;
 | 
						|
 | 
						|
            if (timeLeft)
 | 
						|
            {
 | 
						|
                *timeLeft -= timer.time_s();
 | 
						|
                timer.setStartTick();
 | 
						|
 | 
						|
                if (*timeLeft <= 0)
 | 
						|
                    break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (compositeMap.mCompiled == compositeMap.mDrawables.size())
 | 
						|
            compositeMap.mDrawables = std::vector<osg::ref_ptr<osg::Drawable>>();
 | 
						|
 | 
						|
        state.haveAppliedAttribute(osg::StateAttribute::VIEWPORT);
 | 
						|
 | 
						|
        GLuint fboId = state.getGraphicsContext() ? state.getGraphicsContext()->getDefaultFboId() : 0;
 | 
						|
        ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId);
 | 
						|
    }
 | 
						|
 | 
						|
    void CompositeMapRenderer::setMinimumTimeAvailableForCompile(double time)
 | 
						|
    {
 | 
						|
        mMinimumTimeAvailable = time;
 | 
						|
    }
 | 
						|
 | 
						|
    void CompositeMapRenderer::setTargetFrameRate(float framerate)
 | 
						|
    {
 | 
						|
        mTargetFrameRate = framerate;
 | 
						|
    }
 | 
						|
 | 
						|
    void CompositeMapRenderer::addCompositeMap(CompositeMap* compositeMap, bool immediate)
 | 
						|
    {
 | 
						|
        std::lock_guard<std::mutex> lock(mMutex);
 | 
						|
        if (immediate)
 | 
						|
            mImmediateCompileSet.insert(compositeMap);
 | 
						|
        else
 | 
						|
            mCompileSet.insert(compositeMap);
 | 
						|
    }
 | 
						|
 | 
						|
    void CompositeMapRenderer::setImmediate(CompositeMap* compositeMap)
 | 
						|
    {
 | 
						|
        std::lock_guard<std::mutex> lock(mMutex);
 | 
						|
        CompileSet::iterator found = mCompileSet.find(compositeMap);
 | 
						|
        if (found == mCompileSet.end())
 | 
						|
            return;
 | 
						|
        else
 | 
						|
        {
 | 
						|
            mImmediateCompileSet.insert(compositeMap);
 | 
						|
            mCompileSet.erase(found);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    unsigned int CompositeMapRenderer::getCompileSetSize() const
 | 
						|
    {
 | 
						|
        std::lock_guard<std::mutex> lock(mMutex);
 | 
						|
        return mCompileSet.size();
 | 
						|
    }
 | 
						|
 | 
						|
    CompositeMap::CompositeMap()
 | 
						|
        : mCompiled(0)
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    CompositeMap::~CompositeMap() {}
 | 
						|
 | 
						|
}
 |