FLTK logo

[master] 89f9671 - Add cross-platform support for adding widgets to an OpenGL3-based Fl_Gl_Window.

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 All Forums  |  Back to fltk.commit  ]
 
Previous Message ]Next Message ]

[master] 89f9671 - Add cross-platform support for adding widgets to an OpenGL3-based Fl_Gl_Window. "ManoloFLTK" Sep 25, 2022  
 
commit 89f9671b406d1d2ac0377ef90d44ebfa7a92150e
Author:     ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>
AuthorDate: Sun Sep 25 16:39:40 2022 +0200
Commit:     ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>
CommitDate: Sun Sep 25 16:39:40 2022 +0200

    Add cross-platform support for adding widgets to an OpenGL3-based Fl_Gl_Window.
    
    Under non-macOS platforms, the key is to call glUseProgram(0); after having used OpenGL 3
    which allows to then use OpenGL 1 and draw FLTK widgets over the OpenGL3 scene.
    
    Under macOS, this is impossible because macOS GL3 contexts are not compatible
    with GL1. The solution implemented here is to create an additional Fl_Gl_Window
    placed above and sized as the GL3-based window, to give it a non opaque,
    GL1-based context, and to put the FLTK widgets in that additional window.

 FL/mac.H                                        |  4 +++
 documentation/src/opengl.dox                    | 30 ++++++++++++++++++
 examples/OpenGL3test.cxx                        | 32 ++++++++++++++++++-
 src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx | 41 +++++++++++++++++++++++++
 src/glut_compatibility.cxx                      | 24 +++++++++++++++
 5 files changed, 130 insertions(+), 1 deletion(-)

diff --git FL/mac.H FL/mac.H
index 9af98a2..d289774 100644
--- FL/mac.H
+++ FL/mac.H
@@ -153,6 +153,10 @@ extern CGContextRef fl_mac_gc();
 extern FLWindow *fl_mac_xid(const Fl_Window *win);
 /** Returns the Fl_Window corresponding to the given macOS-specific window reference */
 extern Fl_Window *fl_mac_find(FLWindow *);
+class Fl_Gl_Window;
+/** Call this to make possible the addition of FLTK widgets to a GL3-using Fl_Gl_Window.
+ \see \ref opengl3 */
+extern Fl_Gl_Window *fl_mac_prepare_add_widgets_to_GL3_win(Fl_Gl_Window *);
 
 /** The version number of the running Mac OS X (e.g., 100604 for 10.6.4, 101300 for 10.13).
  FLTK initializes this global variable before main() begins running. If
diff --git documentation/src/opengl.dox documentation/src/opengl.dox
index d1a36be..68f5e71 100644
--- documentation/src/opengl.dox
+++ documentation/src/opengl.dox
@@ -605,6 +605,36 @@ to be created among your Fl_Gl_Window-derived classes:
 \endcode
 after the first glutCreateWindow() call.
 
+\li If the GL3-using window is intended to contain FLTK widgets laid over
+the GL3 scene (see \ref opengl_with_fltk_widgets), extra steps are necessary to make this possible in a
+cross-platform way.
+<ol><li>Create a function called, say, add_widgets(), charged of the creation
+of all FLTK widgets expected to be drawn above the GL3 scene, as follows
+\code
+void add_widgets(Fl_Gl_Window *g) {
+#ifdef __APPLE__
+  g = fl_mac_prepare_add_widgets_to_GL3_win(g);
+#endif
+  g->begin();
+  // â?¦ Create here FLTK widgets expected to be drawn above the GL3 scene â?¦
+  g->end();
+}
+\endcode
+and call this function with the GL3-using window as argument to populate it
+with FLTK widgets.
+<li>
+Put
+\code
+#ifndef __APPLE__
+    glUseProgram(0); // Switch from GL3-style to GL1-style drawing
+    Fl_Gl_Window::draw(); // Draw FLTK child widgets.
+#endif
+\endcode
+at the end of your GL3 window's draw() function. This is not necessary if
+the GL3 window is built by GLUT, because Fl_Glut_Window::draw() does it.
+
+</ol>
+
 If GLEW is installed on the Mac OS development platform, it is possible
 to use the same code for all platforms, with one exception: put
 \code
diff --git examples/OpenGL3test.cxx examples/OpenGL3test.cxx
index 9acbaf3..26ee1b8 100644
--- examples/OpenGL3test.cxx
+++ examples/OpenGL3test.cxx
@@ -138,6 +138,13 @@ public:
     GLfloat p[]={0,0};
     glUniform2fv(positionUniform, 1, (const GLfloat *)&p);
     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+#ifndef __APPLE__
+    // suggested by https://stackoverflow.com/questions/22293870/mixing-fixed-function-pipeline-and-programmable-pipeline-in-opengl
+    // Switch from GL3-style to GL1-style drawing;
+    // good under Windows, X11 and Wayland; impossible under macOS.
+    glUseProgram(0);
+    Fl_Gl_Window::draw(); // Draw FLTK child widgets.
+#endif
   }
   virtual int handle(int event) {
     static int first = 1;
@@ -161,6 +168,9 @@ public:
       redraw();
     }
 
+    int retval = Fl_Gl_Window::handle(event);
+    if (retval) return retval;
+    
     if (event == FL_PUSH && gl_version_major >= 3) {
       static float factor = 1.1;
       GLfloat data[4];
@@ -175,7 +185,7 @@ public:
       add_output("push  Fl_Gl_Window::pixels_per_unit()=%.1f\n", pixels_per_unit());
       return 1;
     }
-    return Fl_Gl_Window::handle(event);
+    return retval;
   }
   void reset(void) { shaderProgram = 0; }
 };
@@ -218,6 +228,25 @@ void add_output(const char *format, ...)
 }
 
 
+void button_cb(Fl_Widget *, void *) {
+  add_output("run button callback\n");
+}
+
+void add_widgets(Fl_Gl_Window *g) {
+#ifdef __APPLE__
+  g = fl_mac_prepare_add_widgets_to_GL3_win(g);
+#endif
+  Fl::set_color(FL_FREE_COLOR, 255, 0, 0, 140); // partially transparent red
+  g->begin();
+  // Create here widgets to go above the GL3 scene
+  Fl_Button* b = new Fl_Button( 0, 170, 60, 30, "button");
+  b->color(FL_FREE_COLOR);
+  b->box(FL_BORDER_BOX );
+  b->callback(button_cb, NULL);
+  g->end();
+}
+
+
 int main(int argc, char **argv)
 {
   Fl::use_high_res_GL(1);
@@ -225,6 +254,7 @@ int main(int argc, char **argv)
   SimpleGL3Window *win = new SimpleGL3Window(0, 0, 300, 300);
   win->end();
   output_win(win);
+  add_widgets(win);
   topwin->end();
   topwin->resizable(win);
   topwin->label("Click GL panel to reshape");
diff --git src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx
index 4d47c30..b14ac6a 100644
--- src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx
+++ src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx
@@ -304,6 +304,47 @@ FL_EXPORT NSOpenGLContext *fl_mac_glcontext(GLContext rc) {
 }
 
 
+/* macOS offers only core contexts when using GL3. This forbids to add
+ FLTK widgets to a GL3-using Fl_Gl_Window because these widgets are drawn
+ with the GL1-based Fl_OpenGL_Graphics_Driver. The solution implemented here
+ is to create, with public function fl_mac_prepare_add_widgets_to_GL3_win(),
+ an additional Fl_Gl_Window placed above and sized as the GL3-based window,
+ to give it a non opaque, GL1-based context, and to put the FLTK widgets
+ in that additional window.
+ */
+
+class transparentGlWindow : public Fl_Gl_Window { // utility class
+  bool need_remove_opacity;
+public:
+  transparentGlWindow(int x, int y, int w, int h) : Fl_Gl_Window(x, y, w, h) {
+    mode(FL_RGB8 | FL_ALPHA | FL_SINGLE);
+    need_remove_opacity = true;
+  }
+  void show() {
+    Fl_Gl_Window::show();
+    if (need_remove_opacity) {
+      need_remove_opacity = false;
+      Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(this);
+      d->remove_gl_context_opacity((NSOpenGLContext*)context());
+    }
+  }
+};
+
+
+Fl_Gl_Window *fl_mac_prepare_add_widgets_to_GL3_win(Fl_Gl_Window *gl3win) {
+  gl3win->begin();
+  transparentGlWindow *transp = new transparentGlWindow(0, 0,
+                        gl3win->w(), gl3win->h());
+  gl3win->end();
+  if (!gl3win->resizable()) gl3win->resizable(gl3win);
+  if (gl3win->shown()) {
+    transp->show();
+    gl3win->make_current();
+  }
+  return transp;
+}
+
+
 class Fl_Gl_Cocoa_Plugin : public Fl_Cocoa_Plugin {
 public:
   Fl_Gl_Cocoa_Plugin() : Fl_Cocoa_Plugin(name()) { }
diff --git src/glut_compatibility.cxx src/glut_compatibility.cxx
index 0a5a6b3..011f929 100644
--- src/glut_compatibility.cxx
+++ src/glut_compatibility.cxx
@@ -30,6 +30,9 @@
 #  include "Fl_Screen_Driver.H"
 #  include <FL/glut.H>
 #  define MAXWINDOWS 32
+#  ifndef GL_CURRENT_PROGRAM
+#    define GL_CURRENT_PROGRAM 0x8B8D  // from glew.h
+#  endif
 
 static Fl_Glut_Window *windows[MAXWINDOWS+1];
 
@@ -54,6 +57,27 @@ void Fl_Glut_Window::draw() {
   indraw = 1;
   if (!valid()) {reshape(pixel_w(),pixel_h()); valid(1);}
   display();
+  if (children()) {
+    if ((mode() & FL_OPENGL3)) {
+#ifndef __APPLE__
+      typedef void (*glUseProgram_type)(GLint);
+      static glUseProgram_type glUseProgram_f = NULL;
+      if (!glUseProgram_f) {
+        Fl_Gl_Window_Driver *dr = Fl_Gl_Window_Driver::driver(this);
+        glUseProgram_f = (glUseProgram_type)dr->GetProcAddress("glUseProgram");
+      }
+      GLint current_prog = 0;
+      glGetIntegerv(GL_CURRENT_PROGRAM, &current_prog);
+      // Switch from GL3-style to GL1-style drawing;
+      // good under Windows, X11 and Wayland; impossible under macOS.
+      glUseProgram_f(0);
+      // Draw FLTK child widgets
+      Fl_Gl_Window::draw();
+      // Switch back to GL3-style drawing
+      glUseProgram_f((GLuint)current_prog);
+#endif // ! __APPLE__
+    } else Fl_Gl_Window::draw(); // Draw FLTK child widgets
+  }
   indraw = 0;
 }
 
Direct Link to Message ]
 
     
Previous Message ]Next Message ]
 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.