mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 07:56:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			216 lines
		
	
	
	
		
			5.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
	
		
			5.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "compositemaprenderer.hpp"
 | 
						|
 | 
						|
#include <osg/FrameBufferObject>
 | 
						|
#include <osg/Texture2D>
 | 
						|
#include <osg/RenderInfo>
 | 
						|
 | 
						|
#include <components/sceneutil/unrefqueue.hpp>
 | 
						|
#include <components/sceneutil/workqueue.hpp>
 | 
						|
 | 
						|
#include <algorithm>
 | 
						|
 | 
						|
namespace Terrain
 | 
						|
{
 | 
						|
 | 
						|
CompositeMapRenderer::CompositeMapRenderer()
 | 
						|
    : mTargetFrameRate(120)
 | 
						|
    , mMinimumTimeAvailable(0.0025)
 | 
						|
{
 | 
						|
    setSupportsDisplayList(false);
 | 
						|
    setCullingActive(false);
 | 
						|
 | 
						|
    mFBO = new osg::FrameBufferObject;
 | 
						|
 | 
						|
    mUnrefQueue = new SceneUtil::UnrefQueue;
 | 
						|
 | 
						|
    getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
 | 
						|
}
 | 
						|
 | 
						|
CompositeMapRenderer::~CompositeMapRenderer()
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void CompositeMapRenderer::setWorkQueue(SceneUtil::WorkQueue* workQueue)
 | 
						|
{
 | 
						|
    mWorkQueue = workQueue;
 | 
						|
}
 | 
						|
 | 
						|
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);
 | 
						|
 | 
						|
    if (mWorkQueue)
 | 
						|
        mUnrefQueue->flush(mWorkQueue.get());
 | 
						|
 | 
						|
    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;
 | 
						|
 | 
						|
        if (mWorkQueue)
 | 
						|
        {
 | 
						|
            mUnrefQueue->push(compositeMap.mDrawables[i]);
 | 
						|
        }
 | 
						|
        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()
 | 
						|
{
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
}
 |