diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index 42a44ceff..ddba8699f 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -53,9 +53,9 @@ void ChunkManager::reportStats(unsigned int frameNumber, osg::Stats *stats) cons stats->setAttribute(frameNumber, "Terrain Chunk", mCache->getCacheSize()); } -osg::ref_ptr ChunkManager::createCompositeMapRTT(osg::ref_ptr& texture) +osg::ref_ptr ChunkManager::createCompositeMapRTT() { - texture = new osg::Texture2D; + osg::ref_ptr texture = new osg::Texture2D; texture->setTextureWidth(mCompositeMapSize); texture->setTextureHeight(mCompositeMapSize); texture->setInternalFormat(GL_RGB); @@ -64,30 +64,17 @@ osg::ref_ptr ChunkManager::createCompositeMapRTT(osg::ref_ptrsetWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); - osg::ref_ptr camera (new osg::Camera); - camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); - camera->attach(osg::Camera::COLOR_BUFFER, texture); - camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); - camera->setViewMatrix(osg::Matrix::identity()); - camera->setProjectionMatrix(osg::Matrix::identity()); - camera->setProjectionResizePolicy(osg::Camera::FIXED); - camera->setClearColor(osg::Vec4(0.f, 0.f, 0.f, 1.f)); - camera->setClearMask(GL_COLOR_BUFFER_BIT); - camera->setViewport(0, 0, mCompositeMapSize, mCompositeMapSize); - camera->setRenderOrder(osg::Camera::PRE_RENDER, -1); - camera->setImplicitBufferAttachmentMask(osg::DisplaySettings::IMPLICIT_COLOR_BUFFER_ATTACHMENT); // no need for a depth buffer - - return camera; + return texture; } -void ChunkManager::createCompositeMapGeometry(float chunkSize, const osg::Vec2f& chunkCenter, const osg::Vec4f& texCoords, osg::Group* compositeMapNode) +void ChunkManager::createCompositeMapGeometry(float chunkSize, const osg::Vec2f& chunkCenter, const osg::Vec4f& texCoords, CompositeMap& compositeMap) { if (chunkSize > 1.f) { - createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(chunkSize/4.f, chunkSize/4.f), osg::Vec4f(texCoords.x() + texCoords.z()/2.f, texCoords.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMapNode); - createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(-chunkSize/4.f, chunkSize/4.f), osg::Vec4f(texCoords.x(), texCoords.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMapNode); - createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(chunkSize/4.f, -chunkSize/4.f), osg::Vec4f(texCoords.x() + texCoords.z()/2.f, texCoords.y()+texCoords.w()/2.f, texCoords.z()/2.f, texCoords.w()/2.f), compositeMapNode); - createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(-chunkSize/4.f, -chunkSize/4.f), osg::Vec4f(texCoords.x(), texCoords.y()+ texCoords.w()/2.f, texCoords.z()/2.f, texCoords.w()/2.f), compositeMapNode); + createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(chunkSize/4.f, chunkSize/4.f), osg::Vec4f(texCoords.x() + texCoords.z()/2.f, texCoords.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMap); + createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(-chunkSize/4.f, chunkSize/4.f), osg::Vec4f(texCoords.x(), texCoords.y(), texCoords.z()/2.f, texCoords.w()/2.f), compositeMap); + createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(chunkSize/4.f, -chunkSize/4.f), osg::Vec4f(texCoords.x() + texCoords.z()/2.f, texCoords.y()+texCoords.w()/2.f, texCoords.z()/2.f, texCoords.w()/2.f), compositeMap); + createCompositeMapGeometry(chunkSize/2.f, chunkCenter + osg::Vec2f(-chunkSize/4.f, -chunkSize/4.f), osg::Vec4f(texCoords.x(), texCoords.y()+texCoords.w()/2.f, texCoords.z()/2.f, texCoords.w()/2.f), compositeMap); } else { @@ -96,16 +83,17 @@ void ChunkManager::createCompositeMapGeometry(float chunkSize, const osg::Vec2f& float width = texCoords.z()*2.f; float height = texCoords.w()*2.f; - osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(left,top,0), osg::Vec3(width,0,0), osg::Vec3(0,height,0)); - geom->setTexCoordArray(1, geom->getTexCoordArray(0), osg::Array::BIND_PER_VERTEX); - std::vector > passes = createPasses(chunkSize, chunkCenter, true); for (std::vector >::iterator it = passes.begin(); it != passes.end(); ++it) { - osg::ref_ptr group = new osg::Group; - group->setStateSet(*it); - group->addChild(geom); - compositeMapNode->addChild(group); + osg::ref_ptr geom = osg::createTexturedQuadGeometry(osg::Vec3(left,top,0), osg::Vec3(width,0,0), osg::Vec3(0,height,0)); + geom->setUseDisplayList(false); // don't bother making a display list for an object that is just rendered once. + geom->setUseVertexBufferObjects(false); + geom->setTexCoordArray(1, geom->getTexCoordArray(0), osg::Array::BIND_PER_VERTEX); + + geom->setStateSet(*it); + + compositeMap.mDrawables.push_back(geom); } } } @@ -194,21 +182,19 @@ osg::ref_ptr ChunkManager::createChunk(float chunkSize, const osg::Ve if (useCompositeMap) { - osg::ref_ptr compositeMap; - osg::ref_ptr compositeMapNode = createCompositeMapRTT(compositeMap); - - createCompositeMapGeometry(chunkSize, chunkCenter, osg::Vec4f(0,0,1,1), compositeMapNode); + osg::ref_ptr compositeMap = new CompositeMap; + compositeMap->mTexture = createCompositeMapRTT(); - compositeMapNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + createCompositeMapGeometry(chunkSize, chunkCenter, osg::Vec4f(0,0,1,1), *compositeMap); - mCompositeMapRenderer->addCompositeMap(compositeMapNode, false); + mCompositeMapRenderer->addCompositeMap(compositeMap.get(), false); std::vector > passes2; passes2.push_back(new osg::StateSet); - passes2[0]->setTextureAttributeAndModes(0, compositeMap, osg::StateAttribute::ON); + passes2[0]->setTextureAttributeAndModes(0, compositeMap->mTexture, osg::StateAttribute::ON); geometry->setPasses(passes2); - transform->getOrCreateUserDataContainer()->addUserObject(compositeMapNode); + transform->getOrCreateUserDataContainer()->setUserData(compositeMap); } else { diff --git a/components/terrain/chunkmanager.hpp b/components/terrain/chunkmanager.hpp index c7c1566a8..08cf2d70c 100644 --- a/components/terrain/chunkmanager.hpp +++ b/components/terrain/chunkmanager.hpp @@ -27,6 +27,7 @@ namespace Terrain class TextureManager; class CompositeMapRenderer; class Storage; + class CompositeMap; /// @brief Handles loading and caching of terrain chunks class ChunkManager : public Resource::ResourceManager @@ -41,9 +42,9 @@ namespace Terrain private: osg::ref_ptr createChunk(float size, const osg::Vec2f& center, int lod, unsigned int lodFlags); - osg::ref_ptr createCompositeMapRTT(osg::ref_ptr& texture); + osg::ref_ptr createCompositeMapRTT(); - void createCompositeMapGeometry(float chunkSize, const osg::Vec2f& chunkCenter, const osg::Vec4f& texCoords, osg::Group* compositeMapNode); + void createCompositeMapGeometry(float chunkSize, const osg::Vec2f& chunkCenter, const osg::Vec4f& texCoords, CompositeMap& map); std::vector > createPasses(float chunkSize, const osg::Vec2f& chunkCenter, bool forCompositeMap); diff --git a/components/terrain/compositemaprenderer.cpp b/components/terrain/compositemaprenderer.cpp index 496162f7b..21d017623 100644 --- a/components/terrain/compositemaprenderer.cpp +++ b/components/terrain/compositemaprenderer.cpp @@ -2,39 +2,42 @@ #include -#include +#include +#include +#include namespace Terrain { CompositeMapRenderer::CompositeMapRenderer() : mNumCompilePerFrame(1) - , mLastFrame(0) { + setSupportsDisplayList(false); setCullingActive(false); -} -void CompositeMapRenderer::traverse(osg::NodeVisitor &nv) -{ - if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR) - return; + mFBO = new osg::FrameBufferObject; - if (mLastFrame == nv.getTraversalNumber()) - return; - mLastFrame = nv.getTraversalNumber(); + getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); +} +void CompositeMapRenderer::drawImplementation(osg::RenderInfo &renderInfo) const +{ mCompiled.clear(); unsigned int numCompiled = 0; OpenThreads::ScopedLock lock(mMutex); + if (mImmediateCompileSet.empty() && mCompileSet.empty()) + return; + while (!mImmediateCompileSet.empty()) { - osg::Node* node = *mImmediateCompileSet.begin(); + CompositeMap* node = *mImmediateCompileSet.begin(); mCompiled.insert(node); - node->accept(nv); + compile(*node, renderInfo); + mImmediateCompileSet.erase(mImmediateCompileSet.begin()); ++numCompiled; @@ -42,14 +45,63 @@ void CompositeMapRenderer::traverse(osg::NodeVisitor &nv) while (!mCompileSet.empty() && numCompiled <= mNumCompilePerFrame) { - osg::Node* node = *mCompileSet.begin(); - mCompiled.insert(node); + CompositeMap* node = *mCompileSet.begin(); - node->accept(nv); - mCompileSet.erase(mCompileSet.begin()); + compile(*node, renderInfo); ++numCompiled; + + mCompiled.insert(node); + mCompileSet.erase(mCompileSet.begin()); + } +} + +void CompositeMapRenderer::compile(CompositeMap &compositeMap, osg::RenderInfo &renderInfo) const +{ + osg::State& state = *renderInfo.getState(); + osg::GLExtensions* ext = state.get(); + + 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; + } + + for (unsigned int i=0; igetStateSet(); + + 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(); } + + state.haveAppliedAttribute(osg::StateAttribute::VIEWPORT); + + GLuint fboId = state.getGraphicsContext() ? state.getGraphicsContext()->getDefaultFboId() : 0; + ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId); } void CompositeMapRenderer::setNumCompilePerFrame(int num) @@ -57,20 +109,25 @@ void CompositeMapRenderer::setNumCompilePerFrame(int num) mNumCompilePerFrame = num; } -void CompositeMapRenderer::addCompositeMap(osg::Node *node, bool immediate) +void CompositeMapRenderer::addCompositeMap(CompositeMap* compositeMap, bool immediate) { OpenThreads::ScopedLock lock(mMutex); if (immediate) - mImmediateCompileSet.insert(node); + mImmediateCompileSet.insert(compositeMap); else - mCompileSet.insert(node); + mCompileSet.insert(compositeMap); } -void CompositeMapRenderer::setImmediate(osg::Node *node) +void CompositeMapRenderer::setImmediate(CompositeMap* compositeMap) { OpenThreads::ScopedLock lock(mMutex); - mImmediateCompileSet.insert(node); - mCompileSet.erase(node); + mImmediateCompileSet.insert(compositeMap); + mCompileSet.erase(compositeMap); +} + +CompositeMap::~CompositeMap() +{ + } diff --git a/components/terrain/compositemaprenderer.hpp b/components/terrain/compositemaprenderer.hpp index 53b38362f..c3579d8bb 100644 --- a/components/terrain/compositemaprenderer.hpp +++ b/components/terrain/compositemaprenderer.hpp @@ -1,46 +1,64 @@ #ifndef OPENMW_COMPONENTS_TERRAIN_COMPOSITEMAPRENDERER_H #define OPENMW_COMPONENTS_TERRAIN_COMPOSITEMAPRENDERER_H -#include +#include #include #include +namespace osg +{ + class FrameBufferObject; + class RenderInfo; + class Texture2D; +} + namespace Terrain { + class CompositeMap : public osg::Referenced + { + public: + ~CompositeMap(); + std::vector > mDrawables; + osg::ref_ptr mTexture; + }; + /** * @brief The CompositeMapRenderer is responsible for updating composite map textures in a blocking or non-blocking way. */ - class CompositeMapRenderer : public osg::Node + class CompositeMapRenderer : public osg::Drawable { public: CompositeMapRenderer(); - virtual void traverse(osg::NodeVisitor& nv); + virtual void drawImplementation(osg::RenderInfo& renderInfo) const; + + void compile(CompositeMap& compositeMap, osg::RenderInfo& renderInfo) const; /// Set the maximum number of (non-immediate) composite maps to compile per frame void setNumCompilePerFrame(int num); /// Add a composite map to be rendered - void addCompositeMap(osg::Node* node, bool immediate=false); + void addCompositeMap(CompositeMap* map, bool immediate=false); /// Mark this composite map to be required for the current frame - void setImmediate(osg::Node* node); + void setImmediate(CompositeMap* map); private: unsigned int mNumCompilePerFrame; - unsigned int mLastFrame; - typedef std::set > CompileSet; + typedef std::set > CompileSet; + + mutable CompileSet mCompileSet; + mutable CompileSet mImmediateCompileSet; - CompileSet mCompileSet; - CompileSet mImmediateCompileSet; + mutable CompileSet mCompiled; - CompileSet mCompiled; + mutable OpenThreads::Mutex mMutex; - OpenThreads::Mutex mMutex; + osg::ref_ptr mFBO; }; } diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index cb49f3392..95252f513 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -329,14 +329,10 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) if (entry.mVisible) { osg::UserDataContainer* udc = entry.mRenderingNode->getUserDataContainer(); - if (udc && udc->getNumUserObjects() > 0) + if (udc && udc->getUserData()) { - osg::Node* compositeMapNode = udc->getUserObject(0)->asNode(); - if (compositeMapNode) - { - mCompositeMapRenderer->setImmediate(compositeMapNode); - udc->removeUserObject(0); - } + mCompositeMapRenderer->setImmediate(static_cast(udc->getUserData())); + udc->setUserData(NULL); } entry.mRenderingNode->accept(nv); } diff --git a/components/terrain/world.cpp b/components/terrain/world.cpp index 401252334..cbd4327c3 100644 --- a/components/terrain/world.cpp +++ b/components/terrain/world.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -27,9 +28,20 @@ World::World(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSyst mTerrainRoot->setName("Terrain Root"); + osg::ref_ptr compositeCam = new osg::Camera; + compositeCam->setRenderOrder(osg::Camera::PRE_RENDER, -1); + compositeCam->setProjectionMatrix(osg::Matrix::identity()); + compositeCam->setViewMatrix(osg::Matrix::identity()); + compositeCam->setReferenceFrame(osg::Camera::ABSOLUTE_RF); + compositeCam->setClearMask(0); + compositeCam->setNodeMask(preCompileMask); + mCompositeMapCamera = compositeCam; + + compileRoot->addChild(compositeCam); + + mCompositeMapRenderer = new CompositeMapRenderer; - mCompositeMapRenderer->setNodeMask(preCompileMask); - compileRoot->addChild(mCompositeMapRenderer); + compositeCam->addChild(mCompositeMapRenderer); mParent->addChild(mTerrainRoot); @@ -46,7 +58,9 @@ World::~World() mResourceSystem->removeResourceManager(mTextureManager.get()); mParent->removeChild(mTerrainRoot); - mCompositeMapRenderer->getParent(0)->removeChild(mCompositeMapRenderer); + + mCompositeMapCamera->removeChild(mCompositeMapRenderer); + mCompositeMapCamera->getParent(0)->removeChild(mCompositeMapCamera); delete mStorage; } diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index 6cba6c5b6..59c390319 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -97,6 +97,8 @@ namespace Terrain osg::ref_ptr mParent; osg::ref_ptr mTerrainRoot; + + osg::ref_ptr mCompositeMapCamera; osg::ref_ptr mCompositeMapRenderer; Resource::ResourceSystem* mResourceSystem;