FLTK logo

[master] 59fc60e - Simpler code to support FLTK widgets in macOS OpenGL 3 windows. Also, the application-level code to add widgets to a GL3 window becomes platform-independent.

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] 59fc60e - Simpler code to support FLTK widgets in macOS OpenGL 3 windows. Also, the application-level code to add widgets to a GL3 window becomes platform-independent. "ManoloFLTK" Sep 27, 2022  
 
commit 59fc60ea4cb8db6ee43a1ac37cd4bbbefcb87faa
Author:     ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>
AuthorDate: Tue Sep 27 14:12:39 2022 +0200
Commit:     ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>
CommitDate: Tue Sep 27 14:12:39 2022 +0200

    Simpler code to support FLTK widgets in macOS OpenGL 3 windows.
    Also, the application-level code to add widgets to a GL3 window becomes
    platform-independent.

 FL/mac.H                                        |  3 --
 documentation/src/opengl.dox                    | 30 -----------
 examples/OpenGL3test.cxx                        | 11 +----
 src/Fl_Gl_Choice.cxx                            | 22 ++++++++-
 src/Fl_Gl_Window.cxx                            |  3 ++
 src/Fl_Gl_Window_Driver.H                       |  9 +++-
 src/Fl_cocoa.mm                                 | 22 +++++++++
 src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H   | 11 ++++-
 src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx | 66 ++++++++++++-------------
 src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H      |  2 +
 src/glut_compatibility.cxx                      | 23 +--------
 11 files changed, 101 insertions(+), 101 deletions(-)

diff --git FL/mac.H FL/mac.H
index d289774..015b9dd 100644
--- FL/mac.H
+++ FL/mac.H
@@ -154,9 +154,6 @@ 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 68f5e71..d1a36be 100644
--- documentation/src/opengl.dox
+++ documentation/src/opengl.dox
@@ -605,36 +605,6 @@ 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 9de83b5..edcb56d 100644
--- examples/OpenGL3test.cxx
+++ examples/OpenGL3test.cxx
@@ -128,23 +128,17 @@ public:
       glEnableVertexAttribArray((GLuint)colourAttribute  );
       glVertexAttribPointer((GLuint)positionAttribute, 4, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), 0);
       glVertexAttribPointer((GLuint)colourAttribute  , 4, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), (char*)0+4*sizeof(GLfloat));
+      glUseProgram(shaderProgram);
     }
     else if ((!valid())) {
       glViewport(0, 0, pixel_w(), pixel_h());
     }
     glClearColor(0.08, 0.8, 0.8, 1.0);
     glClear(GL_COLOR_BUFFER_BIT);
-    glUseProgram(shaderProgram);
     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;
@@ -233,9 +227,6 @@ void button_cb(Fl_Widget *, void *) {
 }
 
 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
diff --git src/Fl_Gl_Choice.cxx src/Fl_Gl_Choice.cxx
index f0ddda6..bafab56 100644
--- src/Fl_Gl_Choice.cxx
+++ src/Fl_Gl_Choice.cxx
@@ -28,7 +28,10 @@
 #include "Fl_Gl_Window_Driver.H"
 #include <FL/gl_draw.H>
 #include <stdlib.h>
-
+#ifndef GL_CURRENT_PROGRAM
+// from glew.h in Windows, glext.h in Unix, not used by FLTK's macOS platform
+#  define GL_CURRENT_PROGRAM 0x8B8D
+#endif
 GLContext *Fl_Gl_Window_Driver::context_list = 0;
 int Fl_Gl_Window_Driver::nContext = 0;
 static int NContext = 0;
@@ -57,6 +60,23 @@ void Fl_Gl_Window_Driver::del_context(GLContext ctx) {
   if (!nContext) gl_remove_displaylist_fonts();
 }
 
+Fl_Gl_Window_Driver::glUseProgram_type Fl_Gl_Window_Driver::glUseProgram_f = NULL;
+
+void Fl_Gl_Window_Driver::switch_to_GL1() {
+  if (!glUseProgram_f) {
+    glUseProgram_f = (glUseProgram_type)GetProcAddress("glUseProgram");
+  }
+  glGetIntegerv(GL_CURRENT_PROGRAM, &current_prog);
+  // Switch from GL3-style to GL1-style drawing;
+  // good under Windows, X11 and Wayland; not appropriate under macOS.
+  // suggested by https://stackoverflow.com/questions/22293870/mixing-fixed-function-pipeline-and-programmable-pipeline-in-opengl
+  if (current_prog) glUseProgram_f(0);
+}
+
+void Fl_Gl_Window_Driver::switch_back() {
+  if (current_prog) glUseProgram_f((GLuint)current_prog);
+}
+
 Fl_Gl_Choice *Fl_Gl_Window_Driver::first;
 
 // this assumes one of the two arguments is zero:
diff --git src/Fl_Gl_Window.cxx src/Fl_Gl_Window.cxx
index 7784af9..b6c8f01 100644
--- src/Fl_Gl_Window.cxx
+++ src/Fl_Gl_Window.cxx
@@ -262,6 +262,7 @@ void Fl_Gl_Window::resize(int X,int Y,int W,int H) {
   if (is_a_resize) valid(0);
   pGlWindowDriver->resize(is_a_resize, W, H);
   Fl_Window::resize(X,Y,W,H);
+  //pGlWindowDriver->resize(is_a_resize, W, H);//essai
 }
 
 /**
@@ -343,6 +344,7 @@ void Fl_Gl_Window::draw_overlay() {}
  \see \ref opengl_with_fltk_widgets
  */
 void Fl_Gl_Window::draw_begin() {
+  if (mode() & FL_OPENGL3) pGlWindowDriver->switch_to_GL1();
   Fl_Surface_Device::push_current( Fl_OpenGL_Display_Device::display_device() );
   Fl_OpenGL_Graphics_Driver *drv = (Fl_OpenGL_Graphics_Driver*)Fl_Surface_Device::surface()->driver();
   drv->pixels_per_unit_ = pixels_per_unit();
@@ -391,6 +393,7 @@ void Fl_Gl_Window::draw_end() {
   glPopAttrib(); // GL_ENABLE_BIT
 
   Fl_Surface_Device::pop_current();
+  if (mode() & FL_OPENGL3) pGlWindowDriver->switch_back();
 }
 
 /** Draws the Fl_Gl_Window.
diff --git src/Fl_Gl_Window_Driver.H src/Fl_Gl_Window_Driver.H
index 8f3f6cf..383b6bf 100644
--- src/Fl_Gl_Window_Driver.H
+++ src/Fl_Gl_Window_Driver.H
@@ -25,6 +25,7 @@
 #define Fl_Gl_Window_Driver_H
 
 #include <FL/Fl_Gl_Window.H>
+#include <FL/gl.h> // for GLint
 
 class Fl_Gl_Choice;
 class Fl_Font_Descriptor;
@@ -33,6 +34,10 @@ class Fl_Font_Descriptor;
  platform-specific derived class from this class.
  */
 class Fl_Gl_Window_Driver {
+private:
+  GLint current_prog;
+  typedef void (*glUseProgram_type)(GLint);
+  static glUseProgram_type glUseProgram_f;
 protected:
   Fl_Gl_Window *pWindow;
 public:
@@ -53,7 +58,7 @@ public:
   void* overlay() {return pWindow->overlay;}
   void draw_overlay() {pWindow->draw_overlay();}
 
-  Fl_Gl_Window_Driver(Fl_Gl_Window *win) : pWindow(win) {}
+  Fl_Gl_Window_Driver(Fl_Gl_Window *win) : pWindow(win) {current_prog=0;}
   virtual ~Fl_Gl_Window_Driver() {}
   static Fl_Gl_Window_Driver *newGlWindowDriver(Fl_Gl_Window *w);
   static Fl_Gl_Window_Driver *global();
@@ -104,6 +109,8 @@ public:
   // true means the platform uses glScissor() to make sure GL subwindows
   // don't leak outside their parent window
   virtual bool need_scissor() { return false; }
+  virtual void switch_to_GL1();
+  virtual void switch_back();
 };
 
 #endif /* Fl_Gl_Window_Driver_H */
diff --git src/Fl_cocoa.mm src/Fl_cocoa.mm
index 47be438..7832736 100644
--- src/Fl_cocoa.mm
+++ src/Fl_cocoa.mm
@@ -2940,6 +2940,28 @@ NSOpenGLContext* Fl_Cocoa_Window_Driver::create_GLcontext_for_window(NSOpenGLPix
   return context;
 }
 
+
+NSOpenGLContext *Fl_Cocoa_Window_Driver::gl1ctxt_create() {
+  FLView *view = (FLView*)[fl_xid(pWindow) contentView];
+  NSView *gl1view = [[NSView alloc] initWithFrame:[view frame]];
+  [view addSubview:gl1view];
+  [gl1view release];
+  NSOpenGLPixelFormat *gl1pixelformat =
+      Fl_Cocoa_Window_Driver::mode_to_NSOpenGLPixelFormat(
+                              FL_RGB8 | FL_ALPHA | FL_SINGLE, NULL);
+  NSOpenGLContext *gl1ctxt = [[NSOpenGLContext alloc]
+                              initWithFormat:gl1pixelformat shareContext:nil];
+  [gl1pixelformat release];
+  remove_gl_context_opacity(gl1ctxt);
+  [gl1ctxt setView:gl1view];
+  return gl1ctxt;
+}
+
+
+void Fl_Cocoa_Window_Driver::gl1ctxt_resize(NSOpenGLContext *ctxt) {
+  [[ctxt view] setFrame:[[[ctxt view] superview] frame]];
+}
+
 #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_VERSION_12_0
 #  define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity
 #endif
diff --git src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H
index 1f03321..e1a8dab 100644
--- src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H
+++ src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H
@@ -20,10 +20,17 @@
 #include "../../Fl_Gl_Window_Driver.H"
 
 class Fl_Gl_Choice;
+#ifdef __OBJC__
+  @class NSOpenGLContext;
+#else
+  class NSOpenGLContext;
+#endif
 
 class Fl_Cocoa_Gl_Window_Driver : public Fl_Gl_Window_Driver {
+  NSOpenGLContext *gl1ctxt; // GL1 context in addition to GL3 context
   friend Fl_Gl_Window_Driver* Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *);
-  Fl_Cocoa_Gl_Window_Driver(Fl_Gl_Window *win) : Fl_Gl_Window_Driver(win) {}
+  Fl_Cocoa_Gl_Window_Driver(Fl_Gl_Window *win);
+  ~Fl_Cocoa_Gl_Window_Driver();
   virtual float pixels_per_unit();
   virtual void before_show(int& need_after);
   virtual void after_show();
@@ -44,6 +51,8 @@ class Fl_Cocoa_Gl_Window_Driver : public Fl_Gl_Window_Driver {
   virtual bool need_scissor() { return true; }
   virtual void* GetProcAddress(const char *procName);
   void apply_scissor();
+  virtual void switch_to_GL1();
+  virtual void switch_back();
 };
 
 
diff --git src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx
index b14ac6a..7a20a75 100644
--- src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx
+++ src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx
@@ -48,6 +48,15 @@ public:
 };
 
 
+Fl_Cocoa_Gl_Window_Driver::Fl_Cocoa_Gl_Window_Driver(Fl_Gl_Window *win) :
+                              Fl_Gl_Window_Driver(win) {
+  gl1ctxt = NULL;
+}
+
+Fl_Cocoa_Gl_Window_Driver::~Fl_Cocoa_Gl_Window_Driver() {
+  if (gl1ctxt) Fl_Cocoa_Window_Driver::GLcontext_release(gl1ctxt);
+}
+
 Fl_Gl_Choice *Fl_Cocoa_Gl_Window_Driver::find(int m, const int *alistp)
 {
   Fl::screen_driver()->open_display(); // useful when called through gl_start()
@@ -188,9 +197,18 @@ void Fl_Cocoa_Gl_Window_Driver::swap_buffers() {
 
 char Fl_Cocoa_Gl_Window_Driver::swap_type() {return copy;}
 
+static void delayed_redraw(Fl_Gl_Window *win) {
+  win->redraw();
+}
+
 void Fl_Cocoa_Gl_Window_Driver::resize(int is_a_resize, int w, int h) {
   if (pWindow->shown()) apply_scissor();
   Fl_Cocoa_Window_Driver::GLcontext_update((NSOpenGLContext*)pWindow->context());
+  if (gl1ctxt) {
+    Fl_Cocoa_Window_Driver::gl1ctxt_resize(gl1ctxt);
+    Fl_Cocoa_Window_Driver::GLcontext_update(gl1ctxt);
+    Fl::add_timeout(0.01, (Fl_Timeout_Handler)delayed_redraw, pWindow);
+  }
 }
 
 void Fl_Cocoa_Gl_Window_Driver::apply_scissor() {
@@ -304,44 +322,26 @@ 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
+/* macOS offers only core contexts when using GL3. This forbids to draw
+ FLTK widgets in a GL3-using NSOpenGLContext 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.
+ is to create an additional NSView and an associated additional NSOpenGLContext
+ placed above and sized as the GL3-based window, to set the new NSOpenGLContext
+ non opaque and GL1-based, and to draw the FLTK widgets in the new
+ view/GL context.
  */
 
-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());
-    }
+void Fl_Cocoa_Gl_Window_Driver::switch_to_GL1() {
+  if (!gl1ctxt) {
+    gl1ctxt = Fl_Cocoa_Window_Driver::driver(pWindow)->gl1ctxt_create();
+    Fl::add_timeout(0.01, (Fl_Timeout_Handler)delayed_redraw, pWindow);
   }
-};
-
+  Fl_Cocoa_Window_Driver::GLcontext_makecurrent(gl1ctxt);
+}
 
-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;
+void Fl_Cocoa_Gl_Window_Driver::switch_back() {
+  glFlush();
+  Fl_Cocoa_Window_Driver::GLcontext_makecurrent((NSOpenGLContext*)pWindow->context());
 }
 
 
diff --git src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H
index cbd8537..d6f7534 100644
--- src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H
+++ src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H
@@ -155,6 +155,8 @@ public:
   static void GL_cleardrawable(void); // uses Objective-c
   static void gl_start(NSOpenGLContext*); // uses Objective-c
   static void remove_gl_context_opacity(NSOpenGLContext*); // uses Objective-c
+  NSOpenGLContext *gl1ctxt_create(); // uses Objective-c
+  static void gl1ctxt_resize(NSOpenGLContext*); // uses Objective-c
 
   //icons
   virtual void icons(const Fl_RGB_Image *icons[], int count);
diff --git src/glut_compatibility.cxx src/glut_compatibility.cxx
index 011f929..c7484ad 100644
--- src/glut_compatibility.cxx
+++ src/glut_compatibility.cxx
@@ -30,9 +30,6 @@
 #  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];
 
@@ -58,25 +55,7 @@ void Fl_Glut_Window::draw() {
   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
+    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'.