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.
This commit is contained in:
parent
2ffd4e4f1a
commit
59fc60ea4c
3
FL/mac.H
3
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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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, ¤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:
|
||||
|
@ -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.
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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, ¤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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user