mirror of https://github.com/OpenMW/openmw.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
5.7 KiB
C++
182 lines
5.7 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);
|
|
mMutex.lock();
|
|
}
|
|
|
|
const auto deadline = std::chrono::steady_clock::now() + std::chrono::duration<double>(availableTime);
|
|
while (!mCompileSet.empty() && std::chrono::steady_clock::now() < deadline)
|
|
{
|
|
osg::ref_ptr<CompositeMap> node = *mCompileSet.begin();
|
|
mCompileSet.erase(node);
|
|
|
|
mMutex.unlock();
|
|
compile(*node, renderInfo);
|
|
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) 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 (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() {}
|
|
|
|
}
|