Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
5.8 kB · 179 lines
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180#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; }
CompositeMapRenderer::~CompositeMapRenderer() = default;
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 (size_t 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); } }
size_t CompositeMapRenderer::getCompileSetSize() const { std::lock_guard<std::mutex> lock(mMutex); return mCompileSet.size(); }
CompositeMap::CompositeMap() : mCompiled(0) { }
CompositeMap::~CompositeMap() {}
}