diff options
| -rw-r--r-- | FL/mac.H | 4 | ||||
| -rw-r--r-- | documentation/src/opengl.dox | 30 | ||||
| -rw-r--r-- | examples/OpenGL3test.cxx | 32 | ||||
| -rw-r--r-- | src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx | 41 | ||||
| -rw-r--r-- | src/glut_compatibility.cxx | 24 |
5 files changed, 130 insertions, 1 deletions
@@ -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 a/documentation/src/opengl.dox b/documentation/src/opengl.dox index d1a36be11..68f5e71aa 100644 --- a/documentation/src/opengl.dox +++ b/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 a/examples/OpenGL3test.cxx b/examples/OpenGL3test.cxx index 9acbaf38b..26ee1b816 100644 --- a/examples/OpenGL3test.cxx +++ b/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 a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx index 4d47c3015..b14ac6a17 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx +++ b/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 a/src/glut_compatibility.cxx b/src/glut_compatibility.cxx index 0a5a6b30e..011f9290b 100644 --- a/src/glut_compatibility.cxx +++ b/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, ¤t_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; } |
