diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index e63756ecd..e1ebf781c 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -46,23 +46,6 @@ namespace { -// Proxy to forward a Drawable's draw call to RenderManager::drawFrame -class Renderable : public osg::Drawable { - osgMyGUI::RenderManager *mParent; - - virtual void drawImplementation(osg::RenderInfo &renderInfo) const - { mParent->drawFrame(renderInfo); } - -public: - Renderable(osgMyGUI::RenderManager *parent=nullptr) : mParent(parent) { } - Renderable(const Renderable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) - : osg::Drawable(copy, copyop) - , mParent(copy.mParent) - { } - - META_Object(osgMyGUI, Renderable) -}; - // Proxy to forward an OSG resize event to RenderManager::setViewSize class ResizeHandler : public osgGA::GUIEventHandler { osgMyGUI::RenderManager *mParent; @@ -94,6 +77,147 @@ public: namespace osgMyGUI { +class Drawable : public osg::Drawable { + osgMyGUI::RenderManager *mParent; + + // Stage 0: update widget animations and controllers. Run during the Update traversal. + class FrameUpdate : public osg::Drawable::UpdateCallback + { + public: + FrameUpdate() + : mRenderManager(NULL) + { + } + + void setRenderManager(osgMyGUI::RenderManager* renderManager) + { + mRenderManager = renderManager; + } + + virtual void update(osg::NodeVisitor*, osg::Drawable*) + { + if (mRenderManager) + mRenderManager->update(); + } + + private: + osgMyGUI::RenderManager* mRenderManager; + }; + + // Stage 1: collect draw calls. Run during the Cull traversal. + class CollectDrawCalls : public osg::Drawable::CullCallback + { + public: + CollectDrawCalls() + : mRenderManager(NULL) + { + } + + void setRenderManager(osgMyGUI::RenderManager* renderManager) + { + mRenderManager = renderManager; + } + + virtual bool cull(osg::NodeVisitor*, osg::Drawable*, osg::State*) const + { + if (!mRenderManager) + return false; + + mRenderManager->collectDrawCalls(); + return false; + } + + private: + osgMyGUI::RenderManager* mRenderManager; + }; + + // Stage 2: execute the draw calls. Run during the Draw traversal. May run in parallel with the update traversal of the next frame. + virtual void drawImplementation(osg::RenderInfo &renderInfo) const + { + osg::State *state = renderInfo.getState(); + state->disableAllVertexArrays(); + state->setClientActiveTextureUnit(0); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + for (std::vector::const_iterator it = mBatchVector.begin(); it != mBatchVector.end(); ++it) + { + const Batch& batch = *it; + osg::VertexBufferObject *vbo = batch.mVertexBuffer; + osg::Texture2D* texture = batch.mTexture; + if(texture) + state->applyTextureAttribute(0, texture); + + osg::GLBufferObject* bufferobject = state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; + if (bufferobject) + { + state->bindVertexBufferObject(bufferobject); + + glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)NULL + 12); + glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL + 16); + } + else + { + glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer()); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer() + 12); + glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer() + 16); + } + + glDrawArrays(GL_TRIANGLES, 0, batch.mVertexCount); + } + + state->unbindVertexBufferObject(); + state->dirtyAllVertexArrays(); + state->disableAllVertexArrays(); + } + +public: + Drawable(osgMyGUI::RenderManager *parent = nullptr) : mParent(parent) + { + setSupportsDisplayList(false); + + osg::ref_ptr collectDrawCalls = new CollectDrawCalls; + collectDrawCalls->setRenderManager(mParent); + setCullCallback(collectDrawCalls); + + osg::ref_ptr frameUpdate = new Drawable::FrameUpdate; + frameUpdate->setRenderManager(mParent); + setUpdateCallback(frameUpdate); + } + Drawable(const Drawable ©, const osg::CopyOp ©op=osg::CopyOp::SHALLOW_COPY) + : osg::Drawable(copy, copyop) + , mParent(copy.mParent) + { + } + + // Defines the necessary information for a draw call + struct Batch + { + // May be empty + osg::ref_ptr mTexture; + + osg::ref_ptr mVertexBuffer; + size_t mVertexCount; + }; + + void addBatch(const Batch& batch) + { + mBatchVector.push_back(batch); + } + + void clear() + { + mBatchVector.clear(); + } + + META_Object(osgMyGUI, Drawable) + +private: + std::vector mBatchVector; +}; + class OSGVertexBuffer : public MyGUI::IVertexBuffer { osg::ref_ptr mBuffer; @@ -213,13 +337,11 @@ void RenderManager::initialise() mUpdate = false; - osg::ref_ptr drawable = new Renderable(this); - drawable->setSupportsDisplayList(false); - drawable->setUseVertexBufferObjects(true); - drawable->setDataVariance(osg::Object::DYNAMIC); + mDrawable = new Drawable(this); + mDrawable->setDataVariance(osg::Object::DYNAMIC); osg::ref_ptr geode = new osg::Geode; - geode->addDrawable(drawable.get()); + geode->addDrawable(mDrawable.get()); osg::ref_ptr camera = new osg::Camera(); camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF); @@ -265,61 +387,25 @@ void RenderManager::destroyVertexBuffer(MyGUI::IVertexBuffer *buffer) void RenderManager::begin() { - osg::State *state = mRenderInfo->getState(); - state->disableAllVertexArrays(); - state->setClientActiveTextureUnit(0); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); } void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count) { - osg::State *state = mRenderInfo->getState(); - osg::VertexBufferObject *vbo = static_cast(buffer)->getBuffer(); - MYGUI_PLATFORM_ASSERT(vbo, "Vertex buffer is not created"); + Drawable::Batch batch; + batch.mVertexCount = count; + batch.mVertexBuffer = static_cast(buffer)->getBuffer(); + if (texture) + batch.mTexture = static_cast(texture)->getTexture(); - if(texture) - { - osg::Texture2D *tex = static_cast(texture)->getTexture(); - MYGUI_PLATFORM_ASSERT(tex, "Texture is not created"); - state->applyTextureAttribute(0, tex); - } - - osg::GLBufferObject* bufferobject = state->isVertexBufferObjectSupported() ? vbo->getOrCreateGLBufferObject(state->getContextID()) : 0; - if (bufferobject) - { - state->bindVertexBufferObject(bufferobject); - - glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)NULL + 12); - glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)NULL + 16); - } - else - { - glVertexPointer(3, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer()); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer() + 12); - glTexCoordPointer(2, GL_FLOAT, sizeof(MyGUI::Vertex), (char*)vbo->getArray(0)->getDataPointer() + 16); - } - - glDrawArrays(GL_TRIANGLES, 0, count); + mDrawable->addBatch(batch); } void RenderManager::end() { - osg::State *state = mRenderInfo->getState(); - state->unbindVertexBufferObject(); - state->dirtyAllVertexArrays(); - state->disableAllVertexArrays(); } -void RenderManager::drawFrame(osg::RenderInfo &renderInfo) +void RenderManager::update() { - MyGUI::Gui *gui = MyGUI::Gui::getInstancePtr(); - if(gui == nullptr) return; - - mRenderInfo = &renderInfo; - static MyGUI::Timer timer; static unsigned long last_time = timer.getMilliseconds(); unsigned long now_time = timer.getMilliseconds(); @@ -328,10 +414,12 @@ void RenderManager::drawFrame(osg::RenderInfo &renderInfo) onFrameEvent((float)((double)(time) / (double)1000)); last_time = now_time; +} - begin(); +void RenderManager::collectDrawCalls() +{ + mDrawable->clear(); onRenderToTarget(this, mUpdate); - end(); mUpdate = false; } diff --git a/components/myguiplatform/myguirendermanager.hpp b/components/myguiplatform/myguirendermanager.hpp index 05d0f9a5a..342050d90 100644 --- a/components/myguiplatform/myguirendermanager.hpp +++ b/components/myguiplatform/myguirendermanager.hpp @@ -25,10 +25,13 @@ namespace osg namespace osgMyGUI { +class Drawable; + class RenderManager : public MyGUI::RenderManager, public MyGUI::IRenderTarget { osg::ref_ptr mViewer; osg::ref_ptr mSceneRoot; + osg::ref_ptr mDrawable; Resource::TextureManager* mTextureManager; MyGUI::IntSize mViewSize; @@ -80,20 +83,25 @@ public: /** @see RenderManager::getTexture */ virtual MyGUI::ITexture* getTexture(const std::string &name); + // Called by the update traversal + void update(); + // Called by the cull traversal /** @see IRenderTarget::begin */ virtual void begin(); /** @see IRenderTarget::end */ virtual void end(); /** @see IRenderTarget::doRender */ virtual void doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *texture, size_t count); + /** @see IRenderTarget::getInfo */ virtual const MyGUI::RenderTargetInfo& getInfo() { return mInfo; } bool checkTexture(MyGUI::ITexture* _texture); /*internal:*/ - void drawFrame(osg::RenderInfo &renderInfo); + + void collectDrawCalls(); void setViewSize(int width, int height); };