# HG changeset patch
# User Pantxo Diribarne <pantxo.diribarne@gmail.com>
# Date 1518993508 -3600
#      Sun Feb 18 23:38:28 2018 +0100
# Node ID 4e371ed4828474aacdad700e69808363469b538d
# Parent  30e1d0bf7ade11f308bdc915e3b2d509166c8dc7
Allow getframe and print to work without osmesa

* __opengl_print__.m: no need to check __gl_window__ status anymore
* getframe.m: use __get_frame__ on qt invible figures
* Backenc.cc (Backend::get_pixels): don't restrict to visible figures
* Canvas.h/cc (Canvas::do_print): new pure virtual function
  (Canvas::print): call do_print
* GLCanvas.h/cc (GLCanvas::begin_rendering): new methods to make sure a valid
  opengl context is made current before rendering.
  (GLCanvas::end_rendering): call doneCurrent
  (GLCanvas::getPixels): make use of begin/end_rendering. If the figure is not
  visible or its size os frozen, draw on a framebuffer object of suitable size
  (GLCanvas::do_print): move code for opengl printing here. Make use of
  begin/end_rendering

diff -r 30e1d0bf7ade -r 4e371ed48284 libgui/graphics/Backend.cc
--- a/libgui/graphics/Backend.cc	Thu Feb 08 04:06:03 2018 -0500
+++ b/libgui/graphics/Backend.cc	Sun Feb 18 23:38:28 2018 +0100
@@ -197,7 +197,7 @@
   {
     uint8NDArray retval;
 
-    if (go.get_properties ().is_visible () && go.isa ("figure"))
+    if (go.isa ("figure"))
       {
         ObjectProxy *proxy = toolkitObjectProxy (go);
 
diff -r 30e1d0bf7ade -r 4e371ed48284 libgui/graphics/Canvas.cc
--- a/libgui/graphics/Canvas.cc	Thu Feb 08 04:06:03 2018 -0500
+++ b/libgui/graphics/Canvas.cc	Sun Feb 18 23:38:28 2018 +0100
@@ -41,7 +41,6 @@
 
 #include "annotation-dialog.h"
 
-#include "gl2ps-print.h"
 #include "oct-opengl.h"
 #include "octave-qt-link.h"
 
@@ -101,27 +100,6 @@
       }
   }
 
-  void
-  Canvas::print (const QString& file_cmd, const QString& term)
-  {
-    gh_manager::auto_lock lock;
-    graphics_object obj = gh_manager::get_object (m_handle);
-
-    if (obj.valid_object ())
-      {
-        graphics_object figObj (obj.get_ancestor ("figure"));
-        try
-          {
-            octave::gl2ps_print (figObj, file_cmd.toStdString (),
-                                 term.toStdString ());
-          }
-        catch (octave::execution_exception e)
-          {
-            octave_link::post_exception (std::current_exception ());
-          }
-      }
-  }
-
   /*
      Two updateCurrentPoint() routines are required:
      1) Used for QMouseEvents where cursor position data is in callback from Qt.
diff -r 30e1d0bf7ade -r 4e371ed48284 libgui/graphics/Canvas.h
--- a/libgui/graphics/Canvas.h	Thu Feb 08 04:06:03 2018 -0500
+++ b/libgui/graphics/Canvas.h	Sun Feb 18 23:38:28 2018 +0100
@@ -54,7 +54,10 @@
     void redraw (bool sync = false);
     void blockRedraw (bool block = true);
 
-    void print (const QString& file_cmd, const QString& term);
+    void print (const QString& file_cmd, const QString& term)
+    {
+      do_print (file_cmd, term, m_handle);
+    }
 
     void addEventMask (int m) { m_eventMask |= m; }
     void clearEventMask (int m) { m_eventMask &= (~m); }
@@ -80,6 +83,8 @@
     virtual graphics_object selectFromAxes (const graphics_object& ax,
                                             const QPoint& pt) = 0;
     virtual uint8NDArray do_getPixels (const graphics_handle& handle) = 0;
+    virtual void do_print (const QString& file_cmd, const QString& term,
+                           const graphics_handle& handle) = 0;
 
   protected:
     Canvas (const graphics_handle& handle)
diff -r 30e1d0bf7ade -r 4e371ed48284 libgui/graphics/GLCanvas.cc
--- a/libgui/graphics/GLCanvas.cc	Thu Feb 08 04:06:03 2018 -0500
+++ b/libgui/graphics/GLCanvas.cc	Sun Feb 18 23:38:28 2018 +0100
@@ -26,9 +26,12 @@
 
 #include "gl-render.h"
 #include "graphics.h"
+#include "octave-link.h"
 
 #include "GLCanvas.h"
 #include "gl-select.h"
+#include "gl2ps-print.h"
+#include <QOpenGLFramebufferObject>
 
 namespace QtHandles
 {
@@ -76,18 +79,73 @@
   {
     uint8NDArray retval;
     graphics_object go = gh_manager::get_object (gh);
-
-    if (go)
+    
+    if (go && go.isa ("figure"))
       {
-        octave::opengl_renderer r;
+        Matrix pos = go.get ("position").matrix_value ();
 
-        r.set_viewport (width (), height ());
-        r.draw (go);
-        retval = r.get_pixels (width (), height ());
+        // Make sure we have a valid current context
+        if (! begin_rendering ())
+          return retval;
+
+        // 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
+        // suitably large frame.
+        if (go.get ("visible").string_value () == "off"
+            || go.get ("__printing__").string_value () == "on")
+          {
+            QOpenGLFramebufferObject
+              fbo (pos(2), pos(3),QOpenGLFramebufferObject::Attachment::Depth);
+            
+            fbo.bind ();
+            
+            octave::opengl_renderer r;
+            r.set_viewport (pos(2), pos(3));
+            r.draw (go);
+            retval = r.get_pixels (pos(2), pos(3));
+            
+            fbo.release ();
+          }
+        else
+          {
+            octave::opengl_renderer r;
+            r.set_viewport (pos(2), pos(3));
+            r.draw (go);
+            retval = r.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)
+  {
+    gh_manager::auto_lock lock;
+    graphics_object obj = gh_manager::get_object (handle);
+
+    if (obj.valid_object ())
+      {
+        graphics_object figObj (obj.get_ancestor ("figure"));
+        try
+          {
+            // Make sure we have a valid current context
+            if (! begin_rendering ())
+              error ("print: no valid opengl offscreen context");
+            
+            octave::gl2ps_print (figObj, file_cmd.toStdString (),
+                                 term.toStdString ());
+          }
+        catch (octave::execution_exception e)
+          {
+            octave_link::post_exception (std::current_exception ());
+            end_rendering ();
+          }
+      }
+  }
 
   void
   GLCanvas::toggleAxes (const graphics_handle& gh)
@@ -219,4 +277,36 @@
       OCTAVE_QT_OPENGL_WIDGET::keyReleaseEvent (xevent);
   }
 
+  bool
+  GLCanvas::begin_rendering (void)
+  {
+    bool retval = true;
+    static bool ctx_ok = true;
+
+    if (! isValid ())
+      {
+        if (ctx_ok && ! m_os_context.isValid ())
+          {
+            // Try to initialize offscreen context
+            m_os_surface.create ();
+            if (! m_os_context.create ())
+              {
+                ctx_ok = false;
+                return false;
+              }
+          }
+        
+        retval = m_os_context.makeCurrent (&m_os_surface);
+      }
+    else
+      makeCurrent ();
+    
+    return retval;
+  }
+  
+  void
+  GLCanvas::end_rendering (void)
+  {        
+    doneCurrent ();
+  }
 }
diff -r 30e1d0bf7ade -r 4e371ed48284 libgui/graphics/GLCanvas.h
--- a/libgui/graphics/GLCanvas.h	Thu Feb 08 04:06:03 2018 -0500
+++ b/libgui/graphics/GLCanvas.h	Sun Feb 18 23:38:28 2018 +0100
@@ -33,6 +33,9 @@
 #  error "configuration error: must have <QOpenGLWidget> or <QGLWidget>."
 #endif
 
+#include <QOffscreenSurface>
+#include <QOpenGLContext>
+
 #include "Canvas.h"
 
 namespace QtHandles
@@ -45,6 +48,8 @@
 
     void draw (const graphics_handle& handle);
     uint8NDArray  do_getPixels (const graphics_handle& handle);
+    void do_print (const QString& file_cmd, const QString& term,
+                   const graphics_handle& handle);
     void toggleAxes (const graphics_handle& handle);
     void toggleGrid (const graphics_handle& handle);
     void autoAxes (const graphics_handle& handle);
@@ -64,6 +69,14 @@
     void wheelEvent (QWheelEvent *event);
     void keyPressEvent (QKeyEvent *event);
     void keyReleaseEvent (QKeyEvent *event);
+    
+  private:
+    
+    bool begin_rendering (void);
+    void end_rendering (void);
+    
+    QOpenGLContext m_os_context;    
+    QOffscreenSurface m_os_surface;
   };
 
 }
diff -r 30e1d0bf7ade -r 4e371ed48284 scripts/image/getframe.m
--- a/scripts/image/getframe.m	Thu Feb 08 04:06:03 2018 -0500
+++ b/scripts/image/getframe.m	Sun Feb 18 23:38:28 2018 +0100
@@ -95,7 +95,8 @@
     pos = rect;
   endif
 
-  if (strcmp (get (hf, "visible"), "on"))
+  if (strcmp (get (hf, "visible"), "on")
+      || strcmp (get (hf, "__graphics_toolkit__"), "qt"))
     cdata = __get_frame__ (hf);
   else
     ## Use OpenGL offscreen rendering with OSMesa for non-visible figures
diff -r 30e1d0bf7ade -r 4e371ed48284 scripts/plot/util/private/__opengl_print__.m
--- a/scripts/plot/util/private/__opengl_print__.m	Thu Feb 08 04:06:03 2018 -0500
+++ b/scripts/plot/util/private/__opengl_print__.m	Sun Feb 18 23:38:28 2018 +0100
@@ -151,8 +151,7 @@
     endif
 
     if (strcmp (get (opts.figure, "visible"), "on")
-        || (strcmp (get (opts.figure, "__graphics_toolkit__"), "qt")
-            && strcmp (get (opts.figure, "__gl_window__"), "on")))
+        || strcmp (get (opts.figure, "__graphics_toolkit__"), "qt"))
       ## Use toolkits "print_figure" method
       drawnow (gl2ps_device{n}, ['|' pipeline{n}]);
     else
