Mercurial > octave
diff libgui/graphics/GLCanvas.cc @ 31762:d94ceed56929
GLCanvas: avoid multiple inheritance from both QWidget and QObject
To avoid having GLCanvas inherit from both QWidget and QObject, create
a separate class, GLWidget, derived from QOpenGLWidget and use that as
a member of GLCanvas instead of a base class.
* Canvas.h (class Canvas): Derive from QWidget instead of QObject.
(Canvas::Canvas): New argument for parent widget. Pass parent to
QWidget base class constructor.
* GLCanvas.h, GLCanvas.cc (class GLCanvas): Split QOpenGLWidget parts
into separate GLWidget class. GLCanvas now processes things related
to the interpreter and forwards to GLWidget for rendering. Use
unwind_action objects to ensure OpenGL context is restored.
(GLCanvas::m_glwidget): New data member for GLWidget.
* libbgui/graphics/module.mk (OCTAVE_GUI_GRAPHICS_MOC): Add
moc-GLCanvas.cc to the list.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Fri, 20 Jan 2023 08:49:19 -0500 |
parents | 345a3f5890e7 |
children | 1d1eff97670e |
line wrap: on
line diff
--- a/libgui/graphics/GLCanvas.cc Fri Jan 20 15:33:05 2023 +0100 +++ b/libgui/graphics/GLCanvas.cc Fri Jan 20 08:49:19 2023 -0500 @@ -37,52 +37,54 @@ OCTAVE_BEGIN_NAMESPACE(octave) - GLCanvas::GLCanvas (octave::interpreter& interp, - const graphics_handle& gh, QWidget *xparent) - : QOpenGLWidget (xparent), Canvas (interp, gh), m_glfcns (), - m_renderer (m_glfcns) + GLWidget::GLWidget (Canvas &parent_canvas) + : QOpenGLWidget (&parent_canvas), m_parent_canvas (parent_canvas), + m_glfcns (), m_renderer (m_glfcns) { setFocusPolicy (Qt::ClickFocus); setFocus (); } - GLCanvas::~GLCanvas (void) - { } + GLWidget::~GLWidget (void) { } void - GLCanvas::initializeGL (void) + GLWidget::initializeGL (void) { + // The qopengl_functions object (part of Octave, not Qt) is just + // wrapper around QOpenGLFunctions_1_1. Does initialization really + // need to be deferred until initializeGL is called? + m_glfcns.init (); + + // All other resources we need are currently (supposed to be) + // managed by the QOpenGLWidget object so there is else nothing to + // do here. If we used custom shader programs, then we would need + // to initialize them here. } void - GLCanvas::draw (const graphics_handle& gh) + GLWidget::draw (graphics_object go) { - gh_manager& gh_mgr = m_interpreter.get_gh_manager (); - - octave::autolock guard (gh_mgr.graphics_lock ()); - - graphics_object go = gh_mgr.get_object (gh); - if (go) { + begin_rendering (); + + unwind_action reset_current ([=] () { end_rendering (); }); + graphics_object fig = go.get_ancestor ("figure"); double dpr = fig.get ("__device_pixel_ratio__").double_value (); m_renderer.set_viewport (dpr * width (), dpr * height ()); m_renderer.set_device_pixel_ratio (dpr); + m_renderer.draw (go); } } uint8NDArray - GLCanvas::do_getPixels (const graphics_handle& gh) + GLWidget::do_getPixels (graphics_object go) { uint8NDArray retval; - gh_manager& gh_mgr = m_interpreter.get_gh_manager (); - - graphics_object go = gh_mgr.get_object (gh); - if (go && go.isa ("figure")) { Matrix pos = go.get ("position").matrix_value (); @@ -90,9 +92,9 @@ pos(2) *= dpr; pos(3) *= dpr; - // Make sure we have a valid current context - if (! begin_rendering ()) - return retval; + begin_rendering (); + + unwind_action reset_current ([=] () { end_rendering (); }); // When the figure is not visible or its size is frozen for printing, // we use a framebuffer object to make sure we are rendering on a @@ -106,104 +108,89 @@ fbo.bind (); + unwind_action release_fbo ([&] () { fbo.release (); }); + m_renderer.set_viewport (pos(2), pos(3)); m_renderer.set_device_pixel_ratio (dpr); m_renderer.draw (go); + retval = m_renderer.get_pixels (pos(2), pos(3)); - - fbo.release (); } else { m_renderer.set_viewport (pos(2), pos(3)); m_renderer.set_device_pixel_ratio (dpr); m_renderer.draw (go); + retval = m_renderer.get_pixels (pos(2), pos(3)); } - - end_rendering (); } return retval; } void - GLCanvas::do_print (const QString& file_cmd, const QString& term, - const graphics_handle& handle) + GLWidget::do_print (const QString& file_cmd, const QString& term, + graphics_object go) { - gh_manager& gh_mgr = m_interpreter.get_gh_manager (); - - octave::autolock guard (gh_mgr.graphics_lock ()); - - graphics_object go = gh_mgr.get_object (handle); - if (go.valid_object ()) { + begin_rendering (); + + unwind_action reset_current ([=] () { end_rendering (); }); + graphics_object fig (go.get_ancestor ("figure")); - // Make sure we have a valid current context - if (! begin_rendering ()) - error ("print: no valid OpenGL offscreen context"); - - try + if (fig.get ("visible").string_value () == "on") + octave::gl2ps_print (m_glfcns, fig, file_cmd.toStdString (), + term.toStdString ()); + else { - if (fig.get ("visible").string_value () == "on") - octave::gl2ps_print (m_glfcns, fig, file_cmd.toStdString (), - term.toStdString ()); - else - { - // When the figure is not visible, we use a framebuffer object - // to make sure we are rendering on a suitably large frame. - Matrix pos = fig.get ("position").matrix_value (); - double dpr = fig.get ("__device_pixel_ratio__").double_value (); - pos(2) *= dpr; - pos(3) *= dpr; + // When the figure is not visible, we use a framebuffer object + // to make sure we are rendering on a suitably large frame. + Matrix pos = fig.get ("position").matrix_value (); + double dpr = fig.get ("__device_pixel_ratio__").double_value (); + pos(2) *= dpr; + pos(3) *= dpr; - QOpenGLFramebufferObject - fbo (pos(2), pos(3), - QOpenGLFramebufferObject::Attachment::Depth); - - fbo.bind (); + QOpenGLFramebufferObject + fbo (pos(2), pos(3), + QOpenGLFramebufferObject::Attachment::Depth); - octave::gl2ps_print (m_glfcns, fig, file_cmd.toStdString (), - term.toStdString ()); + fbo.bind (); - fbo.release (); - } + unwind_action release_fbo ([&] () { fbo.release (); }); + + octave::gl2ps_print (m_glfcns, fig, file_cmd.toStdString (), + term.toStdString ()); } - catch (octave::execution_exception& ee) - { - emit interpreter_event - ([=] (void) - { - // INTERPRETER THREAD - throw ee; - }); - } - - end_rendering (); } } graphics_object - GLCanvas::selectFromAxes (const graphics_object& ax, const QPoint& pt) + GLWidget::selectFromAxes (const graphics_object& ax, const QPoint& pt) { - makeCurrent (); - if (ax) { + begin_rendering (); + + unwind_action reset_current ([=] () { end_rendering (); }); + octave::opengl_selector s (m_glfcns); s.set_viewport (width (), height ()); - return s.select (ax, pt.x (), height () - pt.y (), - octave::select_ignore_hittest); + + graphics_object go = s.select (ax, pt.x (), height () - pt.y (), + octave::select_ignore_hittest); + + doneCurrent (); } return graphics_object (); } void - GLCanvas::drawZoomBox (const QPoint& p1, const QPoint& p2) + GLWidget::drawZoomBox (const QPoint& p1, const QPoint& p2) { Matrix overlaycolor (3, 1); overlaycolor(0) = 0.45; @@ -221,67 +208,72 @@ } void - GLCanvas::paintGL (void) + GLWidget::paintGL (void) { - canvasPaintEvent (); + m_parent_canvas.canvasPaintEvent (); } void - GLCanvas::mouseDoubleClickEvent (QMouseEvent *xevent) + GLWidget::mouseDoubleClickEvent (QMouseEvent *xevent) { - canvasMouseDoubleClickEvent (xevent); + m_parent_canvas.canvasMouseDoubleClickEvent (xevent); } void - GLCanvas::mouseMoveEvent (QMouseEvent *xevent) + GLWidget::mouseMoveEvent (QMouseEvent *xevent) { - canvasMouseMoveEvent (xevent); + m_parent_canvas.canvasMouseMoveEvent (xevent); } void - GLCanvas::mousePressEvent (QMouseEvent *xevent) + GLWidget::mousePressEvent (QMouseEvent *xevent) { - canvasMousePressEvent (xevent); + m_parent_canvas.canvasMousePressEvent (xevent); } void - GLCanvas::mouseReleaseEvent (QMouseEvent *xevent) + GLWidget::mouseReleaseEvent (QMouseEvent *xevent) { - canvasMouseReleaseEvent (xevent); + m_parent_canvas.canvasMouseReleaseEvent (xevent); } void - GLCanvas::wheelEvent (QWheelEvent *xevent) + GLWidget::wheelEvent (QWheelEvent *xevent) { - canvasWheelEvent (xevent); + m_parent_canvas.canvasWheelEvent (xevent); } void - GLCanvas::keyPressEvent (QKeyEvent *xevent) + GLWidget::keyPressEvent (QKeyEvent *xevent) { - if (! canvasKeyPressEvent (xevent)) + if (! m_parent_canvas.canvasKeyPressEvent (xevent)) QOpenGLWidget::keyPressEvent (xevent); } void - GLCanvas::keyReleaseEvent (QKeyEvent *xevent) + GLWidget::keyReleaseEvent (QKeyEvent *xevent) { - if (! canvasKeyReleaseEvent (xevent)) + if (! m_parent_canvas.canvasKeyReleaseEvent (xevent)) QOpenGLWidget::keyReleaseEvent (xevent); } bool - GLCanvas::begin_rendering (void) + GLWidget::begin_rendering (void) { bool retval = true; if (! isValid ()) { + // FIXME: Is this really the right way to manager offscreen + // rendering for printing? + static bool os_ctx_ok = true; + if (os_ctx_ok && ! m_os_context.isValid ()) { // Try to initialize offscreen context m_os_surface.create (); + if (! m_os_context.create ()) { os_ctx_ok = false; @@ -298,9 +290,92 @@ } void - GLCanvas::end_rendering (void) + GLWidget::end_rendering (void) { doneCurrent (); } + GLCanvas::GLCanvas (octave::interpreter& interp, + const graphics_handle& gh, QWidget *parent) + : Canvas (interp, gh, parent), m_glwidget (new GLWidget (*this)) + { } + + GLCanvas::~GLCanvas (void) + { + delete m_glwidget; + } + + void + GLCanvas::draw (const graphics_handle& gh) + { + gh_manager& gh_mgr = m_interpreter.get_gh_manager (); + + octave::autolock guard (gh_mgr.graphics_lock ()); + + graphics_object go = gh_mgr.get_object (gh); + + m_glwidget->draw (go); + } + + uint8NDArray + GLCanvas::do_getPixels (const graphics_handle& gh) + { + uint8NDArray retval; + + gh_manager& gh_mgr = m_interpreter.get_gh_manager (); + + graphics_object go = gh_mgr.get_object (gh); + + return m_glwidget->do_getPixels (go); + } + + void + GLCanvas::do_print (const QString& file_cmd, const QString& term, + const graphics_handle& handle) + { + gh_manager& gh_mgr = m_interpreter.get_gh_manager (); + + octave::autolock guard (gh_mgr.graphics_lock ()); + + graphics_object go = gh_mgr.get_object (handle); + + try + { + m_glwidget->do_print (file_cmd, term, go); + } + catch (octave::execution_exception& ee) + { + emit interpreter_event + ([=] (void) + { + // INTERPRETER THREAD + throw ee; + }); + } + } + + graphics_object + GLCanvas::selectFromAxes (const graphics_object& ax, const QPoint& pt) + { + return m_glwidget->selectFromAxes (ax, pt); + } + + void + GLCanvas::drawZoomBox (const QPoint& p1, const QPoint& p2) + { + m_glwidget->drawZoomBox (p1, p2); + } + + bool + GLCanvas::begin_rendering (void) + { + return m_glwidget->begin_rendering (); + } + + void + GLCanvas::end_rendering (void) + { + m_glwidget->end_rendering (); + } + OCTAVE_END_NAMESPACE(octave)