Hi Sebastian, I am not using Qt but faced the same problem. So here is a 'hack' for Windows if it helps:
osgViewer::CompositeViewer::Windows wins; viewer->getWindows(wins); while (!viewer->done()) { #if defined(_WIN32) MSG msg; if (::PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) { ::GetMessage(&msg, NULL, 0, 0); if (wins.size()) { osgViewer::GraphicsHandleWin32 *hdl = dynamic_cast<osgViewer::GraphicsHandleWin32*>(wins.at(0)); if(hdl) { WNDPROC fWndProc = (WNDPROC)::GetWindowLongPtr(hdl->getHWND(), GWLP_WNDPROC); if (fWndProc && hdl->getHWND()) { ::CallWindowProc(fWndProc,hdl->getHWND(),msg.message, msg.wParam, msg.lParam); } } } } #endif On Mon, Aug 3, 2015 at 3:43 PM, Sebastian Messerschmidt < sebastian.messerschm...@gmx.de> wrote: > Hi Can, > > Have you created a full code example yet? > My problem right now is the lack of keyboard events being passed through > to OSG. Any hints on this? > > Cheers > Sebastian > > Hi, >> >> I have been working Qt5 integration for my current rendering application >> implementing deferred rendering and came up with couple of solutions. I >> want to share it with the people struggling Qt5 integration while waiting >> official stable release :) >> >> Since the current stable release is OSG 3.2.1, this will be based on that >> version. >> >> For Qt5 version, I recommend using >= 5.4, because in earlier versions >> you have to do a lot by yourself. In 5.4, at least you have QOpenGLWidget. >> >> Even though I will give solution for widget, this can be applied to >> QWindow solution as well. The codes will be bits and pieces, unfortunately >> cannot share full working code. >> >> Firstly, create a new widget rendering class subclassing QOpenGLWidget. >> This one is almost same as the QGLWidget version of it. >> >> >> Code: >> >> class RenderWidget : public [b]QOpenGLWidget[/b] >> { >> Q_OBJECT >> public: >> RenderWidget(QWidget* parent = 0, Qt::WindowFlags f = 0); >> ~RenderWidget(); >> >> protected: >> virtual void initializeGL(); >> virtual void paintGL(); >> virtual void resizeGL(int width, int height); >> >> osg::ref_ptr<osgViewer::GraphicsWindow> gw; >> osg::ref_ptr<osgViewer::Viewer> viewer; >> >> private: >> QTimer heartbeat; >> }; >> >> RenderWidget::RenderWidget(QWidget* parent, Qt::WindowFlags f) >> { >> // instead of osgViewer::setUpViewerAsEmbeddedInWindow, we are going >> to >> // inject our osg::State subclass >> gw = new GraphicsWindowEx(0, 0, width(), height()); >> viewer = new osgViewer::Viewer(); >> viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded); >> // setup viewer's camera etc. >> // In my case, I don't want the base camera to clear anything >> // I have a lot of other cameras queued as FBO rendering >> viewer->getCamera()->setViewport(0, 0, width(), height()) >> viewer->getCamera()->setGraphicsContext(gw); >> viewer->getCamera()->setClearMask(0); >> //... >> connect(&heartbeat, SIGNAL(timeout()), this, SLOT(update()), >> Qt::QueuedConnection); >> hearbeat.start(10); >> } >> >> void RenderWidget::initializeGL() >> { >> viewer->realize(); >> } >> >> void RenderWidget::paintGL() >> { >> static_cast<StateEx >> *>(&state)->setDefaultFbo(defaultFramebufferObject()); >> >> viewer->frame(); >> // OR if you want to mix OSG with Qt 2D API >> QPainter painter(this); >> painter.beginNativePainting(); >> viewer->frame(); >> painter.endNativePainting(); >> // calculate fps... >> painter.setPen(Qt::white); >> painter.drawText(width() - 100, 10, 50, 25, Qt::AlignLeft, >> QString::number(fps)); >> painter.end(); >> } >> >> void RenderWidget::resizeGL(int width, int height) >> { >> gw->getEventQueue()->windowResize(0, 0, width, height); >> gw->resized(0, 0, width, height); >> //... >> } >> >> >> >> >> The difference between old QGLWidget and QOpenGLWidget is how they handle >> the rendering in the background. QOpenGLWidget is using QOffscreenSurface >> and QFrameBufferObject to render its content. The main problem of the >> current OSG integration is that it does not expect a superior FBO as main >> framebuffer. Like in my case, if you are using a lot of FBOs, some point >> OSG unbinds them and returns to direct drawing or leaves the last FBO bound >> after drawing. However, it should return(bind) to our superior FBO used by >> QOpenGLWidget. >> >> Let me explain it with the source code of OSG. >> >> >> Code: >> >> void RenderStage::drawInner(osg::RenderInfo& renderInfo, >> osgUtil::RenderLeaf*& previous, bool& doCopyTexture) >> { >> //... >> osg::State& state = *renderInfo.getState(); >> >> osg::FBOExtensions* fbo_ext = _fbo.valid() ? >> osg::FBOExtensions::instance(state.getContextID(),true) : 0; >> bool fbo_supported = fbo_ext && fbo_ext->isSupported(); >> >> bool using_multiple_render_targets = fbo_supported && >> _fbo->hasMultipleRenderingTargets(); >> >> if (!using_multiple_render_targets) >> { >> #if !defined(OSG_GLES1_AVAILABLE) && >> !defined(OSG_GLES2_AVAILABLE) >> >> if( getDrawBufferApplyMask() ) >> glDrawBuffer(_drawBuffer); >> >> if( getReadBufferApplyMask() ) >> glReadBuffer(_readBuffer); >> >> #endif >> } >> >> if (fbo_supported) >> { >> _fbo->apply(state); >> } >> RenderBin::draw(renderInfo,previous); >> //... >> } >> >> >> >> >> As you can see, _fbo->apply(state); is the only point where FBO of the >> camera (which comes from our osg::Camera and RenderStage::runCameraSetUp) >> is bound before drawing our geometry etc. However, there is no line to >> handle returning back to FBO of QOpenGLWidget. Even we put a empty FBO as a >> last camera, it will executes following line: >> >> >> Code: >> >> void FrameBufferObject::apply(State &state, BindTarget target) const >> { >> //... >> if (_attachments.empty()) >> { >> ext->glBindFramebuffer(target, 0); >> return; >> } >> //... >> } >> >> >> >> >> So basicly, it switches back to direct rendering because of 0 argument. >> Therefore, we have to inject default FBO of QOpenGLWidget somehow. You >> might already notice two special lines in paintGL() and constructor methods >> of RenderWidget implementation. We are going to subclass osg::State and >> osgViewer::GraphicsWindow. Here are the classes: >> >> >> Code: >> >> >> class StateEx : public osg::State >> { >> public: >> StateEx(); >> >> inline void setDefaultFbo(GLuint fbo); >> inline GLuint getDefaultFbo() const; >> >> protected: >> GLuint defaultFbo; >> }; >> >> StateEx::StateEx() : >> defaultFbo(0) >> { >> } >> >> inline void StateEx::setDefaultFbo(GLuint fbo) >> { >> defaultFbo = fbo; >> } >> >> inline GLuint getDefaultFbo() const >> { >> return defaultFbo; >> } >> >> >> >> >> Code: >> >> class GraphicsWindowEx : public osgViewer::GraphicsWindow >> { >> public: >> GraphicsWindowEx(osg::GraphicsContext::Traits* traits); >> GraphicsWindowEx(int x, int y, int width, int height); >> >> void init(); >> >> virtual bool isSameKindAs(const osg::Object* object) const { return >> dynamic_cast<const GraphicsWindowEx *>(object) != 0; } >> virtual const char* libraryName() const { return ""; } >> virtual const char* className() const { return "GraphicsWindowEx"; } >> >> // dummy implementations, assume that graphics context is *always* >> current and valid. >> virtual bool valid() const { return true; } >> virtual bool realizeImplementation() { return true; } >> virtual bool isRealizedImplementation() const { return true; } >> virtual void closeImplementation() {} >> virtual bool makeCurrentImplementation() { return true; } >> virtual bool releaseContextImplementation() { return true; } >> virtual void swapBuffersImplementation() {} >> virtual void grabFocus() {} >> virtual void grabFocusIfPointerInWindow() {} >> virtual void raiseWindow() {} >> }; >> >> GraphicsWindowEx::GraphicsWindowEx(osg::GraphicsContext::Traits* traits) >> { >> _traits = traits; >> init(); >> } >> >> GraphicsWindowEx::GraphicsWindowEx(int x, int y, int width, int height); >> { >> _traits = new osg::GraphicsContext::Traits(); >> _traits->x = x; >> _traits->x = y; >> _traits->width = width; >> _traits->height = height; >> >> init(); >> } >> >> void GraphicsWindowEx::init() >> { >> if(valid()) >> { >> // inject our "extended" state >> setState(new StateEx()); >> getState()->setGraphicsContext(this); >> if (_traits.valid() && _traits->sharedContext.valid()) >> { >> >> getState()->setContextID(_traits->sharedContext->getState()->getContextID() >> ); >> incrementContextIDUsageCount(getState()->getContextID()); >> } >> else >> { >> >> getState()->setContextID(osg::GraphicsContext::createNewContextID()); >> } >> } >> } >> >> >> >> >> Now, our rendering knows the default FBO of the QOpenGLWidget so with >> custom RenderStage we can use this information. Only method we have to >> override is drawInner. >> >> >> Code: >> >> void RenderStageEx::drawInner(osg::RenderInfo& renderInfo, >> osgUtil::RenderLeaf*& previous, bool& doCopyTexture) >> { >> //... >> osg::State& state = *renderInfo.getState(); >> osg::FBOExtensions* fbo_ext = >> osg::FBOExtensions::instance(state.getContextID(), true); >> bool fbo_supported = fbo_ext && fbo_ext->isSupported(); >> if (fbo_supported) >> { >> if(_fbo.valid()) >> { >> if (!_fbo->hasMultipleRenderingTargets()) >> { >> #if !defined(OSG_GLES1_AVAILABLE) && >> !defined(OSG_GLES2_AVAILABLE) >> >> if( getDrawBufferApplyMask() ) >> glDrawBuffer(_drawBuffer); >> >> if( getReadBufferApplyMask() ) >> glReadBuffer(_readBuffer); >> >> #endif >> } >> >> _fbo->apply(state); >> } >> else >> >> fbo_ext->glBindFramebuffer(osg::FrameBufferObject::READ_DRAW_FRAMEBUFFER, >> static_cast<StateEx *>(&state)->getDefaultFbo()); >> } >> RenderBin::draw(renderInfo,previous); >> //... >> } >> >> >> >> >> After all this hussle, the most strange part of this solutions is >> extending osgUtil::CullVisitor. Unfortunately, there is no easy way to >> inject our RenderStageEx into the rendering pipeline. To solve it, I have >> overriden the apply(osg::Camera& camera) method. Actually almost all the >> code come from the original source code but two special care should be >> given. Firstly, here is what I did: >> >> >> Code: >> >> >> void CullVisitorEx::apply(osg::Camera &camera) >> { >> //... >> if(camera.getRenderOrder() == osg::Camera::NESTED_RENDER) >> { >> handle_cull_callbacks_and_traverse(camera); >> } >> else >> { >> osgUtil::RenderStage *prevRenderStage = >> getCurrentRenderBin()->getStage(); >> osg::ref_ptr<RenderStageCacheEx> rsCache = >> dynamic_cast<RenderStageCacheEx *>(camera.getRenderingCache()); >> if(!rsCache) >> { >> rsCache = new RenderStageCacheEx(); >> camera.setRenderingCache(rsCache); >> } >> >> osg::ref_ptr<osgUtil::RenderStage> rtts = >> rsCache->getRenderStage(this); >> if(!rtts) >> { >> rtts = new RenderStageEx(); >> >> //... >> } >> else >> rtts->reset(); >> >> //... >> } >> >> //... >> } >> >> >> >> >> I kept only the parts that changed. Instead of new >> osgUtil::RenderStage(), we should call new RenderStageEx(). Unfortunately, >> renderstage caching implementation is hidden (implemented inside CPP) so >> you have to create your own RenderStageCache from scratch. Just copy the >> source code of it into the beginning of your CullVisitorEx.cpp and rename >> it. >> >> If you can manage to properly inject all these classes into your project, >> you can use any combination of FBO rendering with Qt5 and OSG 3.2.1. I have >> struggled a lot to make it work in current stable release. Hope this helps. >> >> P.S. I am preparing full source code and post it later. >> >> Thank you! >> >> Happy coding, >> Can[/code] >> >> ------------------ >> Read this topic online here: >> http://forum.openscenegraph.org/viewtopic.php?p=64403#64403 >> >> >> >> >> >> _______________________________________________ >> osg-users mailing list >> osg-users@lists.openscenegraph.org >> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org >> > > _______________________________________________ > osg-users mailing list > osg-users@lists.openscenegraph.org > http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org > -- trajce nikolov nick
_______________________________________________ osg-users mailing list osg-users@lists.openscenegraph.org http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org