diff --git a/modules/gfx/pymod/export_scene.cc b/modules/gfx/pymod/export_scene.cc index f67e90ccef4820c3cb08f515fe8d8a6d8d155f07..746c958f7c8ee041252b79687e2cfb0c4a029342 100644 --- a/modules/gfx/pymod/export_scene.cc +++ b/modules/gfx/pymod/export_scene.cc @@ -108,8 +108,6 @@ void export_Scene() void (Scene::*remove2)(const String&) = &Scene::Remove; void (Scene::*center_on1)(const String&) = &Scene::CenterOn; void (Scene::*center_on2)(const GfxObjP&) = &Scene::CenterOn; - bool (Scene::*start_offscreen_mode1)(unsigned int, unsigned int) = &Scene::StartOffscreenMode; - bool (Scene::*start_offscreen_mode2)(unsigned int, unsigned int, int) = &Scene::StartOffscreenMode; class_<Viewport>("Viewport", init<>()) .def_readwrite("x", &Viewport::x) .def_readwrite("y", &Viewport::y) @@ -249,9 +247,6 @@ void export_Scene() .add_property("ao_quality",&Scene::GetAmbientOcclusionQuality,&Scene::SetAmbientOcclusionQuality) .add_property("ao_size",&Scene::GetAmbientOcclusionSize,&Scene::SetAmbientOcclusionSize) .def("AttachObserver",&Scene::AttachObserver) - .def("StartOffscreenMode",start_offscreen_mode1) - .def("StartOffscreenMode",start_offscreen_mode2) - .def("StopOffscreenMode",&Scene::StopOffscreenMode) .def("SetShadingMode",&Scene::SetShadingMode) .def("SetBeacon",&Scene::SetBeacon) .add_property("root_node", &Scene::GetRootNode) diff --git a/modules/gfx/src/gfx_object.cc b/modules/gfx/src/gfx_object.cc index b265db7315ecb6010a519c90df68d8b508f63988..97e235f418f2e50dee56a33d55f285919d138175 100644 --- a/modules/gfx/src/gfx_object.cc +++ b/modules/gfx/src/gfx_object.cc @@ -151,13 +151,8 @@ void GfxObj::RenderGL(RenderPass pass) glMatrixMode(GL_MODELVIEW); glPushMatrix(); glMultMatrix(transform_.GetTransposedMatrix().Data()); - if(Scene::Instance().InOffscreenMode()) { - LOG_TRACE("applying material"); - mat_.RenderGL(); - } else { - LOG_TRACE("applying material display list"); - glCallList(mat_dlist_); - } + LOG_TRACE("applying material display list"); + glCallList(mat_dlist_); LOG_TRACE("calling custom render gl pass " << pass); /* diff --git a/modules/gfx/src/glwin_base.hh b/modules/gfx/src/glwin_base.hh index 7486540d5a8e8807ec4cacfd63366fd50a1d0372..77d30ee76ea8cedb30a80d615b74e968439b65a8 100644 --- a/modules/gfx/src/glwin_base.hh +++ b/modules/gfx/src/glwin_base.hh @@ -26,6 +26,7 @@ */ #include <ost/gfx/module_config.hh> +#include <ost/message.hh> namespace ost { namespace gfx { @@ -42,6 +43,25 @@ public: virtual bool HasStereo() const = 0; virtual bool HasMultisample() const = 0; + + // The GLWin is supposed to setup the OpenGL resources. To avoid implementing + // our own offscreen buffers, image export from OpenGL also happens here + virtual void Export(const String& fname, unsigned int width, + unsigned int height, bool transparent) { + throw ost::Error("Image export not implemented for this GLWin"); + } + + virtual void Export(const String& fname, unsigned int width, + unsigned int height, int max_samples, + bool transparent) { + throw ost::Error("Image export with multi-sampling not implemented for " + "this GLWin"); + } + + virtual void Export(const String& fname, bool transparent) { + throw ost::Error("Image export not implemented for this GLWin"); + } + }; }} diff --git a/modules/gfx/src/scene.cc b/modules/gfx/src/scene.cc index 4f3cf2a1c7df2f0a05f8ac65bf51756e8efc6e65..1ce2a44ebfa553a035c5cb285fa9f97b5c493409 100644 --- a/modules/gfx/src/scene.cc +++ b/modules/gfx/src/scene.cc @@ -52,7 +52,6 @@ #include "entity.hh" #include "exporter.hh" #include "povray.hh" -#include "offscreen_buffer.hh" #if OST_SHADER_SUPPORT_ENABLED # include "shader.hh" @@ -117,9 +116,6 @@ Scene::Scene(): auto_autoslab_(true), do_autoslab_(true), autoslab_mode_(0), - offscreen_flag_(false), - main_offscreen_buffer_(0), - old_vp_(), def_shading_mode_("default"), selection_mode_(1), test_flag_(false), @@ -592,7 +588,7 @@ void Scene::InitGL(bool full) void Scene::RequestRedraw() { - if (win_ && !offscreen_flag_) { + if (win_) { win_->DoRefresh(); } } @@ -602,19 +598,6 @@ void Scene::StatusMessage(const String& s) if(win_) win_->StatusMessage(s); } -void Scene::SetBackground(const Color& c) -{ - background_=c; - bg_mode_=0; - if(gl_init_) { - this->ActivateGLContext(); - //glClearColor(c.Red(),c.Green(),c.Blue(),c.Alpha()); - glClearColor(c.Red(),c.Green(),c.Blue(),0.0); - SetFogColor(c); - RequestRedraw(); - } -} - namespace { void c2d(const Color& c, unsigned char* d) { d[0]=static_cast<unsigned char>(c.GetRed()*255.0); @@ -655,6 +638,19 @@ void Scene::set_bg() } } +void Scene::SetBackground(const Color& c) +{ + + background_=c; + bg_mode_=0; + if(gl_init_) { + this->ActivateGLContext(); + glClearColor(c.Red(),c.Green(),c.Blue(),0.0); + SetFogColor(c); + RequestRedraw(); + } +} + void Scene::SetBackground(const Gradient& g) { bg_grad_=g; @@ -1629,178 +1625,33 @@ uint Scene::GetSelectionMode() const return selection_mode_; } -bool Scene::StartOffscreenMode(unsigned int width, unsigned int height) { - return StartOffscreenMode(width,height,2); -} - -bool Scene::StartOffscreenMode(unsigned int width, unsigned int height, int max_samples) -{ - LOG_DEBUG("Scene: starting offscreen rendering mode " << width << "x" << height); - if(main_offscreen_buffer_) return false; - OffscreenBufferFormat obf; - if(max_samples>0) { - obf.multisample=true; - obf.samples=max_samples; - } else { - obf.multisample=false; - } - main_offscreen_buffer_ = new OffscreenBuffer(width,height,obf,true); - - if(!main_offscreen_buffer_->IsValid()) { - LOG_ERROR("Scene: error during offscreen buffer creation"); - delete main_offscreen_buffer_; - main_offscreen_buffer_=0; - return false; - } - old_vp_[0]=vp_width_; - old_vp_[1]=vp_height_; - this->ActivateGLContext(); - offscreen_flag_=true; - root_node_->ContextSwitch(); - -#if OST_SHADER_SUPPORT_ENABLED - String shader_name = !def_shading_mode_.empty() ? def_shading_mode_ : Shader::Instance().GetCurrentName(); -#endif - - LOG_DEBUG("Scene: initializing GL"); - if(gl_init_) { - this->InitGL(false); - } else { - this->InitGL(true); - } - LOG_DEBUG("Scene: setting viewport"); - Resize(width,height); - LOG_DEBUG("Scene: updating fog settings"); - update_fog(); - glDrawBuffer(GL_FRONT); -#if OST_SHADER_SUPPORT_ENABLED - LOG_DEBUG("Scene: activating shader " << shader_name); - Shader::Instance().Activate(shader_name); -#endif - return true; -} - -void Scene::StopOffscreenMode() +void Scene::Export(const String& fname, bool transparent) { - if(main_offscreen_buffer_) { - delete main_offscreen_buffer_; - main_offscreen_buffer_=0; - this->ActivateGLContext(); - Scene::Instance().SetViewport(old_vp_[0],old_vp_[1]); - offscreen_flag_=false; - root_node_->ContextSwitch(); - glDrawBuffer(GL_BACK); - update_fog(); + if(!win_) { + LOG_ERROR("Scene: Image export requires registered GLWin"); } + + win_->Export(fname, transparent); } void Scene::Export(const String& fname, unsigned int width, unsigned int height, bool transparent) { - Export(fname,width,height,0,transparent); -} - -void Scene::Export(const String& fname, unsigned int width, - unsigned int height, int max_samples, bool transparent) -{ - int d_index=fname.rfind('.'); - if (d_index==-1) { - LOG_ERROR("Scene: no file extension specified"); - return; - } - String ext = fname.substr(d_index+1); - if(ext!="png") { - LOG_ERROR("Scene::Export: unknown file format (" << ext << ")"); - return; - } - - bool of_flag = (main_offscreen_buffer_==0); - - // only switch if offscreen mode is not active - if(of_flag) { - if(max_samples<0) { - int msamples=0; -#if OST_SHADER_SUPPORT_ENABLED - if(OST_GL_VERSION_2_0) { - glGetIntegerv(GL_SAMPLES, &msamples); - } -#endif - max_samples=msamples; - } - // proper GLContext is activated in StartOffscreenMode function - if(!StartOffscreenMode(width,height, max_samples)) { - return; - } - } - LOG_DEBUG("Scene: rendering into offscreen buffer"); - this->RenderGL(); - // make sure drawing operations are finished - glFlush(); - glFinish(); - - boost::shared_array<uchar> img_data(new uchar[width*height*4]); - - LOG_DEBUG("Scene: setting background transparency"); - if (transparent) { - glPixelTransferf(GL_ALPHA_BIAS, 0.0); - } else { - // shift alpha channel by one to make sure pixels are read out as opaque - glPixelTransferf(GL_ALPHA_BIAS, 1.0); + if(!win_) { + LOG_ERROR("Scene: Image export requires registered GLWin"); } - LOG_DEBUG("Scene: reading framebuffer pixels"); - glReadBuffer(GL_FRONT); - glReadPixels(0,0,width,height,GL_RGBA,GL_UNSIGNED_BYTE,img_data.get()); - glReadBuffer(GL_BACK); - - LOG_DEBUG("Scene: calling bitmap export"); - ExportBitmap(fname,ext,width,height,img_data.get()); - - // only switch back if it was not on to begin with - if(of_flag) { - StopOffscreenMode(); - } + win_->Export(fname, width, height, transparent); } -void Scene::Export(const String& fname, bool transparent) +void Scene::Export(const String& fname, unsigned int width, + unsigned int height, int max_samples, bool transparent) { - if(!win_ && !main_offscreen_buffer_) { - LOG_ERROR("Scene: Export without dimensions either requires an interactive session \nor an active offscreen mode (scene.StartOffscreenMode(W,H))"); - return; + if(!win_) { + LOG_ERROR("Scene: Image export requires registered GLWin"); } - this->ActivateGLContext(); - - int d_index=fname.rfind('.'); - if (d_index==-1) { - LOG_ERROR("Scene: no file extension specified"); - return; - } - String ext = fname.substr(d_index+1); - if(ext!="png") { - LOG_ERROR("Scene: unknown file format (" << ext << ")"); - return; - } - GLint vp[4]; - glGetIntegerv(GL_VIEWPORT,vp); - - if(main_offscreen_buffer_) { - this->RenderGL(); - glFlush(); - glFinish(); - } - - if (transparent) { - glPixelTransferf(GL_ALPHA_BIAS, 0.0); - } else { - // shift alpha channel by one to make sure pixels are read out as opaque - glPixelTransferf(GL_ALPHA_BIAS, 1.0); - } - boost::shared_array<uchar> img_data(new uchar[vp[2]*vp[3]*4]); - glReadPixels(0,0,vp[2],vp[3],GL_RGBA,GL_UNSIGNED_BYTE,img_data.get()); - glFinish(); - ExportBitmap(fname,ext,vp[2],vp[3],img_data.get()); - glPixelTransferf(GL_ALPHA_BIAS, 0.0); + win_->Export(fname, width, height, max_samples, transparent); } void Scene::ExportPov(const std::string& fname, const std::string& wdir) @@ -1989,11 +1840,6 @@ GfxNodeP Scene::GetRootNode() const return root_node_; } -bool Scene::InOffscreenMode() const -{ - return offscreen_flag_; -} - float Scene::ElapsedTime() const { #ifndef _MSC_VER @@ -2680,11 +2526,16 @@ void Scene::ActivateGLContext() const{ return; } - if(offscreen_flag_) { - main_offscreen_buffer_->MakeActive(); - } else { - win_->MakeActive(); - } + win_->MakeActive(); +} + +void Scene::SetAlphaBias(Real bias) { + this->ActivateGLContext(); + glPixelTransferf(GL_ALPHA_BIAS, bias); +} + +void Scene::ContextSwitch() { + root_node_->ContextSwitch(); } }} // ns diff --git a/modules/gfx/src/scene.hh b/modules/gfx/src/scene.hh index adacb4ca9e307ca1c96ee664d91da85f5b7e3b1f..c10bec64dd15d022017c1324c6c9bd3d76f59c12 100644 --- a/modules/gfx/src/scene.hh +++ b/modules/gfx/src/scene.hh @@ -49,7 +49,6 @@ namespace ost { namespace gfx { class InputEvent; -class OffscreenBuffer; typedef std::vector<SceneObserver*> SceneObserverList; @@ -290,11 +289,7 @@ class DLLEXPORT_OST_GFX Scene { void SetSelectionMode(uint m); uint GetSelectionMode() const; - /// \name Export - //@} - /// \brief export scene into a bitmap, rendering into offscreen of given size - /// if a main offscreen buffer is active (\sa StartOffscreenMode), then the - /// dimensions here are ignored + void Export(const String& fname, unsigned int w, unsigned int h, bool transparent=false); /// \brief export into bitmap, using multisample anti-aliasing @@ -459,8 +454,6 @@ class DLLEXPORT_OST_GFX Scene { void AttachObserver(SceneObserver* o); /// \brief observer interface (internal use) void DetachObserver(SceneObserver* o); - - bool InOffscreenMode() const; /// \brief switch into test mode (internal use) void SetTestMode(bool t); @@ -469,31 +462,6 @@ class DLLEXPORT_OST_GFX Scene { Viewport GetViewport() const; - /*! - This method has two different tasks. - - During interactive rendering, it facilitates export - into an offscreen buffer with Scene::Export(file,width,height) - by avoiding repeated initializations of the GL state, e.g. - during animation rendering. - - During batch mode, this is the only way to get meaningful - functionality with the gfx module - - Returns true upon success and false upon failure - - You can ask for multisampling to be enabled by giving the - max_samples a value larger than zero; in this case, the framebuffer - with at most this many samplebuffers will be used. The recommended - value here is 4; going to 8 or 16 may give you higher export times - with usually no marked increase in quality. - - */ - bool StartOffscreenMode(unsigned int w, unsigned int h, int max_samples); - bool StartOffscreenMode(unsigned int w, unsigned int h); - - /// \brief stops offline rendering in interactive mode - void StopOffscreenMode(); /// \brief show center of rotation of true void SetShowCenter(bool f); @@ -525,6 +493,11 @@ class DLLEXPORT_OST_GFX Scene { bool GetShowExportAspect() const {return show_export_aspect_;} bool HasMultisample() const {return ms_flag_;} + + void SetAlphaBias(Real bias); + + void ContextSwitch(); + protected: friend class GfxObj; friend class GfxNode; @@ -538,7 +511,6 @@ protected: void NodeAdded(const GfxNodeP& node); void RenderModeChanged(const String& name); - private: template <typename ACTION> @@ -593,9 +565,6 @@ private: bool do_autoslab_; // run autoslab on next scene update int autoslab_mode_; // 0: fast, 1:precise, 2: max - bool offscreen_flag_; // a simple indicator whether in offscreen mode or not - OffscreenBuffer* main_offscreen_buffer_; // not null if a main offscreen buffer is present - uint old_vp_[2]; // used by the offline rendering code std::string def_shading_mode_; uint selection_mode_; diff --git a/modules/gfx/src/vertex_array.cc b/modules/gfx/src/vertex_array.cc index 1ada7b7c6ddb3a4113a17edc180ae2aeaa4bbb33..89dbaa728405ab3b0adf50fb3a21a60ba7d195e3 100644 --- a/modules/gfx/src/vertex_array.cc +++ b/modules/gfx/src/vertex_array.cc @@ -316,9 +316,7 @@ void IndexedVertexArray::RenderGL() if(!initialized_) { LOG_DEBUG("initializing vertex array lists"); #if OST_SHADER_SUPPORT_ENABLED - if(!Scene::Instance().InOffscreenMode()) { - glGenBuffers(7,buffer_id_); - } + glGenBuffers(7,buffer_id_); #endif outline_mat_dlist_=glGenLists(1); initialized_=true; @@ -1025,7 +1023,6 @@ void IndexedVertexArray::copy(const IndexedVertexArray& va) bool IndexedVertexArray::prep_buff() { - if(Scene::Instance().InOffscreenMode()) return false; #if OST_SHADER_SUPPORT_ENABLED glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); @@ -1106,7 +1103,7 @@ void IndexedVertexArray::draw_ltq(bool use_buff) glStencilOp(GL_KEEP,GL_INVERT,GL_INVERT); } - if(use_buff && !Scene::Instance().InOffscreenMode()) { + if(use_buff) { #if OST_SHADER_SUPPORT_ENABLED #if 0 /* @@ -1198,7 +1195,7 @@ void IndexedVertexArray::draw_ltq(bool use_buff) void IndexedVertexArray::draw_p(bool use_buff) { - if(use_buff && !Scene::Instance().InOffscreenMode()) { + if(use_buff) { #if OST_SHADER_SUPPORT_ENABLED glBindBuffer(GL_ARRAY_BUFFER, buffer_id_[VA_VERTEX_BUFFER]); glVertexPointer(3, GL_FLOAT, sizeof(Entry), reinterpret_cast<void*>(sizeof(float)*9)); diff --git a/modules/gfx/tests/test_gfx_node.cc b/modules/gfx/tests/test_gfx_node.cc index 8a7059f8db459e16d765f634799626fc4d41b214..827e7ae176ef13e2cf8f12e3aad101b04af1e400 100644 --- a/modules/gfx/tests/test_gfx_node.cc +++ b/modules/gfx/tests/test_gfx_node.cc @@ -33,28 +33,6 @@ using boost::unit_test_framework::test_suite; using namespace ost; using namespace ost::gfx; -// small RAII class to setup environment for unit tests. even though we don't -// use any of the rendering functionality, we still need to initialize an -// offscreen buffer on mac to avoid segfaults. -struct GfxTestEnv { - GfxTestEnv() - { -#if defined(__APPLE__) - // we know OST_ROOT is set for unit tests - SetPrefixPath(getenv("OST_ROOT")); - Scene::Instance().StartOffscreenMode(100, 100); -#endif - } - - ~GfxTestEnv() - { -#if defined(__APPLE__) - Scene::Instance().StopOffscreenMode(); -#endif - } - -}; - struct Observer : public SceneObserver { Observer(): added_count(0),removed_count(0) {} @@ -134,7 +112,6 @@ BOOST_AUTO_TEST_CASE(gfx_node_remove_all) BOOST_AUTO_TEST_CASE(is_attached_to_scene) { - GfxTestEnv env; Scene::Instance().RemoveAll(); GfxNodeP n1(new GfxNode("1")); GfxNodeP n2(new GfxNode("2")); @@ -152,7 +129,6 @@ BOOST_AUTO_TEST_CASE(is_attached_to_scene) BOOST_AUTO_TEST_CASE(observe_added_removed) { - GfxTestEnv env; Observer o1; Scene::Instance().RemoveAll(); Scene::Instance().AttachObserver(&o1); diff --git a/modules/gui/src/gl_canvas.cc b/modules/gui/src/gl_canvas.cc index 449f7bb3ba2613aeae96824ff7ee8055d4a000c2..8bec7a90773e7e5bbd8851a661ab7d0da8b97057 100644 --- a/modules/gui/src/gl_canvas.cc +++ b/modules/gui/src/gl_canvas.cc @@ -29,6 +29,12 @@ #include <QResizeEvent> #include <QMouseEvent> +#include <QImage> +#include <QString> +#include <QOpenGLFramebufferObject> +#include <QOffscreenSurface> +#include <QOpenGLContext> +#include <QOpenGLFunctions> namespace ost { namespace gui { @@ -36,13 +42,36 @@ namespace ost { namespace gui { ost::gui::GLCanvas::GLCanvas(): QOpenGLWindow(), last_pos_(), show_beacon_(false), - bench_flag_(false) { + bench_flag_(false), + offscreen_flag_(false), + offscreen_context_(NULL), + offscreen_surface_(NULL), + offscreen_fbo_(NULL) { LOG_DEBUG("GLCanvas::registering with scene"); gfx::Scene::Instance().Register(this); } ost::gui::GLCanvas::~GLCanvas() { gfx::Scene::Instance().Unregister(this); + if(offscreen_fbo_ != NULL) { + // all other offscreen rendering objects are also != NULL + // cleanup done as in QT threadrenderer example, not sure whether + // offscreen context must be made current to delete offscreen buffer... + offscreen_context_->makeCurrent(offscreen_surface_); + delete offscreen_fbo_; + offscreen_context_->doneCurrent(); + delete offscreen_context_; + delete offscreen_surface_; + offscreen_flag_ = false; + } +} + +void GLCanvas::MakeActive() { + if(offscreen_flag_) { + offscreen_context_->makeCurrent(offscreen_surface_); + } else { + this->makeCurrent(); + } } void GLCanvas::StatusMessage(const String& m) { @@ -202,6 +231,110 @@ void GLCanvas::SetTestMode(bool f) { gfx::Scene::Instance().SetTestMode(f); } +void GLCanvas::Export(const String& fname, unsigned int width, + unsigned int height, bool transparent) { + this->Export(fname, width, height, 0, transparent); +} + +void GLCanvas::Export(const String& fname, unsigned int width, + unsigned int height, int max_samples, bool transparent) { + + // setup of context, surface, fbo etc are implemented as in the QT + // threadrenderer example + + gfx::Viewport old_vp = gfx::Scene::Instance().GetViewport(); + + if(old_vp.width == static_cast<int>(width) && + old_vp.height == static_cast<int>(height) && max_samples <= 0) { + // just grab the framebuffer, no need for fancy offscreen rendering... + this->Export(fname, transparent); + return; + } + + offscreen_flag_ = true; + + if(offscreen_surface_ == NULL) { + offscreen_surface_ = new QOffscreenSurface(); + QSurfaceFormat f = this->context()->format(); + if(max_samples > 0) { + f.setSamples(max_samples); + } + offscreen_surface_->setFormat(f); + offscreen_surface_->create(); + } + + if(offscreen_context_ == NULL) { + QOpenGLContext *current = this->context(); + // Some GL implementations require that the currently bound context is + // made non-current before we set up sharing, so we doneCurrent here + // and makeCurrent down below while setting up our own context. + current->doneCurrent(); + offscreen_context_ = new QOpenGLContext(); + QSurfaceFormat f = this->context()->format(); + if(max_samples > 0) { + f.setSamples(max_samples); + } + offscreen_context_->setFormat(f); + offscreen_context_->setShareContext(current); + offscreen_context_->create(); + offscreen_context_->makeCurrent(offscreen_surface_); + gfx::Scene::Instance().ContextSwitch(); + gfx::Scene::Instance().InitGL(false); + } else { + offscreen_context_->makeCurrent(offscreen_surface_); + gfx::Scene::Instance().ContextSwitch(); + // the following InitGL sets potentially changed glClearcolor etc + // could be made more efficient... + gfx::Scene::Instance().InitGL(false); + } + + if(offscreen_fbo_ == NULL || + offscreen_fbo_->width() != static_cast<int>(width) || + offscreen_fbo_->height() != static_cast<int>(height)) { + if(offscreen_fbo_ != NULL) { + delete offscreen_fbo_; + } + QOpenGLFramebufferObjectFormat fbo_format; + // the following flag is required for OpenGL depth testing + fbo_format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); + offscreen_fbo_ = new QOpenGLFramebufferObject(width, height, fbo_format); + } + + offscreen_fbo_->bind(); + gfx::Scene::Instance().Resize(width, height); + this->paintGL(); + + if(!transparent) { + gfx::Scene::Instance().SetAlphaBias(1.0); + } + + offscreen_context_->functions()->glFlush(); + QImage image = offscreen_fbo_->toImage(); + offscreen_fbo_->release(); + + if(!transparent) { + gfx::Scene::Instance().SetAlphaBias(0.0); + } + + image.save(QString(fname.c_str())); + offscreen_flag_ = false; + this->MakeActive(); + gfx::Scene::Instance().Resize(old_vp.width, old_vp.height); + gfx::Scene::Instance().ContextSwitch(); +} + +void GLCanvas::Export(const String& fname, bool transparent) { + + if(!transparent) { + gfx::Scene::Instance().SetAlphaBias(1.0); + } + QImage image = this->grabFramebuffer(); + if(!transparent) { + gfx::Scene::Instance().SetAlphaBias(0.0); + } + image.save(QString(fname.c_str())); +} + bool GLCanvas::IsToolEvent(QInputEvent* event) const { return event->modifiers() & Qt::ControlModifier; } diff --git a/modules/gui/src/gl_canvas.hh b/modules/gui/src/gl_canvas.hh index 7f7c89e0808d1b224e0e5061bd80bcc7de0185a3..36d74b2a77bcb582e22dbf58c7a27b5ca241a254 100644 --- a/modules/gui/src/gl_canvas.hh +++ b/modules/gui/src/gl_canvas.hh @@ -29,6 +29,9 @@ // forward declaration class QResizeEvent; +class QOpenGLFramebufferObject; +class QOpenGLContext; +class QOffscreenSurface; namespace ost { namespace gui { @@ -40,7 +43,7 @@ public: virtual ~GLCanvas(); // gfx::GLWinBase interface - virtual void MakeActive() { this->makeCurrent(); } + virtual void MakeActive(); virtual void DoRefresh() {this->update(); } virtual void StatusMessage(const String& m); virtual bool HasStereo() const {return format().stereo();}; @@ -56,6 +59,15 @@ public: void SetTestMode(bool f); + // Grab images from framebuffer and dump to disk + virtual void Export(const String& fname, unsigned int width, + unsigned int height, bool transparent); + + virtual void Export(const String& fname, unsigned int width, + unsigned int height, int max_samples, bool transparent); + + virtual void Export(const String& fname, bool transparent); + signals: void CustomContextMenuRequested(const QPoint& point); @@ -88,6 +100,12 @@ private: QPoint last_pos_; bool show_beacon_; bool bench_flag_; + + // for image export + bool offscreen_flag_; + QOpenGLContext* offscreen_context_; + QOffscreenSurface* offscreen_surface_; + QOpenGLFramebufferObject* offscreen_fbo_; }; }} // ns