diff --git a/FL/mac.H b/FL/mac.H index d289774f2..015b9ddda 100644 --- a/FL/mac.H +++ b/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 a/documentation/src/opengl.dox b/documentation/src/opengl.dox index 68f5e71aa..d1a36be11 100644 --- a/documentation/src/opengl.dox +++ b/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. -
  1. 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. -
  2. -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. - -
- 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 9de83b5bd..edcb56d93 100644 --- a/examples/OpenGL3test.cxx +++ b/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 a/src/Fl_Gl_Choice.cxx b/src/Fl_Gl_Choice.cxx index f0ddda652..bafab56fd 100644 --- a/src/Fl_Gl_Choice.cxx +++ b/src/Fl_Gl_Choice.cxx @@ -28,7 +28,10 @@ #include "Fl_Gl_Window_Driver.H" #include #include - +#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, ¤t_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 a/src/Fl_Gl_Window.cxx b/src/Fl_Gl_Window.cxx index 7784af9cb..b6c8f0135 100644 --- a/src/Fl_Gl_Window.cxx +++ b/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 a/src/Fl_Gl_Window_Driver.H b/src/Fl_Gl_Window_Driver.H index 8f3f6cf29..383b6bf56 100644 --- a/src/Fl_Gl_Window_Driver.H +++ b/src/Fl_Gl_Window_Driver.H @@ -25,6 +25,7 @@ #define Fl_Gl_Window_Driver_H #include +#include // 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 a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm index 47be438fc..783273662 100644 --- a/src/Fl_cocoa.mm +++ b/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 a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H index 1f0332103..e1a8dabb3 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H +++ b/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 a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx index b14ac6a17..7a20a7536 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx +++ b/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 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); } - 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_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 a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H index cbd853776..d6f7534c2 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H +++ b/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 a/src/glut_compatibility.cxx b/src/glut_compatibility.cxx index 011f9290b..c7484ad5f 100644 --- a/src/glut_compatibility.cxx +++ b/src/glut_compatibility.cxx @@ -30,9 +30,6 @@ # include "Fl_Screen_Driver.H" # include # 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, ¤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 + Fl_Gl_Window::draw(); // Draw FLTK child widgets } indraw = 0; }