From c96a4f3141259d412b249144086492ec4c400355 Mon Sep 17 00:00:00 2001 From: ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> Date: Thu, 29 Sep 2022 16:25:14 +0200 Subject: macOS platform: rename Fl_Cocoa_Gl_Window_Driver.cxx to .mm --- src/CMakeLists.txt | 2 +- src/Fl_cocoa.mm | 181 --------- src/Makefile | 4 +- src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H | 1 - src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx | 380 ----------------- src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.mm | 518 ++++++++++++++++++++++++ src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H | 15 - 7 files changed, 521 insertions(+), 580 deletions(-) delete mode 100644 src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx create mode 100644 src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.mm (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 91d4f5f17..ab5188ece 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -440,7 +440,7 @@ elseif (FLTK_USE_X11) set (GL_DRIVER_FILES ${GL_DRIVER_FILES} drivers/X11/Fl_X11_Gl_Window_Driver.cxx drivers/X11/fl_X11_gl_platform_init.cxx) set (GL_DRIVER_HEADER_FILES drivers/X11/Fl_X11_Gl_Window_Driver.H) elseif (APPLE) - set (GL_DRIVER_FILES ${GL_DRIVER_FILES} drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx drivers/Cocoa/fl_macOS_gl_platform_init.cxx) + set (GL_DRIVER_FILES ${GL_DRIVER_FILES} drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.mm drivers/Cocoa/fl_macOS_gl_platform_init.cxx) set (GL_DRIVER_HEADER_FILES drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H) elseif (WIN32) set (GL_DRIVER_FILES ${GL_DRIVER_FILES} drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.cxx drivers/WinAPI/fl_WinAPI_gl_platform_init.cxx) diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm index ccb4ebe81..694e54ae1 100644 --- a/src/Fl_cocoa.mm +++ b/src/Fl_cocoa.mm @@ -2831,184 +2831,6 @@ static FLTextInputContext* fltextinputcontext_instance = nil; @end -NSOpenGLPixelFormat* Fl_Cocoa_Window_Driver::mode_to_NSOpenGLPixelFormat(int m, const int *alistp) -{ - NSOpenGLPixelFormatAttribute attribs[32]; - int n = 0; - // AGL-style code remains commented out for comparison - if (!alistp) { - if (m & FL_INDEX) { - //list[n++] = AGL_BUFFER_SIZE; list[n++] = 8; - } else { - //list[n++] = AGL_RGBA; - //list[n++] = AGL_GREEN_SIZE; - //list[n++] = (m & FL_RGB8) ? 8 : 1; - attribs[n++] = NSOpenGLPFAColorSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)((m & FL_RGB8) ? 32 : 1); - if (m & FL_ALPHA) { - //list[n++] = AGL_ALPHA_SIZE; - attribs[n++] = NSOpenGLPFAAlphaSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)((m & FL_RGB8) ? 8 : 1); - } - if (m & FL_ACCUM) { - //list[n++] = AGL_ACCUM_GREEN_SIZE; list[n++] = 1; - attribs[n++] = NSOpenGLPFAAccumSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)1; - if (m & FL_ALPHA) { - //list[n++] = AGL_ACCUM_ALPHA_SIZE; list[n++] = 1; - } - } - } - if (m & FL_DOUBLE) { - //list[n++] = AGL_DOUBLEBUFFER; - attribs[n++] = NSOpenGLPFADoubleBuffer; - } - if (m & FL_DEPTH) { - //list[n++] = AGL_DEPTH_SIZE; list[n++] = 24; - attribs[n++] = NSOpenGLPFADepthSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)24; - } - if (m & FL_STENCIL) { - //list[n++] = AGL_STENCIL_SIZE; list[n++] = 1; - attribs[n++] = NSOpenGLPFAStencilSize; - attribs[n++] = (NSOpenGLPixelFormatAttribute)1; - } - if (m & FL_STEREO) { - //list[n++] = AGL_STEREO; - attribs[n++] = NSOpenGLPFAStereo; - } - if ((m & FL_MULTISAMPLE) && fl_mac_os_version >= 100400) { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 - attribs[n++] = NSOpenGLPFAMultisample, // 10.4 -#endif - attribs[n++] = NSOpenGLPFASampleBuffers; attribs[n++] = (NSOpenGLPixelFormatAttribute)1; - attribs[n++] = NSOpenGLPFASamples; attribs[n++] = (NSOpenGLPixelFormatAttribute)4; - } -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 -#define NSOpenGLPFAOpenGLProfile (NSOpenGLPixelFormatAttribute)99 -#define kCGLPFAOpenGLProfile NSOpenGLPFAOpenGLProfile -#define NSOpenGLProfileVersionLegacy (NSOpenGLPixelFormatAttribute)0x1000 -#define NSOpenGLProfileVersion3_2Core (NSOpenGLPixelFormatAttribute)0x3200 -#define kCGLOGLPVersion_Legacy NSOpenGLProfileVersionLegacy -#endif - if (fl_mac_os_version >= 100700) { - attribs[n++] = NSOpenGLPFAOpenGLProfile; - attribs[n++] = (m & FL_OPENGL3) ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy; - } - } else { - while (alistp[n] && n < 30) { - if (alistp[n] == kCGLPFAOpenGLProfile) { - if (fl_mac_os_version < 100700) { - if (alistp[n+1] != kCGLOGLPVersion_Legacy) return nil; - n += 2; - continue; - } - } - attribs[n] = (NSOpenGLPixelFormatAttribute)alistp[n]; - n++; - } - } - attribs[n] = (NSOpenGLPixelFormatAttribute)0; - NSOpenGLPixelFormat *pixform = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; - /*GLint color,alpha,accum,depth; - [pixform getValues:&color forAttribute:NSOpenGLPFAColorSize forVirtualScreen:0]; - [pixform getValues:&alpha forAttribute:NSOpenGLPFAAlphaSize forVirtualScreen:0]; - [pixform getValues:&accum forAttribute:NSOpenGLPFAAccumSize forVirtualScreen:0]; - [pixform getValues:&depth forAttribute:NSOpenGLPFADepthSize forVirtualScreen:0]; - NSLog(@"color=%d alpha=%d accum=%d depth=%d",color,alpha,accum,depth);*/ - return pixform; -} - -NSOpenGLContext* Fl_Cocoa_Window_Driver::create_GLcontext_for_window(NSOpenGLPixelFormat *pixelformat, - NSOpenGLContext *shared_ctx, Fl_Window *window) -{ - NSOpenGLContext *context = [[NSOpenGLContext alloc] initWithFormat:pixelformat shareContext:shared_ctx]; - if (shared_ctx && !context) context = [[NSOpenGLContext alloc] initWithFormat:pixelformat shareContext:nil]; - if (context) { - FLView *view = (FLView*)[fl_xid(window) contentView]; - if (fl_mac_os_version >= 100700) { - //replaces [view setWantsBestResolutionOpenGLSurface:YES] without compiler warning - typedef void (*bestResolutionIMP)(id, SEL, BOOL); - static bestResolutionIMP addr = (bestResolutionIMP)[NSView instanceMethodForSelector:@selector(setWantsBestResolutionOpenGLSurface:)]; - addr(view, @selector(setWantsBestResolutionOpenGLSurface:), Fl::use_high_res_GL() != 0); - } - [context setView:view]; - if (Fl_Cocoa_Window_Driver::driver(window)->subRect()) { - remove_gl_context_opacity(context); - } - } - return context; -} - - -NSOpenGLContext *Fl_Cocoa_Window_Driver::gl1ctxt_create(NSView **gl1view) { - FLView *view = (FLView*)[fl_xid(pWindow) contentView]; - *gl1view = [[NSView alloc] initWithFrame:[view frame]]; - 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]; - return gl1ctxt; -} - -void Fl_Cocoa_Window_Driver::gl1ctxt_add(NSOpenGLContext *gl1ctxt, NSView *gl1view) { - FLView *flview = (FLView*)[fl_xid(pWindow) contentView]; - [flview addSubview:gl1view]; - [gl1view release]; -#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_7 - if (fl_mac_os_version >= 100700 && Fl::use_high_res_GL()) { - [gl1view setWantsBestResolutionOpenGLSurface:YES]; - } -#endif - [gl1ctxt setView:gl1view]; - remove_gl_context_opacity(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 - -void Fl_Cocoa_Window_Driver::remove_gl_context_opacity(NSOpenGLContext *ctx) { - GLint gl_opacity; - [ctx getValues:&gl_opacity forParameter:NSOpenGLContextParameterSurfaceOpacity]; - if (gl_opacity != 0) { - gl_opacity = 0; - [ctx setValues:&gl_opacity forParameter:NSOpenGLContextParameterSurfaceOpacity]; - } -} - -void Fl_Cocoa_Window_Driver::GLcontext_update(NSOpenGLContext* ctxt) -{ - [ctxt update]; -} - -void Fl_Cocoa_Window_Driver::flush_context(NSOpenGLContext* ctxt) -{ - [ctxt flushBuffer]; -} - -void Fl_Cocoa_Window_Driver::GLcontext_release(NSOpenGLContext* ctxt) -{ - [ctxt release]; -} - -void Fl_Cocoa_Window_Driver::GL_cleardrawable(void) -{ - [[NSOpenGLContext currentContext] clearDrawable]; -} - -void Fl_Cocoa_Window_Driver::GLcontext_makecurrent(NSOpenGLContext* ctxt) -{ - [ctxt makeCurrentContext]; -} - /* * Initialize the given port for redraw and call the window's flush() to actually draw the content */ @@ -4561,9 +4383,6 @@ void Fl_Cocoa_Window_Driver::draw_titlebar_to_context(CGContextRef gc, int w, in } } -void Fl_Cocoa_Window_Driver::gl_start(NSOpenGLContext *ctxt) { - [ctxt update]; // supports window resizing -} /* Returns the version of the running Mac OS as an int such as 100802 for 10.8.2, and also assigns that value to global fl_mac_os_version. diff --git a/src/Makefile b/src/Makefile index 0510cbb66..1271f7ce3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -202,7 +202,7 @@ GLCPPFILES = \ drivers/OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx \ drivers/OpenGL/Fl_OpenGL_Graphics_Driver_vertex.cxx -GLCPPFILES_OSX = drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx \ +GLCPPFILES_OSX = drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.mm \ drivers/Cocoa/fl_macOS_gl_platform_init.cxx GLCPPFILES_X11 = drivers/X11/Fl_X11_Gl_Window_Driver.cxx \ drivers/X11/fl_X11_gl_platform_init.cxx @@ -427,7 +427,7 @@ CXXFLAGS += $(EXTRA_CXXFLAGS_$(BUILD)) OBJECTS = $(MMFILES:.mm=.o) $(CPPFILES:.cxx=.o) $(CFILES:.c=.o) $(UTF8CFILES:.c=.o) OBJECTS += $(EXTRA_OBJECTS_$(BUILD)) -GLOBJECTS = $(GLCPPFILES:.cxx=.o) +GLOBJECTS = $(GLCPPFILES:.cxx=.o) $(GLCPPFILES:.mm=.o) FLOBJECTS = $(FLCPPFILES:.cxx=.o) IMGOBJECTS = $(IMGCPPFILES:.cxx=.o) diff --git a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H index f0456eec9..01ab231c2 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H +++ b/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.H @@ -28,7 +28,6 @@ class Fl_Gl_Choice; class Fl_Cocoa_Gl_Window_Driver : public Fl_Gl_Window_Driver { NSOpenGLContext *gl1ctxt; // GL1 context in addition to GL3 context - static void delayed_addgl1ctxt(void *data); friend Fl_Gl_Window_Driver* Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *); Fl_Cocoa_Gl_Window_Driver(Fl_Gl_Window *win); virtual float pixels_per_unit(); diff --git a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx deleted file mode 100644 index 3ee281b37..000000000 --- a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx +++ /dev/null @@ -1,380 +0,0 @@ -// -// Class Fl_Cocoa_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). -// -// Copyright 2021-2022 by Bill Spitzak and others. -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -#include -#if HAVE_GL -#include -#include -#include "../../Fl_Gl_Choice.H" -#include "../../Fl_Screen_Driver.H" -#include "Fl_Cocoa_Window_Driver.H" -#include "Fl_Cocoa_Gl_Window_Driver.H" -#include -#include -#include -#include - - -#ifdef __OBJC__ -@class NSOpenGLPixelFormat; -#else -class NSOpenGLPixelFormat; -#endif // __OBJC__ - - -// Describes crap needed to create a GLContext. -class Fl_Cocoa_Gl_Choice : public Fl_Gl_Choice { - friend class Fl_Cocoa_Gl_Window_Driver; -private: - NSOpenGLPixelFormat* pixelformat; -public: - Fl_Cocoa_Gl_Choice(int m, const int *alistp, Fl_Gl_Choice *n) : Fl_Gl_Choice(m, alistp, n) { - pixelformat = NULL; - } -}; - - -Fl_Cocoa_Gl_Window_Driver::Fl_Cocoa_Gl_Window_Driver(Fl_Gl_Window *win) : - Fl_Gl_Window_Driver(win) { - gl1ctxt = NULL; -} - -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() - Fl_Cocoa_Gl_Choice *g = (Fl_Cocoa_Gl_Choice*)Fl_Gl_Window_Driver::find_begin(m, alistp); - if (g) return g; - NSOpenGLPixelFormat* fmt = Fl_Cocoa_Window_Driver::mode_to_NSOpenGLPixelFormat(m, alistp); - if (!fmt) return 0; - g = new Fl_Cocoa_Gl_Choice(m, alistp, first); - first = g; - g->pixelformat = fmt; - return g; -} - -GLContext Fl_Cocoa_Gl_Window_Driver::create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer) { - GLContext context, shared_ctx = 0; - if (context_list && nContext) shared_ctx = context_list[0]; - // resets the pile of string textures used to draw strings - // necessary before the first context is created - if (!shared_ctx) gl_texture_reset(); - context = Fl_Cocoa_Window_Driver::create_GLcontext_for_window(((Fl_Cocoa_Gl_Choice*)g)->pixelformat, (NSOpenGLContext*)shared_ctx, window); - if (!context) return 0; - add_context(context); - Fl_Cocoa_Window_Driver::GLcontext_makecurrent((NSOpenGLContext*)context); - glClearColor(0., 0., 0., 1.); - apply_scissor(); - return (context); -} - -void Fl_Cocoa_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context) { - if (context != cached_context || w != cached_window) { - cached_context = context; - cached_window = w; - Fl_Cocoa_Window_Driver::GLcontext_makecurrent((NSOpenGLContext*)context); - } -} - -void Fl_Cocoa_Gl_Window_Driver::delete_gl_context(GLContext context) { - if (cached_context == context) { - cached_context = 0; - cached_window = 0; - Fl_Cocoa_Window_Driver::GL_cleardrawable(); - } - Fl_Cocoa_Window_Driver::GLcontext_release((NSOpenGLContext*)context); - del_context(context); -} - -void Fl_Cocoa_Gl_Window_Driver::make_overlay_current() { - // this is not very useful, but unfortunately, Apple decided - // that front buffer drawing can no longer (OS X 10.4) be supported on their platforms. - pWindow->make_current(); -} - -void Fl_Cocoa_Gl_Window_Driver::redraw_overlay() { - pWindow->redraw(); -} - -void Fl_Cocoa_Gl_Window_Driver::before_show(int& need_after) { - need_after = 1; -} - -void Fl_Cocoa_Gl_Window_Driver::after_show() { - // Makes sure the GL context is created to avoid drawing twice the window when first shown - pWindow->make_current(); -} - -float Fl_Cocoa_Gl_Window_Driver::pixels_per_unit() -{ - int retina = (fl_mac_os_version >= 100700 && Fl::use_high_res_GL() && Fl_X::i(pWindow) && - Fl_Cocoa_Window_Driver::driver(pWindow)->mapped_to_retina()) ? 2 : 1; - return retina * Fl_Graphics_Driver::default_driver().scale(); -} - -int Fl_Cocoa_Gl_Window_Driver::mode_(int m, const int *a) { - if (a) { // when the mode is set using the a array of system-dependent values, and if asking for double buffer, - // the FL_DOUBLE flag must be set in the mode_ member variable - const int *aa = a; - while (*aa) { - if (*(aa++) == - kCGLPFADoubleBuffer - ) { m |= FL_DOUBLE; break; } - } - } - pWindow->context(0); - mode( m); alist(a); - if (pWindow->shown()) { - g( find(m, a) ); - pWindow->redraw(); - } else { - g(0); - } - return 1; -} - -void Fl_Cocoa_Gl_Window_Driver::make_current_before() { - // detect if the window was moved between low and high resolution displays - Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(pWindow); - if (d->changed_resolution()){ - d->changed_resolution(false); - pWindow->invalidate(); - Fl_Cocoa_Window_Driver::GLcontext_update((NSOpenGLContext*)pWindow->context()); - } -} - -void Fl_Cocoa_Gl_Window_Driver::swap_buffers() { - if (overlay() != NULL) { - // STR# 2944 [1] - // Save matrixmode/proj/modelview/rasterpos before doing overlay. - // - int wo = pWindow->pixel_w(), ho = pWindow->pixel_h(); - GLint matrixmode; - GLfloat pos[4]; - glGetIntegerv(GL_MATRIX_MODE, &matrixmode); - glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); // save original glRasterPos - glMatrixMode(GL_PROJECTION); // save proj/model matrices - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glScalef(2.0f/wo, 2.0f/ho, 1.0f); - glTranslatef(-wo/2.0f, -ho/2.0f, 0.0f); // set transform so 0,0 is bottom/left of Gl_Window - glRasterPos2i(0,0); // set glRasterPos to bottom left corner - { - // Emulate overlay by doing copypixels - glReadBuffer(GL_BACK); - glDrawBuffer(GL_FRONT); - glCopyPixels(0, 0, wo, ho, GL_COLOR); // copy GL_BACK to GL_FRONT - } - glPopMatrix(); // GL_MODELVIEW // restore model/proj matrices - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(matrixmode); - glRasterPos3f(pos[0], pos[1], pos[2]); // restore original glRasterPos - } - else - Fl_Cocoa_Window_Driver::flush_context((NSOpenGLContext*)pWindow->context());//aglSwapBuffers((AGLContext)context_); -} - -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() { - CGRect *extents = Fl_Cocoa_Window_Driver::driver(pWindow)->subRect(); - if (extents) { - Fl_Cocoa_Window_Driver::remove_gl_context_opacity((NSOpenGLContext*)pWindow->context()); - glDisable(GL_SCISSOR_TEST); - GLdouble vals[4]; - glGetDoublev(GL_COLOR_CLEAR_VALUE, vals); - glClearColor(0., 0., 0., 0.); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(vals[0], vals[1], vals[2], vals[3]); - float s = pWindow->pixels_per_unit(); - glScissor(s*extents->origin.x, s*extents->origin.y, s*extents->size.width, s*extents->size.height); -//printf("apply_scissor %dx%d %dx%d\n",extents->x, extents->y, extents->width, extents->height); - glEnable(GL_SCISSOR_TEST); - } -} - - -/* Some old Apple hardware doesn't implement the GL_EXT_texture_rectangle extension. - For it, draw_string_legacy_glut() is used to draw text. */ - -char *Fl_Cocoa_Gl_Window_Driver::alpha_mask_for_string(const char *str, int n, int w, int h, Fl_Fontsize fs) -{ - // write str to a bitmap just big enough - Fl_Image_Surface *surf = new Fl_Image_Surface(w, h); - Fl_Font f=fl_font(); - Fl_Surface_Device::push_current(surf); - fl_color(FL_WHITE); - fl_font(f, fs); - fl_draw(str, n, 0, fl_height() - fl_descent()); - // get the alpha channel only of the bitmap - char *alpha_buf = new char[w*h], *r = alpha_buf, *q; - q = (char*)CGBitmapContextGetData((CGContextRef)surf->offscreen()); - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - *r++ = *(q+3); - q += 4; - } - } - Fl_Surface_Device::pop_current(); - delete surf; - return alpha_buf; -} - -void Fl_Cocoa_Gl_Window_Driver::gl_start() { - Fl_Cocoa_Window_Driver::gl_start((NSOpenGLContext*)gl_start_context); -} - -// convert BGRA to RGB and also exchange top and bottom -static uchar *convert_BGRA_to_RGB(uchar *baseAddress, int w, int h, int mByteWidth) -{ - uchar *newimg = new uchar[3*w*h]; - uchar *to = newimg; - for (int i = h-1; i >= 0; i--) { - uchar *from = baseAddress + i * mByteWidth; - for (int j = 0; j < w; j++, from += 4) { -#if defined(__ppc__) && __ppc__ - memcpy(to, from + 1, 3); - to += 3; -#else - *(to++) = *(from+2); - *(to++) = *(from+1); - *(to++) = *from; -#endif - } - } - delete[] baseAddress; - return newimg; -} - -Fl_RGB_Image* Fl_Cocoa_Gl_Window_Driver::capture_gl_rectangle(int x, int y, int w, int h) -{ - Fl_Gl_Window* glw = pWindow; - float factor = glw->pixels_per_unit(); - if (factor != 1) { - w *= factor; h *= factor; x *= factor; y *= factor; - } - Fl_Cocoa_Window_Driver::GLcontext_makecurrent((NSOpenGLContext*)glw->context()); - Fl_Cocoa_Window_Driver::flush_context((NSOpenGLContext*)glw->context()); // to capture also the overlay and for directGL demo - // Read OpenGL context pixels directly. - // For extra safety, save & restore OpenGL states that are changed - glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); - glPixelStorei(GL_PACK_ALIGNMENT, 4); /* Force 4-byte alignment */ - glPixelStorei(GL_PACK_ROW_LENGTH, 0); - glPixelStorei(GL_PACK_SKIP_ROWS, 0); - glPixelStorei(GL_PACK_SKIP_PIXELS, 0); - // Read a block of pixels from the frame buffer - int mByteWidth = w * 4; - mByteWidth = (mByteWidth + 3) & ~3; // Align to 4 bytes - uchar *baseAddress = new uchar[mByteWidth * h]; - glReadPixels(x, glw->pixel_h() - (y+h), w, h, - GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, baseAddress); - glPopClientAttrib(); - baseAddress = convert_BGRA_to_RGB(baseAddress, w, h, mByteWidth); - Fl_RGB_Image *img = new Fl_RGB_Image(baseAddress, w, h, 3, 3 * w); - img->alloc_array = 1; - Fl_Cocoa_Window_Driver::flush_context((NSOpenGLContext*)glw->context()); - return img; -} - - -void* Fl_Cocoa_Gl_Window_Driver::GetProcAddress(const char *procName) { - return dlsym(RTLD_DEFAULT, procName); -} - - -FL_EXPORT NSOpenGLContext *fl_mac_glcontext(GLContext rc) { - return (NSOpenGLContext*)rc; -} - - -/* 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 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. - */ - -static struct win_view { - Fl_Gl_Window *win; - NSView *gl1view; - NSOpenGLContext *gl1ctxt; -} win_view_struct; - -void Fl_Cocoa_Gl_Window_Driver::delayed_addgl1ctxt(void *d) { - struct win_view *data = (struct win_view *)d; - Fl_Cocoa_Window_Driver::driver(data->win)->gl1ctxt_add(data->gl1ctxt, data->gl1view); - data->win->redraw(); -} - -void Fl_Cocoa_Gl_Window_Driver::switch_to_GL1() { - if (!gl1ctxt) { - gl1ctxt = Fl_Cocoa_Window_Driver::driver(pWindow)->gl1ctxt_create( - &win_view_struct.gl1view); - win_view_struct.win = pWindow; - win_view_struct.gl1ctxt = gl1ctxt; - Fl::add_timeout(0.01, - Fl_Cocoa_Gl_Window_Driver::delayed_addgl1ctxt, - &win_view_struct); - } - Fl_Cocoa_Window_Driver::GLcontext_makecurrent(gl1ctxt); - glClearColor(0., 0., 0., 0.); - glClear(GL_COLOR_BUFFER_BIT); -} - -void Fl_Cocoa_Gl_Window_Driver::switch_back() { - glFlush(); - Fl_Cocoa_Window_Driver::GLcontext_makecurrent((NSOpenGLContext*)pWindow->context()); -} - -void Fl_Cocoa_Gl_Window_Driver::gl_hide_before(void *&) { - if (gl1ctxt) { - Fl_Cocoa_Window_Driver::GLcontext_release(gl1ctxt); - gl1ctxt = 0; - } -} - - -class Fl_Gl_Cocoa_Plugin : public Fl_Cocoa_Plugin { -public: - Fl_Gl_Cocoa_Plugin() : Fl_Cocoa_Plugin(name()) { } - virtual const char *name() { return "gl.cocoa.fltk.org"; } - virtual void resize(Fl_Gl_Window *glw, int x, int y, int w, int h) { - glw->Fl_Gl_Window::resize(x, y, w, h); - } -}; - -static Fl_Gl_Cocoa_Plugin Gl_Cocoa_Plugin; - -#endif // HAVE_GL diff --git a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.mm b/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.mm new file mode 100644 index 000000000..741ab3373 --- /dev/null +++ b/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.mm @@ -0,0 +1,518 @@ +// +// Class Fl_Cocoa_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). +// +// Copyright 2021-2022 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +#include +#if HAVE_GL +#include +#include +#include "../../Fl_Gl_Choice.H" +#include "../../Fl_Screen_Driver.H" +#include "Fl_Cocoa_Window_Driver.H" +#include "Fl_Cocoa_Gl_Window_Driver.H" +#include +#include +#include +#include + +#import + +// Describes crap needed to create a GLContext. +class Fl_Cocoa_Gl_Choice : public Fl_Gl_Choice { + friend class Fl_Cocoa_Gl_Window_Driver; +private: + NSOpenGLPixelFormat* pixelformat; +public: + Fl_Cocoa_Gl_Choice(int m, const int *alistp, Fl_Gl_Choice *n) : Fl_Gl_Choice(m, alistp, n) { + pixelformat = NULL; + } +}; + + +Fl_Cocoa_Gl_Window_Driver::Fl_Cocoa_Gl_Window_Driver(Fl_Gl_Window *win) : + Fl_Gl_Window_Driver(win) { + gl1ctxt = NULL; +} + + +static NSOpenGLPixelFormat* mode_to_NSOpenGLPixelFormat(int m, const int *alistp) +{ + NSOpenGLPixelFormatAttribute attribs[32]; + int n = 0; + // AGL-style code remains commented out for comparison + if (!alistp) { + if (m & FL_INDEX) { + //list[n++] = AGL_BUFFER_SIZE; list[n++] = 8; + } else { + //list[n++] = AGL_RGBA; + //list[n++] = AGL_GREEN_SIZE; + //list[n++] = (m & FL_RGB8) ? 8 : 1; + attribs[n++] = NSOpenGLPFAColorSize; + attribs[n++] = (NSOpenGLPixelFormatAttribute)((m & FL_RGB8) ? 32 : 1); + if (m & FL_ALPHA) { + //list[n++] = AGL_ALPHA_SIZE; + attribs[n++] = NSOpenGLPFAAlphaSize; + attribs[n++] = (NSOpenGLPixelFormatAttribute)((m & FL_RGB8) ? 8 : 1); + } + if (m & FL_ACCUM) { + //list[n++] = AGL_ACCUM_GREEN_SIZE; list[n++] = 1; + attribs[n++] = NSOpenGLPFAAccumSize; + attribs[n++] = (NSOpenGLPixelFormatAttribute)1; + if (m & FL_ALPHA) { + //list[n++] = AGL_ACCUM_ALPHA_SIZE; list[n++] = 1; + } + } + } + if (m & FL_DOUBLE) { + //list[n++] = AGL_DOUBLEBUFFER; + attribs[n++] = NSOpenGLPFADoubleBuffer; + } + if (m & FL_DEPTH) { + //list[n++] = AGL_DEPTH_SIZE; list[n++] = 24; + attribs[n++] = NSOpenGLPFADepthSize; + attribs[n++] = (NSOpenGLPixelFormatAttribute)24; + } + if (m & FL_STENCIL) { + //list[n++] = AGL_STENCIL_SIZE; list[n++] = 1; + attribs[n++] = NSOpenGLPFAStencilSize; + attribs[n++] = (NSOpenGLPixelFormatAttribute)1; + } + if (m & FL_STEREO) { + //list[n++] = AGL_STEREO; + attribs[n++] = NSOpenGLPFAStereo; + } + if ((m & FL_MULTISAMPLE) && fl_mac_os_version >= 100400) { +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 + attribs[n++] = NSOpenGLPFAMultisample, // 10.4 +#endif + attribs[n++] = NSOpenGLPFASampleBuffers; attribs[n++] = (NSOpenGLPixelFormatAttribute)1; + attribs[n++] = NSOpenGLPFASamples; attribs[n++] = (NSOpenGLPixelFormatAttribute)4; + } +#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 +#define NSOpenGLPFAOpenGLProfile (NSOpenGLPixelFormatAttribute)99 +#define kCGLPFAOpenGLProfile NSOpenGLPFAOpenGLProfile +#define NSOpenGLProfileVersionLegacy (NSOpenGLPixelFormatAttribute)0x1000 +#define NSOpenGLProfileVersion3_2Core (NSOpenGLPixelFormatAttribute)0x3200 +#define kCGLOGLPVersion_Legacy NSOpenGLProfileVersionLegacy +#endif + if (fl_mac_os_version >= 100700) { + attribs[n++] = NSOpenGLPFAOpenGLProfile; + attribs[n++] = (m & FL_OPENGL3) ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy; + } + } else { + while (alistp[n] && n < 30) { + if (alistp[n] == kCGLPFAOpenGLProfile) { + if (fl_mac_os_version < 100700) { + if (alistp[n+1] != kCGLOGLPVersion_Legacy) return nil; + n += 2; + continue; + } + } + attribs[n] = (NSOpenGLPixelFormatAttribute)alistp[n]; + n++; + } + } + attribs[n] = (NSOpenGLPixelFormatAttribute)0; + NSOpenGLPixelFormat *pixform = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; + /*GLint color,alpha,accum,depth; + [pixform getValues:&color forAttribute:NSOpenGLPFAColorSize forVirtualScreen:0]; + [pixform getValues:&alpha forAttribute:NSOpenGLPFAAlphaSize forVirtualScreen:0]; + [pixform getValues:&accum forAttribute:NSOpenGLPFAAccumSize forVirtualScreen:0]; + [pixform getValues:&depth forAttribute:NSOpenGLPFADepthSize forVirtualScreen:0]; + NSLog(@"color=%d alpha=%d accum=%d depth=%d",color,alpha,accum,depth);*/ + return pixform; +} + + +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() + Fl_Cocoa_Gl_Choice *g = (Fl_Cocoa_Gl_Choice*)Fl_Gl_Window_Driver::find_begin(m, alistp); + if (g) return g; + NSOpenGLPixelFormat* fmt = mode_to_NSOpenGLPixelFormat(m, alistp); + if (!fmt) return 0; + g = new Fl_Cocoa_Gl_Choice(m, alistp, first); + first = g; + g->pixelformat = fmt; + return g; +} + + +#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_VERSION_12_0 +# define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity +#endif + +static void remove_gl_context_opacity(NSOpenGLContext *ctx) { + GLint gl_opacity; + [ctx getValues:&gl_opacity forParameter:NSOpenGLContextParameterSurfaceOpacity]; + if (gl_opacity != 0) { + gl_opacity = 0; + [ctx setValues:&gl_opacity forParameter:NSOpenGLContextParameterSurfaceOpacity]; + } +} + + +static NSOpenGLContext *create_GLcontext_for_window( + NSOpenGLPixelFormat *pixelformat, + NSOpenGLContext *shared_ctx, Fl_Window *window) +{ + NSOpenGLContext *context = [[NSOpenGLContext alloc] initWithFormat:pixelformat shareContext:shared_ctx]; + if (shared_ctx && !context) context = [[NSOpenGLContext alloc] initWithFormat:pixelformat shareContext:nil]; + if (context) { + NSView *view = [fl_xid(window) contentView]; + if (fl_mac_os_version >= 100700) { + //replaces [view setWantsBestResolutionOpenGLSurface:YES] without compiler warning + typedef void (*bestResolutionIMP)(id, SEL, BOOL); + static bestResolutionIMP addr = (bestResolutionIMP)[NSView instanceMethodForSelector:@selector(setWantsBestResolutionOpenGLSurface:)]; + addr(view, @selector(setWantsBestResolutionOpenGLSurface:), Fl::use_high_res_GL() != 0); + } + [context setView:view]; + if (Fl_Cocoa_Window_Driver::driver(window)->subRect()) { + remove_gl_context_opacity(context); + } + } + return context; +} + +GLContext Fl_Cocoa_Gl_Window_Driver::create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer) { + GLContext context, shared_ctx = 0; + if (context_list && nContext) shared_ctx = context_list[0]; + // resets the pile of string textures used to draw strings + // necessary before the first context is created + if (!shared_ctx) gl_texture_reset(); + context = create_GLcontext_for_window(((Fl_Cocoa_Gl_Choice*)g)->pixelformat, (NSOpenGLContext*)shared_ctx, window); + if (!context) return 0; + add_context(context); + [(NSOpenGLContext*)context makeCurrentContext]; + glClearColor(0., 0., 0., 1.); + apply_scissor(); + return (context); +} + +void Fl_Cocoa_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context) { + if (context != cached_context || w != cached_window) { + cached_context = context; + cached_window = w; + [(NSOpenGLContext*)context makeCurrentContext]; + } +} + +void Fl_Cocoa_Gl_Window_Driver::delete_gl_context(GLContext context) { + if (cached_context == context) { + cached_context = 0; + cached_window = 0; + [[NSOpenGLContext currentContext] clearDrawable]; + } + [(NSOpenGLContext*)context release]; + del_context(context); +} + +void Fl_Cocoa_Gl_Window_Driver::make_overlay_current() { + // this is not very useful, but unfortunately, Apple decided + // that front buffer drawing can no longer (OS X 10.4) be supported on their platforms. + pWindow->make_current(); +} + +void Fl_Cocoa_Gl_Window_Driver::redraw_overlay() { + pWindow->redraw(); +} + +void Fl_Cocoa_Gl_Window_Driver::before_show(int& need_after) { + need_after = 1; +} + +void Fl_Cocoa_Gl_Window_Driver::after_show() { + // Makes sure the GL context is created to avoid drawing twice the window when first shown + pWindow->make_current(); +} + +float Fl_Cocoa_Gl_Window_Driver::pixels_per_unit() +{ + int retina = (fl_mac_os_version >= 100700 && Fl::use_high_res_GL() && Fl_X::i(pWindow) && + Fl_Cocoa_Window_Driver::driver(pWindow)->mapped_to_retina()) ? 2 : 1; + return retina * Fl_Graphics_Driver::default_driver().scale(); +} + +int Fl_Cocoa_Gl_Window_Driver::mode_(int m, const int *a) { + if (a) { // when the mode is set using the a array of system-dependent values, and if asking for double buffer, + // the FL_DOUBLE flag must be set in the mode_ member variable + const int *aa = a; + while (*aa) { + if (*(aa++) == + kCGLPFADoubleBuffer + ) { m |= FL_DOUBLE; break; } + } + } + pWindow->context(0); + mode( m); alist(a); + if (pWindow->shown()) { + g( find(m, a) ); + pWindow->redraw(); + } else { + g(0); + } + return 1; +} + +void Fl_Cocoa_Gl_Window_Driver::make_current_before() { + // detect if the window was moved between low and high resolution displays + Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(pWindow); + if (d->changed_resolution()){ + d->changed_resolution(false); + pWindow->invalidate(); + [(NSOpenGLContext*)pWindow->context() update]; + } +} + +void Fl_Cocoa_Gl_Window_Driver::swap_buffers() { + if (overlay() != NULL) { + // STR# 2944 [1] + // Save matrixmode/proj/modelview/rasterpos before doing overlay. + // + int wo = pWindow->pixel_w(), ho = pWindow->pixel_h(); + GLint matrixmode; + GLfloat pos[4]; + glGetIntegerv(GL_MATRIX_MODE, &matrixmode); + glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); // save original glRasterPos + glMatrixMode(GL_PROJECTION); // save proj/model matrices + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glScalef(2.0f/wo, 2.0f/ho, 1.0f); + glTranslatef(-wo/2.0f, -ho/2.0f, 0.0f); // set transform so 0,0 is bottom/left of Gl_Window + glRasterPos2i(0,0); // set glRasterPos to bottom left corner + { + // Emulate overlay by doing copypixels + glReadBuffer(GL_BACK); + glDrawBuffer(GL_FRONT); + glCopyPixels(0, 0, wo, ho, GL_COLOR); // copy GL_BACK to GL_FRONT + } + glPopMatrix(); // GL_MODELVIEW // restore model/proj matrices + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(matrixmode); + glRasterPos3f(pos[0], pos[1], pos[2]); // restore original glRasterPos + } else { + [(NSOpenGLContext*)pWindow->context() flushBuffer]; + } +} + +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(); + [(NSOpenGLContext*)pWindow->context() update]; + if (gl1ctxt) { + [[gl1ctxt view] setFrame:[[[gl1ctxt view] superview] frame]]; + [gl1ctxt update]; + Fl::add_timeout(0.01, (Fl_Timeout_Handler)delayed_redraw, pWindow); + } +} + +void Fl_Cocoa_Gl_Window_Driver::apply_scissor() { + CGRect *extents = Fl_Cocoa_Window_Driver::driver(pWindow)->subRect(); + if (extents) { + remove_gl_context_opacity((NSOpenGLContext*)pWindow->context()); + glDisable(GL_SCISSOR_TEST); + GLdouble vals[4]; + glGetDoublev(GL_COLOR_CLEAR_VALUE, vals); + glClearColor(0., 0., 0., 0.); + glClear(GL_COLOR_BUFFER_BIT); + glClearColor(vals[0], vals[1], vals[2], vals[3]); + float s = pWindow->pixels_per_unit(); + glScissor(s*extents->origin.x, s*extents->origin.y, s*extents->size.width, s*extents->size.height); +//printf("apply_scissor %dx%d %dx%d\n",extents->x, extents->y, extents->width, extents->height); + glEnable(GL_SCISSOR_TEST); + } +} + + +/* Some old Apple hardware doesn't implement the GL_EXT_texture_rectangle extension. + For it, draw_string_legacy_glut() is used to draw text. */ + +char *Fl_Cocoa_Gl_Window_Driver::alpha_mask_for_string(const char *str, int n, int w, int h, Fl_Fontsize fs) +{ + // write str to a bitmap just big enough + Fl_Image_Surface *surf = new Fl_Image_Surface(w, h); + Fl_Font f=fl_font(); + Fl_Surface_Device::push_current(surf); + fl_color(FL_WHITE); + fl_font(f, fs); + fl_draw(str, n, 0, fl_height() - fl_descent()); + // get the alpha channel only of the bitmap + char *alpha_buf = new char[w*h], *r = alpha_buf, *q; + q = (char*)CGBitmapContextGetData((CGContextRef)surf->offscreen()); + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + *r++ = *(q+3); + q += 4; + } + } + Fl_Surface_Device::pop_current(); + delete surf; + return alpha_buf; +} + +void Fl_Cocoa_Gl_Window_Driver::gl_start() { + [(NSOpenGLContext*)gl_start_context update]; +} + +// convert BGRA to RGB and also exchange top and bottom +static uchar *convert_BGRA_to_RGB(uchar *baseAddress, int w, int h, int mByteWidth) +{ + uchar *newimg = new uchar[3*w*h]; + uchar *to = newimg; + for (int i = h-1; i >= 0; i--) { + uchar *from = baseAddress + i * mByteWidth; + for (int j = 0; j < w; j++, from += 4) { +#if defined(__ppc__) && __ppc__ + memcpy(to, from + 1, 3); + to += 3; +#else + *(to++) = *(from+2); + *(to++) = *(from+1); + *(to++) = *from; +#endif + } + } + delete[] baseAddress; + return newimg; +} + +Fl_RGB_Image* Fl_Cocoa_Gl_Window_Driver::capture_gl_rectangle(int x, int y, int w, int h) +{ + Fl_Gl_Window* glw = pWindow; + float factor = glw->pixels_per_unit(); + if (factor != 1) { + w *= factor; h *= factor; x *= factor; y *= factor; + } + [(NSOpenGLContext*)glw->context() makeCurrentContext]; +// to capture also the overlay and for directGL demo + [(NSOpenGLContext*)glw->context() flushBuffer]; + // Read OpenGL context pixels directly. + // For extra safety, save & restore OpenGL states that are changed + glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); + glPixelStorei(GL_PACK_ALIGNMENT, 4); /* Force 4-byte alignment */ + glPixelStorei(GL_PACK_ROW_LENGTH, 0); + glPixelStorei(GL_PACK_SKIP_ROWS, 0); + glPixelStorei(GL_PACK_SKIP_PIXELS, 0); + // Read a block of pixels from the frame buffer + int mByteWidth = w * 4; + mByteWidth = (mByteWidth + 3) & ~3; // Align to 4 bytes + uchar *baseAddress = new uchar[mByteWidth * h]; + glReadPixels(x, glw->pixel_h() - (y+h), w, h, + GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, baseAddress); + glPopClientAttrib(); + baseAddress = convert_BGRA_to_RGB(baseAddress, w, h, mByteWidth); + Fl_RGB_Image *img = new Fl_RGB_Image(baseAddress, w, h, 3, 3 * w); + img->alloc_array = 1; + [(NSOpenGLContext*)glw->context() flushBuffer]; + return img; +} + + +void* Fl_Cocoa_Gl_Window_Driver::GetProcAddress(const char *procName) { + return dlsym(RTLD_DEFAULT, procName); +} + + +FL_EXPORT NSOpenGLContext *fl_mac_glcontext(GLContext rc) { + return (NSOpenGLContext*)rc; +} + + +/* 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 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. + */ + +static struct win_view { + Fl_Gl_Window *win; + NSView *gl1view; + NSOpenGLContext *gl1ctxt; +} win_view_struct; + + +static void delayed_addgl1ctxt(struct win_view *data) { + NSView *flview = [fl_mac_xid(data->win) contentView]; + [flview addSubview:data->gl1view]; + [data->gl1view release]; +#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_7 + if (fl_mac_os_version >= 100700 && Fl::use_high_res_GL()) { + [data->gl1view setWantsBestResolutionOpenGLSurface:YES]; + } +#endif + [data->gl1ctxt setView:data->gl1view]; + remove_gl_context_opacity(data->gl1ctxt); + data->win->redraw(); +} + + +void Fl_Cocoa_Gl_Window_Driver::switch_to_GL1() { + if (!gl1ctxt) { + NSView *view = [fl_xid(pWindow) contentView]; + win_view_struct.gl1view = [[NSView alloc] initWithFrame:[view frame]]; + NSOpenGLPixelFormat *gl1pixelformat = mode_to_NSOpenGLPixelFormat( + FL_RGB8 | FL_ALPHA | FL_SINGLE, NULL); + gl1ctxt = [[NSOpenGLContext alloc] + initWithFormat:gl1pixelformat shareContext:nil]; + [gl1pixelformat release]; + win_view_struct.win = pWindow; + win_view_struct.gl1ctxt = gl1ctxt; + Fl::add_timeout(0.01, (Fl_Timeout_Handler)delayed_addgl1ctxt, + &win_view_struct); + } + [gl1ctxt makeCurrentContext]; + glClearColor(0., 0., 0., 0.); + glClear(GL_COLOR_BUFFER_BIT); +} + + +void Fl_Cocoa_Gl_Window_Driver::switch_back() { + glFlush(); + [(NSOpenGLContext*)pWindow->context() makeCurrentContext]; +} + + +void Fl_Cocoa_Gl_Window_Driver::gl_hide_before(void *&) { + if (gl1ctxt) { + [gl1ctxt release]; + gl1ctxt = 0; + } +} + + +class Fl_Gl_Cocoa_Plugin : public Fl_Cocoa_Plugin { +public: + Fl_Gl_Cocoa_Plugin() : Fl_Cocoa_Plugin(name()) { } + virtual const char *name() { return "gl.cocoa.fltk.org"; } + virtual void resize(Fl_Gl_Window *glw, int x, int y, int w, int h) { + glw->Fl_Gl_Window::resize(x, y, w, h); + } +}; + +static Fl_Gl_Cocoa_Plugin Gl_Cocoa_Plugin; + +#endif // HAVE_GL diff --git a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H index 16cea4e67..520c4c239 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H +++ b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H @@ -146,21 +146,6 @@ public: void draw_titlebar_to_context(CGContextRef gc, int w, int h); virtual int scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, void (*draw_area)(void*, int,int,int,int), void* data); - // these functions are OpenGL-related and use objective-c - // they are put here to avoid libfltk_gl dependency in Fl_cocoa.mm - static NSOpenGLContext* create_GLcontext_for_window(NSOpenGLPixelFormat *pixelformat, NSOpenGLContext *shared_ctx, Fl_Window *window); - static NSOpenGLPixelFormat *mode_to_NSOpenGLPixelFormat(int mode, const int*); // uses Objective-c - static void GLcontext_update(NSOpenGLContext*); // uses Objective-c - static void GLcontext_release(NSOpenGLContext*); // uses Objective-c - static void flush_context(NSOpenGLContext*); // uses Objective-c - static void GLcontext_makecurrent(NSOpenGLContext*); // uses Objective-c - 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(NSView **); // uses Objective-c - void gl1ctxt_add(NSOpenGLContext*, NSView*); // uses Objective-c - static void gl1ctxt_resize(NSOpenGLContext*); // uses Objective-c - //icons virtual void icons(const Fl_RGB_Image *icons[], int count); NSImage *icon_image; -- cgit v1.2.3