diff options
28 files changed, 1264 insertions, 1299 deletions
diff --git a/CMake/options.cmake b/CMake/options.cmake index 2bb439ae6..142f345ee 100644 --- a/CMake/options.cmake +++ b/CMake/options.cmake @@ -485,6 +485,7 @@ if (X11_Xft_FOUND AND OPTION_USE_PANGO) if (APPLE AND OPTION_APPLE_X11) find_file(FINK_PREFIX NAMES /opt/sw /sw) list (APPEND CMAKE_INCLUDE_PATH ${FINK_PREFIX}/include) + include_directories (${FINK_PREFIX}/include/cairo) list (APPEND CMAKE_LIBRARY_PATH ${FINK_PREFIX}/lib) endif (APPLE AND OPTION_APPLE_X11) find_file(HAVE_PANGO_H pango-1.0/pango/pango.h ${CMAKE_INCLUDE_PATH}) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ff15cf04a..c2f606e3f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -398,6 +398,14 @@ set (GL_DRIVER_FILES drivers/OpenGL/Fl_OpenGL_Graphics_Driver_rect.cxx drivers/OpenGL/Fl_OpenGL_Graphics_Driver_vertex.cxx ) +if (USE_X11) + set (GL_DRIVER_FILES ${GL_DRIVER_FILES} drivers/X11/Fl_X11_Gl_Window_driver.cxx) +elseif (APPLE) + set (GL_DRIVER_FILES ${GL_DRIVER_FILES} drivers/Cocoa/Fl_Cocoa_Gl_Window_driver.cxx) +elseif (WIN32) + set (GL_DRIVER_FILES ${GL_DRIVER_FILES} drivers/WinAPI/Fl_WinAPI_Gl_Window_driver.cxx) +endif (USE_X11) + set (GL_DRIVER_HEADER_FILES drivers/OpenGL/Fl_OpenGL_Display_Device.H drivers/OpenGL/Fl_OpenGL_Graphics_Driver.H diff --git a/src/Fl_Gl_Choice.H b/src/Fl_Gl_Choice.H index 7c83170be..2d2f0fb76 100644 --- a/src/Fl_Gl_Choice.H +++ b/src/Fl_Gl_Choice.H @@ -40,33 +40,7 @@ #ifndef Fl_Gl_Choice_H #define Fl_Gl_Choice_H -#ifdef FL_CFG_GFX_QUARTZ -# include <OpenGL/gl.h> -# define FL_GL_CHOICE_PLATFORM_SPECIFIC_MEMBERS void* pixelformat; -#endif // FL_CFG_GFX_QUARTZ - - -#ifdef FL_CFG_GFX_XLIB -# include <GL/glx.h> -# if ! defined(GLX_VERSION_1_3) -# typedef void *GLXFBConfig; -# endif -# define FL_GL_CHOICE_PLATFORM_SPECIFIC_MEMBERS \ - XVisualInfo *vis; /* the visual to use */ \ - Colormap colormap; /* a colormap for that visual */ \ - GLXFBConfig best_fb; -#endif // FL_CFG_GFX_XLIB*/ - - -#ifdef FL_CFG_GFX_GDI -# include <FL/gl.h> -# define FL_GL_CHOICE_PLATFORM_SPECIFIC_MEMBERS \ - int pixelformat; /* the visual to use */ \ - PIXELFORMATDESCRIPTOR pfd; // some wgl calls need this thing -#endif // FL_CFG_GFX_GDI - - -// Describes crap needed to create a GLContext. +// Describes the platform-independent part of data needed to create a GLContext. class Fl_Gl_Choice { friend class Fl_Gl_Window_Driver; int mode; @@ -74,9 +48,6 @@ class Fl_Gl_Choice { Fl_Gl_Choice *next; public: Fl_Gl_Choice(int m, const int *alistp, Fl_Gl_Choice *n) : mode(m), alist(alistp), next(n) {} - FL_GL_CHOICE_PLATFORM_SPECIFIC_MEMBERS }; -#undef FL_GL_CHOICE_PLATFORM_SPECIFIC_MEMBERS - #endif // Fl_Gl_Choice_H diff --git a/src/Fl_Gl_Choice.cxx b/src/Fl_Gl_Choice.cxx index 12bf46e85..993687316 100644 --- a/src/Fl_Gl_Choice.cxx +++ b/src/Fl_Gl_Choice.cxx @@ -18,19 +18,16 @@ #if HAVE_GL # include <FL/Fl.H> -# include <stdlib.h> # include "Fl_Gl_Choice.H" # include <FL/Fl_Gl_Window.H> # include "Fl_Gl_Window_Driver.H" # include <FL/gl_draw.H> -# include "flstring.h" -# include <FL/fl_utf8.h> +GLContext *Fl_Gl_Window_Driver::context_list = 0; +int Fl_Gl_Window_Driver::nContext = 0; +static int NContext = 0; -static GLContext *context_list = 0; -static int nContext = 0, NContext = 0; - -static void add_context(GLContext ctx) { +void Fl_Gl_Window_Driver::add_context(GLContext ctx) { if (!ctx) return; if (nContext==NContext) { if (!NContext) NContext = 8; @@ -41,7 +38,7 @@ static void add_context(GLContext ctx) { context_list[nContext++] = ctx; } -static void del_context(GLContext ctx) { +void Fl_Gl_Window_Driver::del_context(GLContext ctx) { int i; for (i=0; i<nContext; i++) { if (context_list[i]==ctx) { @@ -54,7 +51,7 @@ static void del_context(GLContext ctx) { if (!nContext) gl_remove_displaylist_fonts(); } -static Fl_Gl_Choice *first; +Fl_Gl_Choice *Fl_Gl_Window_Driver::first; /** \cond DriverDev @@ -78,406 +75,4 @@ Fl_Gl_Choice *Fl_Gl_Window_Driver::find_begin(int m, const int *alistp) { \endcond */ -static GLContext cached_context; -static Fl_Window* cached_window; - - -#ifdef FL_CFG_GFX_QUARTZ -# include "drivers/Cocoa/Fl_Cocoa_Window_Driver.H" -# include "Fl_Screen_Driver.H" - -extern void gl_texture_reset(); - -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_Gl_Choice *g = 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_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((NSOpenGLPixelFormat*)g->pixelformat, shared_ctx, window); - if (!context) return 0; - add_context(context); - 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(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(context); - del_context(context); -} - -#endif // FL_CFG_GFX_QUARTZ - -#ifdef FL_CFG_GFX_GDI -# include <FL/platform.H> -# include <FL/Fl_Graphics_Driver.H> -#include "drivers/WinAPI/Fl_WinAPI_Window_Driver.H" -extern void fl_save_dc(HWND, HDC); - -// STR #3119: select pixel format with composition support -// ... and no more than 32 color bits (8 bits/color) -// Ref: PixelFormatDescriptor Object -// https://msdn.microsoft.com/en-us/library/cc231189.aspx -#if !defined(PFD_SUPPORT_COMPOSITION) -# define PFD_SUPPORT_COMPOSITION (0x8000) -#endif - -#define DEBUG_PFD (0) // 1 = PFD selection debug output, 0 = no debug output - -Fl_Gl_Choice *Fl_WinAPI_Gl_Window_Driver::find(int m, const int *alistp) -{ - Fl_Gl_Choice *g = Fl_Gl_Window_Driver::find_begin(m, alistp); - if (g) return g; - - // Replacement for ChoosePixelFormat() that finds one with an overlay if possible: - HDC gc = (HDC)(fl_graphics_driver ? fl_graphics_driver->gc() : 0); - if (!gc) gc = fl_GetDC(0); - int pixelformat = 0; - PIXELFORMATDESCRIPTOR chosen_pfd; - for (int i = 1; ; i++) { - PIXELFORMATDESCRIPTOR pfd; - if (!DescribePixelFormat(gc, i, sizeof(pfd), &pfd)) break; - // continue if it does not satisfy our requirements: - if (~pfd.dwFlags & (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL)) continue; - if (pfd.iPixelType != ((m&FL_INDEX)?PFD_TYPE_COLORINDEX:PFD_TYPE_RGBA)) continue; - if ((m & FL_ALPHA) && !pfd.cAlphaBits) continue; - if ((m & FL_ACCUM) && !pfd.cAccumBits) continue; - if ((!(m & FL_DOUBLE)) != (!(pfd.dwFlags & PFD_DOUBLEBUFFER))) continue; - if ((!(m & FL_STEREO)) != (!(pfd.dwFlags & PFD_STEREO))) continue; - if ((m & FL_DEPTH) && !pfd.cDepthBits) continue; - if ((m & FL_STENCIL) && !pfd.cStencilBits) continue; - -#if DEBUG_PFD - printf("pfd #%d supports composition: %s\n", i, (pfd.dwFlags & PFD_SUPPORT_COMPOSITION) ? "yes" : "no"); - printf(" ... & PFD_GENERIC_FORMAT: %s\n", (pfd.dwFlags & PFD_GENERIC_FORMAT) ? "generic" : "accelerated"); - printf(" ... Overlay Planes : %d\n", pfd.bReserved & 15); - printf(" ... Color & Depth : %d, %d\n", pfd.cColorBits, pfd.cDepthBits); - if (pixelformat) - printf(" current pixelformat : %d\n", pixelformat); - fflush(stdout); -#endif // DEBUG_PFD - - // see if better than the one we have already: - if (pixelformat) { - // offering non-generic rendering is better (read: hardware acceleration) - if (!(chosen_pfd.dwFlags & PFD_GENERIC_FORMAT) && - (pfd.dwFlags & PFD_GENERIC_FORMAT)) continue; - // offering overlay is better: - else if (!(chosen_pfd.bReserved & 15) && (pfd.bReserved & 15)) {} - // otherwise prefer a format that supports composition (STR #3119) - else if ((chosen_pfd.dwFlags & PFD_SUPPORT_COMPOSITION) && - !(pfd.dwFlags & PFD_SUPPORT_COMPOSITION)) continue; - // otherwise more bit planes is better, but no more than 32 (8 bits per channel): - else if (pfd.cColorBits > 32 || chosen_pfd.cColorBits > pfd.cColorBits) continue; - else if (chosen_pfd.cDepthBits > pfd.cDepthBits) continue; - } - pixelformat = i; - chosen_pfd = pfd; - } - -#if DEBUG_PFD - static int bb = 0; - if (!bb) { - bb = 1; - printf("PFD_SUPPORT_COMPOSITION = 0x%x\n", PFD_SUPPORT_COMPOSITION); - } - printf("Chosen pixel format is %d\n", pixelformat); - printf("Color bits = %d, Depth bits = %d\n", chosen_pfd.cColorBits, chosen_pfd.cDepthBits); - printf("Pixel format supports composition: %s\n", (chosen_pfd.dwFlags & PFD_SUPPORT_COMPOSITION) ? "yes" : "no"); - fflush(stdout); -#endif // DEBUG_PFD - - if (!pixelformat) return 0; - - g = new Fl_Gl_Choice(m, alistp, first); - first = g; - - g->pixelformat = pixelformat; - g->pfd = chosen_pfd; - - return g; -} - - -GLContext Fl_WinAPI_Gl_Window_Driver::create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer) -{ - Fl_X* i = Fl_X::i(window); - HDC hdc = Fl_WinAPI_Window_Driver::driver(window)->private_dc; - if (!hdc) { - hdc = Fl_WinAPI_Window_Driver::driver(window)->private_dc = GetDCEx(i->xid, 0, DCX_CACHE); - fl_save_dc(i->xid, hdc); - SetPixelFormat(hdc, g->pixelformat, (PIXELFORMATDESCRIPTOR*)(&g->pfd)); -# if USE_COLORMAP - if (fl_palette) SelectPalette(hdc, fl_palette, FALSE); -# endif - } - GLContext context = layer ? wglCreateLayerContext(hdc, layer) : wglCreateContext(hdc); - if (context) { - if (context_list && nContext) - wglShareLists(context_list[0], context); - add_context(context); - } - return context; -} - - -void Fl_WinAPI_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context) { - if (context != cached_context || w != cached_window) { - cached_context = context; - cached_window = w; - wglMakeCurrent(Fl_WinAPI_Window_Driver::driver(w)->private_dc, context); - } -} - -void Fl_WinAPI_Gl_Window_Driver::delete_gl_context(GLContext context) { - if (cached_context == context) { - cached_context = 0; - cached_window = 0; - wglMakeCurrent(0, 0); - } - wglDeleteContext(context); - del_context(context); -} - -#endif // FL_CFG_GFX_GDI - -#ifdef FL_CFG_GFX_XLIB -# include <FL/platform.H> - -static XVisualInfo *gl3_getvisual(const int *blist, GLXFBConfig *pbestFB) -{ - int glx_major, glx_minor; - - // FBConfigs were added in GLX version 1.3. - if ( !glXQueryVersion(fl_display, &glx_major, &glx_minor) || - ( ( glx_major == 1 ) && ( glx_minor < 3 ) ) || ( glx_major < 1 ) ) { - return NULL; - } - - //printf( "Getting matching framebuffer configs\n" ); - int fbcount; - GLXFBConfig* fbc = glXChooseFBConfig(fl_display, DefaultScreen(fl_display), blist, &fbcount); - if (!fbc) { - //printf( "Failed to retrieve a framebuffer config\n" ); - return NULL; - } - //printf( "Found %d matching FB configs.\n", fbcount ); - - // Pick the FB config/visual with the most samples per pixel - int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999; - for (int i = 0; i < fbcount; ++i) - { - XVisualInfo *vi = glXGetVisualFromFBConfig( fl_display, fbc[i] ); - if (vi) { - int samp_buf, samples; - glXGetFBConfigAttrib(fl_display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); - glXGetFBConfigAttrib(fl_display, fbc[i], GLX_SAMPLES , &samples ); - /*printf( " Matching fbconfig %d, visual ID 0x%2lx: SAMPLE_BUFFERS = %d, SAMPLES = %d\n", - i, vi -> visualid, samp_buf, samples );*/ - if ( best_fbc < 0 || (samp_buf && samples > best_num_samp) ) - best_fbc = i, best_num_samp = samples; - if ( worst_fbc < 0 || !samp_buf || samples < worst_num_samp ) - worst_fbc = i, worst_num_samp = samples; - } - XFree(vi); - } - - GLXFBConfig bestFbc = fbc[ best_fbc ]; - // Be sure to free the FBConfig list allocated by glXChooseFBConfig() - XFree(fbc); - // Get a visual - XVisualInfo *vi = glXGetVisualFromFBConfig(fl_display, bestFbc); - *pbestFB = bestFbc; - return vi; -} - -Fl_Gl_Choice *Fl_X11_Gl_Window_Driver::find(int m, const int *alistp) -{ - Fl_Gl_Choice *g = Fl_Gl_Window_Driver::find_begin(m, alistp); - if (g) return g; - - const int *blist; - int list[32]; - - if (alistp) - blist = alistp; - else { - int n = 0; - if (m & FL_INDEX) { - list[n++] = GLX_BUFFER_SIZE; - list[n++] = 8; // glut tries many sizes, but this should work... - } else { - list[n++] = GLX_RGBA; - list[n++] = GLX_GREEN_SIZE; - list[n++] = (m & FL_RGB8) ? 8 : 1; - if (m & FL_ALPHA) { - list[n++] = GLX_ALPHA_SIZE; - list[n++] = (m & FL_RGB8) ? 8 : 1; - } - if (m & FL_ACCUM) { - list[n++] = GLX_ACCUM_GREEN_SIZE; - list[n++] = 1; - if (m & FL_ALPHA) { - list[n++] = GLX_ACCUM_ALPHA_SIZE; - list[n++] = 1; - } - } - } - if (m & FL_DOUBLE) { - list[n++] = GLX_DOUBLEBUFFER; - } - if (m & FL_DEPTH) { - list[n++] = GLX_DEPTH_SIZE; list[n++] = 1; - } - if (m & FL_STENCIL) { - list[n++] = GLX_STENCIL_SIZE; list[n++] = 1; - } - if (m & FL_STEREO) { - list[n++] = GLX_STEREO; - } -# if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) - if (m & FL_MULTISAMPLE) { - list[n++] = GLX_SAMPLES_SGIS; - list[n++] = 4; // value Glut uses - } -# endif - list[n] = 0; - blist = list; - } - - fl_open_display(); - XVisualInfo *visp = NULL; - GLXFBConfig best_fb = NULL; - if (m & FL_OPENGL3) { - visp = gl3_getvisual((const int *)blist, &best_fb); - } - if (!visp) { - visp = glXChooseVisual(fl_display, fl_screen, (int *)blist); - if (!visp) { -# if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) - if (m&FL_MULTISAMPLE) return find(m&~FL_MULTISAMPLE, 0); -# endif - return 0; - } - } - - g = new Fl_Gl_Choice(m, alistp, first); - first = g; - - g->vis = visp; - g->best_fb = best_fb; - - if (/*MaxCmapsOfScreen(ScreenOfDisplay(fl_display,fl_screen))==1 && */ - visp->visualid == fl_visual->visualid && - !fl_getenv("MESA_PRIVATE_CMAP")) - g->colormap = fl_colormap; - else - g->colormap = XCreateColormap(fl_display, RootWindow(fl_display,fl_screen), - visp->visual, AllocNone); - return g; -} - -static bool ctxErrorOccurred = false; -static int ctxErrorHandler( Display *dpy, XErrorEvent *ev ) -{ - ctxErrorOccurred = true; - return 0; -} - -GLContext Fl_X11_Gl_Window_Driver::create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer) { - GLContext shared_ctx = 0; - if (context_list && nContext) shared_ctx = context_list[0]; - - typedef GLContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLContext, Bool, const int*); - // It is not necessary to create or make current to a context before calling glXGetProcAddressARB - static glXCreateContextAttribsARBProc glXCreateContextAttribsARB = -#if defined(HAVE_GLXGETPROCADDRESSARB) - (glXCreateContextAttribsARBProc)glXGetProcAddressARB((const GLubyte *)"glXCreateContextAttribsARB"); -#else - NULL; -#endif - - GLContext ctx = 0; - // Check for the GLX_ARB_create_context extension string and the function. - // If either is not present, use GLX 1.3 context creation method. - const char *glxExts = glXQueryExtensionsString(fl_display, fl_screen); - if (g->best_fb && strstr(glxExts, "GLX_ARB_create_context") && glXCreateContextAttribsARB ) { - int context_attribs[] = - { - GLX_CONTEXT_MAJOR_VERSION_ARB, 3, - GLX_CONTEXT_MINOR_VERSION_ARB, 2, - //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, - //GLX_CONTEXT_PROFILE_MASK_ARB , GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - None - }; - ctxErrorOccurred = false; - XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler); - ctx = glXCreateContextAttribsARB(fl_display, g->best_fb, shared_ctx, true, context_attribs); - XSync(fl_display, false); // Sync to ensure any errors generated are processed. - if (ctxErrorOccurred) ctx = 0; - XSetErrorHandler(oldHandler); - } - if (!ctx) { // use OpenGL 1-style context creation - ctx = glXCreateContext(fl_display, g->vis, shared_ctx, true); - } - if (ctx) - add_context(ctx); -//glXMakeCurrent(fl_display, fl_xid(window), ctx);printf("%s\n", glGetString(GL_VERSION)); - return ctx; -} - -GLContext Fl_X11_Gl_Window_Driver::create_gl_context(XVisualInfo *vis) { - GLContext shared_ctx = 0; - if (context_list && nContext) shared_ctx = context_list[0]; - GLContext context = glXCreateContext(fl_display, vis, shared_ctx, 1); - if (context) - add_context(context); - return context; -} - -void Fl_X11_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context) { - if (context != cached_context || w != cached_window) { - cached_context = context; - cached_window = w; - glXMakeCurrent(fl_display, fl_xid(w), context); - } -} - -void Fl_X11_Gl_Window_Driver::delete_gl_context(GLContext context) { - if (cached_context == context) { - cached_context = 0; - cached_window = 0; - glXMakeCurrent(fl_display, 0, 0); - } - glXDestroyContext(fl_display, context); - del_context(context); -} - -#endif // FL_CFG_GFX_XLIB - #endif // HAVE_GL diff --git a/src/Fl_Gl_Overlay.cxx b/src/Fl_Gl_Overlay.cxx index b03e13953..04c906adc 100644 --- a/src/Fl_Gl_Overlay.cxx +++ b/src/Fl_Gl_Overlay.cxx @@ -76,227 +76,4 @@ void Fl_Gl_Window::hide_overlay() { pGlWindowDriver->hide_overlay(); } - -// Methods on Fl_Gl_Window that create an overlay window. Because -// many programs don't need the overlay, this is separated into this -// source file so it is not linked in if not used. - -// Under X this is done by creating another window, of class _Fl_Gl_Overlay -// which is a subclass of Fl_Gl_Window except it uses the overlay planes. -// A pointer to this is stored in the "overlay" pointer of the Fl_Gl_Window. - -// Under win32 another GLX context is created to draw into the overlay -// and it is stored in the "overlay" pointer. - -// In both cases if overlay hardware is unavailable, the overlay is -// "faked" by drawing into the main layers. This is indicated by -// setting overlay == this. - -#ifdef FL_CFG_GFX_QUARTZ - -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(); -} - -#endif // FL_CFG_GFX_QUARTZ - - -#ifdef FL_CFG_GFX_XLIB -#include <FL/platform.H> -//////////////////////////////////////////////////////////////// -// X version - -void Fl_X11_Gl_Window_Driver::make_overlay_current() { -#if HAVE_GL_OVERLAY - if (overlay() != pWindow) { - ((Fl_Gl_Window*)overlay())->make_current(); - } else -#endif - glDrawBuffer(GL_FRONT); -} - -void Fl_X11_Gl_Window_Driver::redraw_overlay() { - if (overlay() != pWindow) - ((Fl_Gl_Window*)overlay())->redraw(); - else - pWindow->damage(FL_DAMAGE_OVERLAY); -} - -#if HAVE_GL_OVERLAY - -extern XVisualInfo *fl_find_overlay_visual(); -extern XVisualInfo *fl_overlay_visual; -extern Colormap fl_overlay_colormap; -extern unsigned long fl_transparent_pixel; -extern uchar fl_overlay; - -class _Fl_Gl_Overlay : public Fl_Gl_Window { - void flush(); - void draw(); -public: - void show(); - _Fl_Gl_Overlay(int x, int y, int w, int h) : - Fl_Gl_Window(x,y,w,h) { - set_flag(INACTIVE); - } -}; - -void _Fl_Gl_Overlay::flush() { - make_current(); -#ifdef BOXX_BUGS - // The BoXX overlay is broken and you must not call swap-buffers. This - // code will make it work, but we lose because machines that do support - // double-buffered overlays will blink when they don't have to - glDrawBuffer(GL_FRONT); - draw(); -#else - draw(); - swap_buffers(); -#endif - glFlush(); - valid(1); -} - -void _Fl_Gl_Overlay::draw() { - if (!valid()) glClearIndex((GLfloat)fl_transparent_pixel); - if (damage() != FL_DAMAGE_EXPOSE) glClear(GL_COLOR_BUFFER_BIT); - Fl_Gl_Window *w = (Fl_Gl_Window *)parent(); - uchar save_valid = w->valid(); - w->valid(valid()); - fl_overlay = 1; - w->gl_driver()->draw_overlay(); - fl_overlay = 0; - valid(w->valid()); - w->valid(save_valid); -} - -void _Fl_Gl_Overlay::show() { - if (!shown()) { - fl_background_pixel = int(fl_transparent_pixel); - Fl_X::make_xid(this, fl_overlay_visual, fl_overlay_colormap); - fl_background_pixel = -1; - // find the outermost window to tell wm about the colormap: - Fl_Window *w = window(); - for (;;) {Fl_Window *w1 = w->window(); if (!w1) break; w = w1;} - XSetWMColormapWindows(fl_display, fl_xid(w), &(Fl_X::i(this)->xid), 1); - context(Fl_X11_Gl_Window_Driver::create_gl_context(fl_overlay_visual), 1); - valid(0); - } - Fl_Gl_Window::show(); -} - -void Fl_X11_Gl_Window_Driver::hide_overlay() { - if (overlay() && overlay() != pWindow) ((Fl_Gl_Window*)overlay())->hide(); -} - -int Fl_X11_Gl_Window_Driver::can_do_overlay() { - return fl_find_overlay_visual() != 0; -} - - -void Fl_X11_Gl_Window_Driver::make_overlay(void *¤t) { - if (current) return; - if (can_do_overlay()) { - _Fl_Gl_Overlay* o = new _Fl_Gl_Overlay(0, 0, pWindow->w(), pWindow->h()); - current = o; - pWindow->add(*o); - o->show(); - } else { - current = pWindow; // fake the overlay - } -} -#endif // HAVE_GL_OVERLAY - -#endif // FL_CFG_GFX_XLIB - - -#ifdef FL_CFG_GFX_GDI -#include "drivers/WinAPI/Fl_WinAPI_Window_Driver.H" - -//////////////////////////////////////////////////////////////// -// Windows version: - -#if HAVE_GL_OVERLAY -void Fl_WinAPI_Gl_Window_Driver::gl_hide_before(void *& overlay) { - if (overlay && overlay != pWindow) { - delete_gl_context((GLContext)overlay); - overlay = 0; - } -} -#endif - - -void Fl_WinAPI_Gl_Window_Driver::make_overlay_current() { -#if HAVE_GL_OVERLAY - if (overlay() != this) { - set_gl_context(pWindow, (GLContext)overlay()); - // if (fl_overlay_depth) - // wglRealizeLayerPalette(Fl_X::i(this)->private_dc, 1, TRUE); - } else -#endif - glDrawBuffer(GL_FRONT); -} - -void Fl_WinAPI_Gl_Window_Driver::redraw_overlay() { - pWindow->damage(FL_DAMAGE_OVERLAY); -} - -#if HAVE_GL_OVERLAY -# include "Fl_Gl_Choice.H" - -//static COLORREF *palette; -extern int fl_overlay_depth; - -void Fl_WinAPI_Gl_Window_Driver::make_overlay(void*&overlay) { - if (overlay) return; - - GLContext context = create_gl_context(pWindow, g(), 1); - if (!context) {overlay = pWindow; return;} // fake the overlay - - HDC hdc = Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc; - overlay = context; - LAYERPLANEDESCRIPTOR pfd; - wglDescribeLayerPlane(hdc, g()->pixelformat, 1, sizeof(pfd), &pfd); - if (!pfd.iPixelType) { - ; // full-color overlay - } else { - fl_overlay_depth = pfd.cColorBits; // used by gl_color() - if (fl_overlay_depth > 8) fl_overlay_depth = 8; - COLORREF palette[256]; - int n = (1<<fl_overlay_depth)-1; - // copy all colors except #0 into the overlay palette: - for (int i = 0; i <= n; i++) { - uchar r,g,b; Fl::get_color((Fl_Color)i,r,g,b); - palette[i] = RGB(r,g,b); - } - // always provide black & white in the last 2 pixels: - if (fl_overlay_depth < 8) { - palette[n-1] = RGB(0,0,0); - palette[n] = RGB(255,255,255); - } - // and use it: - wglSetLayerPaletteEntries(hdc, 1, 1, n, palette+1); - wglRealizeLayerPalette(hdc, 1, TRUE); - } - pWindow->valid(0); - return; -} - -int Fl_WinAPI_Gl_Window_Driver::can_do_overlay() { - if (!g()) { - g( find(mode(), alist()) ); - if (!g()) return 0; - } - return (g()->pfd.bReserved & 15) != 0; -} -#endif // HAVE_GL_OVERLAY - -#endif // FL_CFG_GFX_GDI - #endif // HAVE_GL diff --git a/src/Fl_Gl_Window.cxx b/src/Fl_Gl_Window.cxx index bc0d0d9e8..fb4376a2e 100644 --- a/src/Fl_Gl_Window.cxx +++ b/src/Fl_Gl_Window.cxx @@ -64,6 +64,11 @@ static char SWAP_TYPE = 0 ; // 0 = determine it from environment variable //////////////////////////////////////////////////////////////// +int Fl_Gl_Window_Driver::copy = COPY; +GLContext Fl_Gl_Window_Driver::cached_context = NULL; +Fl_Window* Fl_Gl_Window_Driver::cached_window = NULL; +float Fl_Gl_Window_Driver::gl_scale = 1; // scaling factor between FLTK and GL drawing units: GL = FLTK * gl_scale + /** Returns non-zero if the hardware supports the given or current OpenGL mode. */ int Fl_Gl_Window::can_do(int a, const int *b) { return Fl_Gl_Window_Driver::global()->find(a,b) != 0; @@ -501,266 +506,6 @@ Fl_Font_Descriptor** Fl_Gl_Window_Driver::fontnum_to_fontdescriptor(int fnum) { return &(fl_fonts[fnum].first); } -#ifdef FL_CFG_GFX_QUARTZ -#include <FL/platform.H> -#include <OpenGL/OpenGL.h> -#include "drivers/Cocoa/Fl_Cocoa_Window_Driver.H" - -Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w) -{ - return new Fl_Cocoa_Gl_Window_Driver(w); -} - -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(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(pWindow->context());//aglSwapBuffers((AGLContext)context_); -} - -char Fl_Cocoa_Gl_Window_Driver::swap_type() {return COPY;} - -void Fl_Cocoa_Gl_Window_Driver::resize(int is_a_resize, int w, int h) { - Fl_Cocoa_Window_Driver::GLcontext_update(pWindow->context()); -} - -#endif // FL_CFG_GFX_QUARTZ - -#if defined(FL_CFG_GFX_GDI) -#include "drivers/WinAPI/Fl_WinAPI_Window_Driver.H" -#include <FL/platform.H> -#include <FL/Fl_Graphics_Driver.H> -#include "Fl_Screen_Driver.H" - -Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w) -{ - return new Fl_WinAPI_Gl_Window_Driver(w); -} - -float Fl_WinAPI_Gl_Window_Driver::pixels_per_unit() -{ - int ns = Fl_Window_Driver::driver(pWindow)->screen_num(); - return Fl::screen_driver()->scale(ns); -} - - -int Fl_WinAPI_Gl_Window_Driver::mode_(int m, const int *a) { - int oldmode = mode(); - pWindow->context(0); - mode( m); alist(a); - if (pWindow->shown()) { - g( find(m, a) ); - if (!g() || (oldmode^m)&(FL_DOUBLE|FL_STEREO)) { - pWindow->hide(); - pWindow->show(); - } - } else { - g(0); - } - return 1; -} - -void Fl_WinAPI_Gl_Window_Driver::make_current_after() { -#if USE_COLORMAP - if (fl_palette) { - fl_GetDC(fl_xid(pWindow)); - SelectPalette((HDC)fl_graphics_driver->gc(), fl_palette, FALSE); - RealizePalette((HDC)fl_graphics_driver->gc()); - } -#endif // USE_COLORMAP -} - -//#define HAVE_GL_OVERLAY 1 //test only - -void Fl_WinAPI_Gl_Window_Driver::swap_buffers() { -# if HAVE_GL_OVERLAY - // Do not swap the overlay, to match GLX: - BOOL ret = wglSwapLayerBuffers(Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc, WGL_SWAP_MAIN_PLANE); - DWORD err = GetLastError(); -# else - SwapBuffers(Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc); -# endif -} - -#if HAVE_GL_OVERLAY -uchar fl_overlay; // changes how fl_color() works -int fl_overlay_depth = 0; -#endif - -int Fl_WinAPI_Gl_Window_Driver::flush_begin(char& valid_f_) { -#if HAVE_GL_OVERLAY - char save_valid_f = valid_f_; - // Draw into hardware overlay planes if they are damaged: - if (overlay() && overlay() != pWindow - && (pWindow->damage()&(FL_DAMAGE_OVERLAY|FL_DAMAGE_EXPOSE) || !save_valid_f & 1)) { - set_gl_context(pWindow, (GLContext)overlay()); - if (fl_overlay_depth) - wglRealizeLayerPalette(Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc, 1, TRUE); - glDisable(GL_SCISSOR_TEST); - glClear(GL_COLOR_BUFFER_BIT); - fl_overlay = 1; - draw_overlay(); - fl_overlay = 0; - valid_f_ = save_valid_f; - wglSwapLayerBuffers(Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc, WGL_SWAP_OVERLAY1); - // if only the overlay was damaged we are done, leave main layer alone: - if (pWindow->damage() == FL_DAMAGE_OVERLAY) { - return 1; - } - } -#endif - return 0; -} - -void* Fl_WinAPI_Gl_Window_Driver::GetProcAddress(const char *procName) { - return (void*)wglGetProcAddress((LPCSTR)procName); -} - -#endif // FL_CFG_GFX_GDI - - -#if defined(FL_CFG_GFX_XLIB) -#include <FL/platform.H> -#include "Fl_Gl_Choice.H" -#include "Fl_Screen_Driver.H" -#include "Fl_Window_Driver.H" - -Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w) -{ - return new Fl_X11_Gl_Window_Driver(w); -} - -void Fl_X11_Gl_Window_Driver::before_show(int&) { - Fl_X::make_xid(pWindow, g()->vis, g()->colormap); - if (overlay() && overlay() != pWindow) ((Fl_Gl_Window*)overlay())->show(); -} - -float Fl_X11_Gl_Window_Driver::pixels_per_unit() -{ - int ns = Fl_Window_Driver::driver(pWindow)->screen_num(); - return Fl::screen_driver()->scale(ns); -} - -int Fl_X11_Gl_Window_Driver::mode_(int m, const int *a) { - int oldmode = mode(); - 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++) == - GLX_DOUBLEBUFFER - ) { m |= FL_DOUBLE; break; } - } - } - Fl_Gl_Choice* oldg = g(); - pWindow->context(0); - mode(m); alist(a); - if (pWindow->shown()) { - g( find(m, a) ); - // under X, if the visual changes we must make a new X window (yuck!): - if (!g() || g()->vis->visualid != oldg->vis->visualid || (oldmode^m)&FL_DOUBLE) { - pWindow->hide(); - pWindow->show(); - } - } else { - g(0); - } - return 1; -} - -void Fl_X11_Gl_Window_Driver::swap_buffers() { - glXSwapBuffers(fl_display, fl_xid(pWindow)); -} - -void Fl_X11_Gl_Window_Driver::resize(int is_a_resize, int W, int H) { - if (is_a_resize && !pWindow->resizable() && overlay() && overlay() != pWindow) { - ((Fl_Gl_Window*)overlay())->resize(0,0,W,H); - } -} - -char Fl_X11_Gl_Window_Driver::swap_type() {return COPY;} - -void Fl_X11_Gl_Window_Driver::waitGL() { - glXWaitGL(); -} - -#endif // FL_CFG_GFX_XLIB - /** \} \endcond diff --git a/src/Fl_Gl_Window_Driver.H b/src/Fl_Gl_Window_Driver.H index 94a54b5d0..d2670e2cc 100644 --- a/src/Fl_Gl_Window_Driver.H +++ b/src/Fl_Gl_Window_Driver.H @@ -36,6 +36,14 @@ class Fl_Gl_Window_Driver { protected: Fl_Gl_Window *pWindow; public: + static GLContext cached_context; + static Fl_Window* cached_window; + static int nContext; + static GLContext *context_list; + static Fl_Gl_Choice *first; + static int copy; + static float gl_scale; + static GLContext gl_start_context; Fl_Gl_Choice* g() {return pWindow->g;} void g(Fl_Gl_Choice *c) {pWindow->g = c;} int mode() {return pWindow->mode_;} @@ -62,6 +70,8 @@ public: virtual int flush_begin(char& valid_f) {return 0;} virtual void gl_hide_before(void *& overlay) {} // the default implementation may be enough static Fl_Gl_Choice *find_begin(int m, const int *alistp); + static void add_context(GLContext ctx); + static void del_context(GLContext ctx); // Return one of these structures for a given gl mode. // The second argument is a glX attribute list, and is used if mode is zero. // This is not supported on Win32: @@ -91,109 +101,6 @@ public: virtual Fl_Font_Descriptor** fontnum_to_fontdescriptor(int fnum); }; -#ifdef FL_CFG_GFX_QUARTZ -#ifdef __OBJC__ -@class NSOpenGLPixelFormat; -#else -class NSOpenGLPixelFormat; -#endif // __OBJC__ - -class Fl_Cocoa_Gl_Window_Driver : public Fl_Gl_Window_Driver { - friend class Fl_Gl_Window_Driver; - friend class Fl_OpenGL_Display_Device; - Fl_Cocoa_Gl_Window_Driver(Fl_Gl_Window *win) : Fl_Gl_Window_Driver(win) {} - virtual float pixels_per_unit(); - virtual void before_show(int& need_after); - virtual void after_show(); - virtual int mode_(int m, const int *a); - virtual void make_current_before(); - virtual void swap_buffers(); - virtual void resize(int is_a_resize, int w, int h); - virtual char swap_type(); - virtual Fl_Gl_Choice *find(int m, const int *alistp); - virtual GLContext create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer = 0); - virtual void set_gl_context(Fl_Window* w, GLContext context); - virtual void delete_gl_context(GLContext); - virtual void make_overlay_current(); - virtual void redraw_overlay(); - virtual void gl_start(); - virtual char *alpha_mask_for_string(const char *str, int n, int w, int h); -}; -#endif // FL_CFG_GFX_QUARTZ - - -#ifdef FL_CFG_GFX_GDI - -class Fl_WinAPI_Gl_Window_Driver : public Fl_Gl_Window_Driver { - friend class Fl_Gl_Window_Driver; - Fl_WinAPI_Gl_Window_Driver(Fl_Gl_Window *win) : Fl_Gl_Window_Driver(win) {} - virtual float pixels_per_unit(); - virtual int mode_(int m, const int *a); - virtual void make_current_after(); - virtual void swap_buffers(); - virtual void invalidate() {} - virtual int flush_begin(char& valid_f); - virtual Fl_Gl_Choice *find(int m, const int *alistp); - virtual GLContext create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer = 0); - virtual void set_gl_context(Fl_Window* w, GLContext context); - virtual void delete_gl_context(GLContext); - virtual void make_overlay_current(); - virtual void redraw_overlay(); - virtual void* GetProcAddress(const char *procName); - virtual void draw_string_legacy(const char* str, int n); - virtual void gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize); - virtual void get_list(Fl_Font_Descriptor *fd, int r); - virtual int genlistsize(); -#if HAVE_GL_OVERLAY - virtual void gl_hide_before(void *& overlay); - virtual int can_do_overlay(); - virtual int overlay_color(Fl_Color i); - void make_overlay(void*&overlay); -#endif -}; - -#endif // FL_CFG_GFX_GDI - - -#ifdef FL_CFG_GFX_XLIB -#include <X11/Xutil.h> // for XVisualInfo -class Fl_X11_Gl_Window_Driver : public Fl_Gl_Window_Driver { - friend class Fl_Gl_Window_Driver; - Fl_X11_Gl_Window_Driver(Fl_Gl_Window *win) : Fl_Gl_Window_Driver(win) {} - virtual float pixels_per_unit(); - virtual void before_show(int& need_after); - virtual int mode_(int m, const int *a); - virtual void swap_buffers(); - virtual void resize(int is_a_resize, int w, int h); - virtual char swap_type(); - virtual Fl_Gl_Choice *find(int m, const int *alistp); - virtual GLContext create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer = 0); - virtual void set_gl_context(Fl_Window* w, GLContext context); - virtual void delete_gl_context(GLContext); -#if HAVE_GL_OVERLAY - virtual void make_overlay(void *&o); - virtual int can_do_overlay(); - virtual void hide_overlay(); - virtual int overlay_color(Fl_Color i); -#endif - virtual void make_overlay_current(); - virtual void redraw_overlay(); - virtual void waitGL(); - virtual void gl_visual(Fl_Gl_Choice*); // support for Fl::gl_visual() - virtual void gl_start(); - virtual void draw_string_legacy(const char* str, int n); - virtual void gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize); - virtual void get_list(Fl_Font_Descriptor *fd, int r); - virtual int genlistsize(); -#if !USE_XFT - virtual Fl_Font_Descriptor** fontnum_to_fontdescriptor(int fnum); -#endif - public: - static GLContext create_gl_context(XVisualInfo* vis); -}; - -#endif // FL_CFG_GFX_XLIB - #endif /* Fl_Gl_Window_Driver_H */ /** diff --git a/src/Makefile b/src/Makefile index c2577c0d7..00e02c0a8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -198,6 +198,13 @@ 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_X11 = drivers/X11/Fl_X11_Gl_Window_Driver.cxx +GLCPPFILES_XFT = $(GLCPPFILES_X11) +GLCPPFILES_WIN = drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.cxx + +GLCPPFILES += $(GLCPPFILES_$(BUILD)) + # the following file currently doesn't contribute code to GLCPPFILES # drivers/OpenGL/Fl_OpenGL_Graphics_Driver.cxx diff --git a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx new file mode 100644 index 000000000..188f4febf --- /dev/null +++ b/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx @@ -0,0 +1,248 @@ +// +// Class Fl_Cocoa_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). +// +// Copyright 2021 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 <config.h> +#if HAVE_GL +#include <FL/platform.H> +#include <FL/gl.h> +#include "../../Fl_Gl_Choice.H" +#include "../../Fl_Screen_Driver.H" +#include "Fl_Cocoa_Window_Driver.H" +#include "../../Fl_Gl_Window_Driver.H" +#include <FL/Fl_Graphics_Driver.H> +#include <OpenGL/OpenGL.h> +#include <FL/Fl_Image_Surface.H> + +extern void gl_texture_reset(); + +#ifdef __OBJC__ +@class NSOpenGLPixelFormat; +#else +class NSOpenGLPixelFormat; +#endif // __OBJC__ + +class Fl_Cocoa_Gl_Window_Driver : public Fl_Gl_Window_Driver { + friend class Fl_Gl_Window_Driver; + friend class Fl_OpenGL_Display_Device; + Fl_Cocoa_Gl_Window_Driver(Fl_Gl_Window *win) : Fl_Gl_Window_Driver(win) {} + virtual float pixels_per_unit(); + virtual void before_show(int& need_after); + virtual void after_show(); + virtual int mode_(int m, const int *a); + virtual void make_current_before(); + virtual void swap_buffers(); + virtual void resize(int is_a_resize, int w, int h); + virtual char swap_type(); + virtual Fl_Gl_Choice *find(int m, const int *alistp); + virtual GLContext create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer = 0); + virtual void set_gl_context(Fl_Window* w, GLContext context); + virtual void delete_gl_context(GLContext); + virtual void make_overlay_current(); + virtual void redraw_overlay(); + virtual void gl_start(); + virtual char *alpha_mask_for_string(const char *str, int n, int w, int h); +}; + +// 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_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, shared_ctx, window); + if (!context) return 0; + add_context(context); + 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(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(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(); +} + + +Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w) +{ + return new Fl_Cocoa_Gl_Window_Driver(w); +} + +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(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(pWindow->context());//aglSwapBuffers((AGLContext)context_); +} + +char Fl_Cocoa_Gl_Window_Driver::swap_type() {return copy;} + +void Fl_Cocoa_Gl_Window_Driver::resize(int is_a_resize, int w, int h) { + Fl_Cocoa_Window_Driver::GLcontext_update(pWindow->context()); +} + +/* 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) +{ + // write str to a bitmap just big enough + Fl_Image_Surface *surf = new Fl_Image_Surface(w, h); + Fl_Font f=fl_font(); Fl_Fontsize s=fl_size(); + Fl_Surface_Device::push_current(surf); + fl_color(FL_WHITE); + fl_font(f, s * gl_scale); + 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(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(gl_start_context); +} + +#endif // HAVE_GL diff --git a/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx b/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx index 9cb5a425c..f4358949a 100644 --- a/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx +++ b/src/drivers/GDI/Fl_GDI_Copy_Surface_Driver.cxx @@ -16,7 +16,6 @@ #include "../../config_lib.h" -#ifdef FL_CFG_GFX_GDI #include <FL/Fl_Copy_Surface.H> #include <FL/platform.H> #include "Fl_GDI_Graphics_Driver.H" @@ -113,4 +112,3 @@ void Fl_GDI_Copy_Surface_Driver::translate(int x, int y) { void Fl_GDI_Copy_Surface_Driver::untranslate() { ((Fl_GDI_Graphics_Driver*)driver())->untranslate_all(); } -#endif // FL_CFG_GFX_GDI diff --git a/src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.cxx b/src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.cxx index 4a913abfc..0933a4aa0 100644 --- a/src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.cxx +++ b/src/drivers/Quartz/Fl_Quartz_Copy_Surface_Driver.cxx @@ -14,9 +14,6 @@ // https://www.fltk.org/bugs.php // -#include "../../config_lib.h" - -#ifdef FL_CFG_GFX_QUARTZ #include <FL/Fl_Copy_Surface.H> #include <FL/platform.H> #include "Fl_Quartz_Graphics_Driver.H" @@ -86,5 +83,3 @@ void Fl_Quartz_Copy_Surface_Driver::translate(int x, int y) { void Fl_Quartz_Copy_Surface_Driver::untranslate() { CGContextRestoreGState(gc); } - -#endif // FL_CFG_GFX_QUARTZ diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_arci.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_arci.cxx index 2cc7a12e6..4163de685 100644 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_arci.cxx +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_arci.cxx @@ -14,9 +14,6 @@ // https://www.fltk.org/bugs.php // -#include "../../config_lib.h" -#ifdef FL_CFG_GFX_QUARTZ - #include "Fl_Quartz_Graphics_Driver.H" #include <FL/platform.H> @@ -66,5 +63,3 @@ void Fl_Quartz_Graphics_Driver::pie(int x,int y,int w,int h,double a1,double a2) CGContextFillPath(gc_); CGContextSetShouldAntialias(gc_, false); } - -#endif // FL_CFG_GFX_QUARTZ diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_color.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_color.cxx index cd03a8c04..f11c2955d 100644 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_color.cxx +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_color.cxx @@ -14,9 +14,6 @@ // https://www.fltk.org/bugs.php // -#include "../../config_lib.h" -#ifdef FL_CFG_GFX_QUARTZ - // The fltk "colormap". This allows ui colors to be stored in 8-bit // locations, and provides a level of indirection so that global color // changes can be made. Not to be confused with the X colormap, which @@ -75,5 +72,3 @@ void Fl_Quartz_Graphics_Driver::set_color(Fl_Color i, unsigned c) { fl_cmap[i] = c; } } - -#endif // FL_CFG_GFX_QUARTZ diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx index fe43f0c6c..335e02826 100644 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_font.cxx @@ -69,10 +69,6 @@ */ - -#include "../../config_lib.h" -#ifdef FL_CFG_GFX_QUARTZ - #include "Fl_Quartz_Graphics_Driver.H" #include "Fl_Font.H" #include <math.h> @@ -878,5 +874,3 @@ Fl_Font Fl_Quartz_Graphics_Driver::ADD_SUFFIX(set_fonts, _ATSU)(const char* xsta } #endif // HAS_ATSU - -#endif // FL_CFG_GFX_QUARTZ diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_line_style.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_line_style.cxx index 8dfa3090c..8e17f87c5 100644 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_line_style.cxx +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_line_style.cxx @@ -14,9 +14,6 @@ // https://www.fltk.org/bugs.php // -#include "../../config_lib.h" -#ifdef FL_CFG_GFX_QUARTZ - #include <FL/fl_draw.H> #include <FL/platform.H> @@ -84,5 +81,3 @@ void Fl_Quartz_Graphics_Driver::line_style(int style, int width, char* dashes) { } quartz_restore_line_style(); } - -#endif // FL_CFG_GFX_QUARTZ diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx index caf4277c4..b238e9a9b 100644 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx @@ -15,9 +15,6 @@ // -#include "../../config_lib.h" -#ifdef FL_CFG_GFX_QUARTZ - #include <FL/Fl.H> #include <FL/platform.H> @@ -297,6 +294,3 @@ void Fl_Quartz_Graphics_Driver::restore_clip() { } } } - - -#endif // FL_CFG_GFX_QUARTZ diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_vertex.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_vertex.cxx index 5ee8f924f..3b0b3f058 100644 --- a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_vertex.cxx +++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_vertex.cxx @@ -14,9 +14,6 @@ // https://www.fltk.org/bugs.php // -#include "../../config_lib.h" -#ifdef FL_CFG_GFX_QUARTZ - /** \file quartz_vertex.cxx \brief Portable drawing code for drawing arbitrary shapes with @@ -148,6 +145,3 @@ void Fl_Quartz_Graphics_Driver::transformed_vertex0(float x, float y) { void Fl_Quartz_Graphics_Driver::fixloop() { // remove equal points from closed path while (n>2 && p[n-1].x == p[0].x && p[n-1].y == p[0].y) n--; } - - -#endif // FL_CFG_GFX_QUARTZ diff --git a/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.cxx b/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.cxx index e0146c8b7..388d2d246 100644 --- a/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.cxx +++ b/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.cxx @@ -14,9 +14,6 @@ // https://www.fltk.org/bugs.php // -#include "../../config_lib.h" - -#ifdef FL_CFG_GFX_QUARTZ #include <FL/platform.H> #include <FL/fl_draw.H> #include <FL/Fl_Image_Surface.H> @@ -137,5 +134,3 @@ void Fl_Quartz_Image_Surface_Driver::end_current() fl_window = pre_window; Fl_Surface_Device::end_current(); } - -#endif // FL_CFG_GFX_QUARTZ diff --git a/src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.cxx new file mode 100644 index 000000000..1dbc9f77d --- /dev/null +++ b/src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.cxx @@ -0,0 +1,404 @@ +// +// Class Fl_WinAPI_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). +// +// Copyright 2021 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 <config.h> +#if HAVE_GL +#include <FL/platform.H> +#include "../../Fl_Screen_Driver.H" +#include <FL/gl.h> +#include "../../Fl_Gl_Window_Driver.H" +#include "../../Fl_Gl_Choice.H" +#include "Fl_WinAPI_Window_Driver.H" +#include "../GDI/Fl_Font.H" +extern void fl_save_dc(HWND, HDC); + +// STR #3119: select pixel format with composition support +// ... and no more than 32 color bits (8 bits/color) +// Ref: PixelFormatDescriptor Object +// https://msdn.microsoft.com/en-us/library/cc231189.aspx +#if !defined(PFD_SUPPORT_COMPOSITION) +# define PFD_SUPPORT_COMPOSITION (0x8000) +#endif + +#define DEBUG_PFD (0) // 1 = PFD selection debug output, 0 = no debug output + + +class Fl_WinAPI_Gl_Window_Driver : public Fl_Gl_Window_Driver { + friend class Fl_Gl_Window_Driver; + Fl_WinAPI_Gl_Window_Driver(Fl_Gl_Window *win) : Fl_Gl_Window_Driver(win) {} + virtual float pixels_per_unit(); + virtual int mode_(int m, const int *a); + virtual void make_current_after(); + virtual void swap_buffers(); + virtual void invalidate() {} + virtual int flush_begin(char& valid_f); + virtual Fl_Gl_Choice *find(int m, const int *alistp); + virtual GLContext create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer = 0); + virtual void set_gl_context(Fl_Window* w, GLContext context); + virtual void delete_gl_context(GLContext); + virtual void make_overlay_current(); + virtual void redraw_overlay(); + virtual void* GetProcAddress(const char *procName); + virtual void draw_string_legacy(const char* str, int n); + virtual void gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize); + virtual void get_list(Fl_Font_Descriptor *fd, int r); + virtual int genlistsize(); +#if HAVE_GL_OVERLAY + virtual void gl_hide_before(void *& overlay); + virtual int can_do_overlay(); + virtual int overlay_color(Fl_Color i); + void make_overlay(void*&overlay); +#endif +}; + +// Describes crap needed to create a GLContext. +class Fl_WinAPI_Gl_Choice : public Fl_Gl_Choice { + friend class Fl_WinAPI_Gl_Window_Driver; +private: + int pixelformat; // the visual to use + PIXELFORMATDESCRIPTOR pfd; // some wgl calls need this thing +public: + Fl_WinAPI_Gl_Choice(int m, const int *alistp, Fl_Gl_Choice *n) : Fl_Gl_Choice(m, alistp, n) { + pixelformat = 0; + } +}; + + +Fl_Gl_Choice *Fl_WinAPI_Gl_Window_Driver::find(int m, const int *alistp) +{ + Fl_WinAPI_Gl_Choice *g = (Fl_WinAPI_Gl_Choice*)Fl_Gl_Window_Driver::find_begin(m, alistp); + if (g) return g; + + // Replacement for ChoosePixelFormat() that finds one with an overlay if possible: + HDC gc = (HDC)(fl_graphics_driver ? fl_graphics_driver->gc() : 0); + if (!gc) gc = fl_GetDC(0); + int pixelformat = 0; + PIXELFORMATDESCRIPTOR chosen_pfd; + for (int i = 1; ; i++) { + PIXELFORMATDESCRIPTOR pfd; + if (!DescribePixelFormat(gc, i, sizeof(pfd), &pfd)) break; + // continue if it does not satisfy our requirements: + if (~pfd.dwFlags & (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL)) continue; + if (pfd.iPixelType != ((m&FL_INDEX)?PFD_TYPE_COLORINDEX:PFD_TYPE_RGBA)) continue; + if ((m & FL_ALPHA) && !pfd.cAlphaBits) continue; + if ((m & FL_ACCUM) && !pfd.cAccumBits) continue; + if ((!(m & FL_DOUBLE)) != (!(pfd.dwFlags & PFD_DOUBLEBUFFER))) continue; + if ((!(m & FL_STEREO)) != (!(pfd.dwFlags & PFD_STEREO))) continue; + if ((m & FL_DEPTH) && !pfd.cDepthBits) continue; + if ((m & FL_STENCIL) && !pfd.cStencilBits) continue; + +#if DEBUG_PFD + printf("pfd #%d supports composition: %s\n", i, (pfd.dwFlags & PFD_SUPPORT_COMPOSITION) ? "yes" : "no"); + printf(" ... & PFD_GENERIC_FORMAT: %s\n", (pfd.dwFlags & PFD_GENERIC_FORMAT) ? "generic" : "accelerated"); + printf(" ... Overlay Planes : %d\n", pfd.bReserved & 15); + printf(" ... Color & Depth : %d, %d\n", pfd.cColorBits, pfd.cDepthBits); + if (pixelformat) + printf(" current pixelformat : %d\n", pixelformat); + fflush(stdout); +#endif // DEBUG_PFD + + // see if better than the one we have already: + if (pixelformat) { + // offering non-generic rendering is better (read: hardware acceleration) + if (!(chosen_pfd.dwFlags & PFD_GENERIC_FORMAT) && + (pfd.dwFlags & PFD_GENERIC_FORMAT)) continue; + // offering overlay is better: + else if (!(chosen_pfd.bReserved & 15) && (pfd.bReserved & 15)) {} + // otherwise prefer a format that supports composition (STR #3119) + else if ((chosen_pfd.dwFlags & PFD_SUPPORT_COMPOSITION) && + !(pfd.dwFlags & PFD_SUPPORT_COMPOSITION)) continue; + // otherwise more bit planes is better, but no more than 32 (8 bits per channel): + else if (pfd.cColorBits > 32 || chosen_pfd.cColorBits > pfd.cColorBits) continue; + else if (chosen_pfd.cDepthBits > pfd.cDepthBits) continue; + } + pixelformat = i; + chosen_pfd = pfd; + } + +#if DEBUG_PFD + static int bb = 0; + if (!bb) { + bb = 1; + printf("PFD_SUPPORT_COMPOSITION = 0x%x\n", PFD_SUPPORT_COMPOSITION); + } + printf("Chosen pixel format is %d\n", pixelformat); + printf("Color bits = %d, Depth bits = %d\n", chosen_pfd.cColorBits, chosen_pfd.cDepthBits); + printf("Pixel format supports composition: %s\n", (chosen_pfd.dwFlags & PFD_SUPPORT_COMPOSITION) ? "yes" : "no"); + fflush(stdout); +#endif // DEBUG_PFD + + if (!pixelformat) return 0; + + g = new Fl_WinAPI_Gl_Choice(m, alistp, first); + first = g; + + g->pixelformat = pixelformat; + g->pfd = chosen_pfd; + + return g; +} + + +GLContext Fl_WinAPI_Gl_Window_Driver::create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer) +{ + Fl_X* i = Fl_X::i(window); + HDC hdc = Fl_WinAPI_Window_Driver::driver(window)->private_dc; + if (!hdc) { + hdc = Fl_WinAPI_Window_Driver::driver(window)->private_dc = GetDCEx(i->xid, 0, DCX_CACHE); + fl_save_dc(i->xid, hdc); + SetPixelFormat(hdc, ((Fl_WinAPI_Gl_Choice*)g)->pixelformat, (PIXELFORMATDESCRIPTOR*)(&((Fl_WinAPI_Gl_Choice*)g)->pfd)); +# if USE_COLORMAP + if (fl_palette) SelectPalette(hdc, fl_palette, FALSE); +# endif + } + GLContext context = layer ? wglCreateLayerContext(hdc, layer) : wglCreateContext(hdc); + if (context) { + if (context_list && nContext) + wglShareLists(context_list[0], context); + add_context(context); + } + return context; +} + + +void Fl_WinAPI_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context) { + if (context != cached_context || w != cached_window) { + cached_context = context; + cached_window = w; + wglMakeCurrent(Fl_WinAPI_Window_Driver::driver(w)->private_dc, context); + } +} + +void Fl_WinAPI_Gl_Window_Driver::delete_gl_context(GLContext context) { + if (cached_context == context) { + cached_context = 0; + cached_window = 0; + wglMakeCurrent(0, 0); + } + wglDeleteContext(context); + del_context(context); +} + + +void Fl_WinAPI_Gl_Window_Driver::make_overlay_current() { +#if HAVE_GL_OVERLAY + if (overlay() != this) { + set_gl_context(pWindow, (GLContext)overlay()); + // if (fl_overlay_depth) + // wglRealizeLayerPalette(Fl_X::i(this)->private_dc, 1, TRUE); + } else +#endif + glDrawBuffer(GL_FRONT); +} + +void Fl_WinAPI_Gl_Window_Driver::redraw_overlay() { + pWindow->damage(FL_DAMAGE_OVERLAY); +} + +#if HAVE_GL_OVERLAY + +// Methods on Fl_Gl_Window_driver that create an overlay window. + +// Under win32 another GLX context is created to draw into the overlay +// and it is stored in the "overlay" pointer. + +// If overlay hardware is unavailable, the overlay is +// "faked" by drawing into the main layers. This is indicated by +// setting overlay == this. + +//static COLORREF *palette; +static int fl_overlay_depth = 0; + +void Fl_WinAPI_Gl_Window_Driver::gl_hide_before(void *& overlay) { + if (overlay && overlay != pWindow) { + delete_gl_context((GLContext)overlay); + overlay = 0; + } +} + +void Fl_WinAPI_Gl_Window_Driver::make_overlay(void*&overlay) { + if (overlay) return; + + GLContext context = create_gl_context(pWindow, g(), 1); + if (!context) {overlay = pWindow; return;} // fake the overlay + + HDC hdc = Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc; + overlay = context; + LAYERPLANEDESCRIPTOR pfd; + wglDescribeLayerPlane(hdc, g()->pixelformat, 1, sizeof(pfd), &pfd); + if (!pfd.iPixelType) { + ; // full-color overlay + } else { + fl_overlay_depth = pfd.cColorBits; // used by gl_color() + if (fl_overlay_depth > 8) fl_overlay_depth = 8; + COLORREF palette[256]; + int n = (1<<fl_overlay_depth)-1; + // copy all colors except #0 into the overlay palette: + for (int i = 0; i <= n; i++) { + uchar r,g,b; Fl::get_color((Fl_Color)i,r,g,b); + palette[i] = RGB(r,g,b); + } + // always provide black & white in the last 2 pixels: + if (fl_overlay_depth < 8) { + palette[n-1] = RGB(0,0,0); + palette[n] = RGB(255,255,255); + } + // and use it: + wglSetLayerPaletteEntries(hdc, 1, 1, n, palette+1); + wglRealizeLayerPalette(hdc, 1, TRUE); + } + pWindow->valid(0); + return; +} + +int Fl_WinAPI_Gl_Window_Driver::can_do_overlay() { + if (!g()) { + g( find(mode(), alist()) ); + if (!g()) return 0; + } + return (g()->pfd.bReserved & 15) != 0; +} + +int Fl_WinAPI_Gl_Window_Driver::overlay_color(Fl_Color i) { + if (Fl_Xlib_Graphics_Driver::fl_overlay && fl_overlay_depth) { + if (fl_overlay_depth < 8) { + // only black & white produce the expected colors. This could + // be improved by fixing the colormap set in Fl_Gl_Overlay.cxx + int size = 1<<fl_overlay_depth; + if (!i) glIndexi(size-2); + else if (i >= size-2) glIndexi(size-1); + else glIndexi(i); + } else { + glIndexi(i ? i : FL_GRAY_RAMP); + } + return 1; + } + return 0; +} + +#endif // HAVE_GL_OVERLAY + + +Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w) +{ + return new Fl_WinAPI_Gl_Window_Driver(w); +} + +float Fl_WinAPI_Gl_Window_Driver::pixels_per_unit() +{ + int ns = Fl_Window_Driver::driver(pWindow)->screen_num(); + return Fl::screen_driver()->scale(ns); +} + + +int Fl_WinAPI_Gl_Window_Driver::mode_(int m, const int *a) { + int oldmode = mode(); + pWindow->context(0); + mode( m); alist(a); + if (pWindow->shown()) { + g( find(m, a) ); + if (!g() || (oldmode^m)&(FL_DOUBLE|FL_STEREO)) { + pWindow->hide(); + pWindow->show(); + } + } else { + g(0); + } + return 1; +} + +void Fl_WinAPI_Gl_Window_Driver::make_current_after() { +#if USE_COLORMAP + if (fl_palette) { + fl_GetDC(fl_xid(pWindow)); + SelectPalette((HDC)fl_graphics_driver->gc(), fl_palette, FALSE); + RealizePalette((HDC)fl_graphics_driver->gc()); + } +#endif // USE_COLORMAP +} + +//#define HAVE_GL_OVERLAY 1 //test only + +void Fl_WinAPI_Gl_Window_Driver::swap_buffers() { +# if HAVE_GL_OVERLAY + // Do not swap the overlay, to match GLX: + BOOL ret = wglSwapLayerBuffers(Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc, WGL_SWAP_MAIN_PLANE); + DWORD err = GetLastError(); +# else + SwapBuffers(Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc); +# endif +} + +#if HAVE_GL_OVERLAY +#endif + +int Fl_WinAPI_Gl_Window_Driver::flush_begin(char& valid_f_) { +#if HAVE_GL_OVERLAY + char save_valid_f = valid_f_; + // Draw into hardware overlay planes if they are damaged: + if (overlay() && overlay() != pWindow + && (pWindow->damage()&(FL_DAMAGE_OVERLAY|FL_DAMAGE_EXPOSE) || !save_valid_f & 1)) { + set_gl_context(pWindow, (GLContext)overlay()); + if (fl_overlay_depth) + wglRealizeLayerPalette(Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc, 1, TRUE); + glDisable(GL_SCISSOR_TEST); + glClear(GL_COLOR_BUFFER_BIT); + Fl_Xlib_Graphics_Driver::fl_overlay = 1; + draw_overlay(); + Fl_Xlib_Graphics_Driver::fl_overlay = 0; + valid_f_ = save_valid_f; + wglSwapLayerBuffers(Fl_WinAPI_Window_Driver::driver(pWindow)->private_dc, WGL_SWAP_OVERLAY1); + // if only the overlay was damaged we are done, leave main layer alone: + if (pWindow->damage() == FL_DAMAGE_OVERLAY) { + return 1; + } + } +#endif + return 0; +} + +void* Fl_WinAPI_Gl_Window_Driver::GetProcAddress(const char *procName) { + return (void*)wglGetProcAddress((LPCSTR)procName); +} + + +void Fl_WinAPI_Gl_Window_Driver::draw_string_legacy(const char* str, int n) { + draw_string_legacy_get_list(str, n); +} + +int Fl_WinAPI_Gl_Window_Driver::genlistsize() { + return 0x10000; +} + +void Fl_WinAPI_Gl_Window_Driver::gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize) { + if (!fl_fontsize->listbase) { + fl_fontsize->listbase = glGenLists(genlistsize()); + } + glListBase(fl_fontsize->listbase); +} + +void Fl_WinAPI_Gl_Window_Driver::get_list(Fl_Font_Descriptor *fd, int r) { + Fl_GDI_Font_Descriptor* gl_fd = (Fl_GDI_Font_Descriptor*)fd; + if (gl_fd->glok[r]) return; + gl_fd->glok[r] = 1; + unsigned int ii = r * 0x400; + HFONT oldFid = (HFONT)SelectObject((HDC)fl_graphics_driver->gc(), gl_fd->fid); + wglUseFontBitmapsW((HDC)fl_graphics_driver->gc(), ii, 0x400, gl_fd->listbase+ii); + SelectObject((HDC)fl_graphics_driver->gc(), oldFid); +} + + +#endif // HAVE_GL diff --git a/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx b/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx new file mode 100644 index 000000000..a52d4c70f --- /dev/null +++ b/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx @@ -0,0 +1,549 @@ +// +// Class Fl_X11_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). +// +// Copyright 2021 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 <config.h> +#if HAVE_GL +#include <FL/platform.H> +#include "../../Fl_Gl_Choice.H" +#include "../../Fl_Screen_Driver.H" +#include "../../Fl_Window_Driver.H" +#include "../../Fl_Gl_Window_Driver.H" +#include "../Xlib/Fl_Font.H" +#include "../Xlib/Fl_Xlib_Graphics_Driver.H" +# include <GL/glx.h> +# if ! defined(GLX_VERSION_1_3) +# typedef void *GLXFBConfig; +# endif + +class Fl_X11_Gl_Window_Driver : public Fl_Gl_Window_Driver { + friend class Fl_Gl_Window_Driver; + Fl_X11_Gl_Window_Driver(Fl_Gl_Window *win) : Fl_Gl_Window_Driver(win) {} + virtual float pixels_per_unit(); + virtual void before_show(int& need_after); + virtual int mode_(int m, const int *a); + virtual void swap_buffers(); + virtual void resize(int is_a_resize, int w, int h); + virtual char swap_type(); + virtual Fl_Gl_Choice *find(int m, const int *alistp); + virtual GLContext create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer = 0); + virtual void set_gl_context(Fl_Window* w, GLContext context); + virtual void delete_gl_context(GLContext); +#if HAVE_GL_OVERLAY + virtual void make_overlay(void *&o); + virtual int can_do_overlay(); + virtual void hide_overlay(); + virtual int overlay_color(Fl_Color i); +#endif + virtual void make_overlay_current(); + virtual void redraw_overlay(); + virtual void waitGL(); + virtual void gl_visual(Fl_Gl_Choice*); // support for Fl::gl_visual() + virtual void gl_start(); + virtual void draw_string_legacy(const char* str, int n); + virtual void gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize); + virtual void get_list(Fl_Font_Descriptor *fd, int r); + virtual int genlistsize(); +#if !USE_XFT + virtual Fl_Font_Descriptor** fontnum_to_fontdescriptor(int fnum); +#endif + public: + static GLContext create_gl_context(XVisualInfo* vis); +}; + +// Describes crap needed to create a GLContext. +class Fl_X11_Gl_Choice : public Fl_Gl_Choice { + friend class Fl_X11_Gl_Window_Driver; +private: + XVisualInfo *vis; /* the visual to use */ + Colormap colormap; /* a colormap for that visual */ + GLXFBConfig best_fb; +public: + Fl_X11_Gl_Choice(int m, const int *alistp, Fl_Gl_Choice *n) : Fl_Gl_Choice(m, alistp, n) { + vis = NULL; + colormap = 0; + best_fb = NULL; + } +}; + +void Fl_X11_Gl_Window_Driver::draw_string_legacy(const char* str, int n) { + draw_string_legacy_get_list(str, n); +} + +int Fl_X11_Gl_Window_Driver::genlistsize() { +#if USE_XFT + return 256; +#else + return 0x10000; +#endif +} + +void Fl_X11_Gl_Window_Driver::gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize) { + /* This method should ONLY be triggered if our GL font texture pile mechanism + * is not working on this platform. This code might not reliably render glyphs + * from higher codepoints. */ + if (!fl_fontsize->listbase) { +#if USE_XFT + /* Ideally, for XFT, we need a glXUseXftFont implementation here... But we + * do not have such a thing. Instead, we try to find a legacy Xlib font that + * matches the current XFT font and use that. + * Ideally, we never come here - we hope the texture pile implementation + * will work correctly so that XFT can render the face directly without the + * need for this workaround. */ + XFontStruct *font = fl_xfont.value(); + int base = font->min_char_or_byte2; + int count = font->max_char_or_byte2 - base + 1; + fl_fontsize->listbase = glGenLists(genlistsize()); + glXUseXFont(font->fid, base, count, fl_fontsize->listbase+base); +#else + /* Not using XFT to render text - the legacy Xlib fonts can usually be rendered + * directly by using glXUseXFont mechanisms. */ + fl_fontsize->listbase = glGenLists(genlistsize()); +#endif // !USE_XFT + } + glListBase(fl_fontsize->listbase); +} + + +void Fl_X11_Gl_Window_Driver::get_list(Fl_Font_Descriptor *fd, int r) { +# if USE_XFT + /* We hope not to come here: We hope that any system using XFT will also + * have sufficient GL capability to support our font texture pile mechansim, + * allowing XFT to render the face directly. */ + // Face already set by gl_bitmap_font in this case. +# else + Fl_Xlib_Font_Descriptor *gl_fd = (Fl_Xlib_Font_Descriptor*)fd; + if (gl_fd->glok[r]) return; + gl_fd->glok[r] = 1; + unsigned int ii = r * 0x400; + for (int i = 0; i < 0x400; i++) { + XFontStruct *font = NULL; + unsigned short id; + fl_XGetUtf8FontAndGlyph(gl_fd->font, ii, &font, &id); + if (font) glXUseXFont(font->fid, id, 1, gl_fd->listbase+ii); + ii++; + } +# endif +} + +#if !USE_XFT +Fl_Font_Descriptor** Fl_X11_Gl_Window_Driver::fontnum_to_fontdescriptor(int fnum) { + Fl_Xlib_Fontdesc *s = ((Fl_Xlib_Fontdesc*)fl_fonts) + fnum; + return &(s->first); +} +#endif + + +static XVisualInfo *gl3_getvisual(const int *blist, GLXFBConfig *pbestFB) +{ + int glx_major, glx_minor; + + // FBConfigs were added in GLX version 1.3. + if ( !glXQueryVersion(fl_display, &glx_major, &glx_minor) || + ( ( glx_major == 1 ) && ( glx_minor < 3 ) ) || ( glx_major < 1 ) ) { + return NULL; + } + + //printf( "Getting matching framebuffer configs\n" ); + int fbcount; + GLXFBConfig* fbc = glXChooseFBConfig(fl_display, DefaultScreen(fl_display), blist, &fbcount); + if (!fbc) { + //printf( "Failed to retrieve a framebuffer config\n" ); + return NULL; + } + //printf( "Found %d matching FB configs.\n", fbcount ); + + // Pick the FB config/visual with the most samples per pixel + int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999; + for (int i = 0; i < fbcount; ++i) + { + XVisualInfo *vi = glXGetVisualFromFBConfig( fl_display, fbc[i] ); + if (vi) { + int samp_buf, samples; + glXGetFBConfigAttrib(fl_display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); + glXGetFBConfigAttrib(fl_display, fbc[i], GLX_SAMPLES , &samples ); + /*printf( " Matching fbconfig %d, visual ID 0x%2lx: SAMPLE_BUFFERS = %d, SAMPLES = %d\n", + i, vi -> visualid, samp_buf, samples );*/ + if ( best_fbc < 0 || (samp_buf && samples > best_num_samp) ) + best_fbc = i, best_num_samp = samples; + if ( worst_fbc < 0 || !samp_buf || samples < worst_num_samp ) + worst_fbc = i, worst_num_samp = samples; + } + XFree(vi); + } + + GLXFBConfig bestFbc = fbc[ best_fbc ]; + // Be sure to free the FBConfig list allocated by glXChooseFBConfig() + XFree(fbc); + // Get a visual + XVisualInfo *vi = glXGetVisualFromFBConfig(fl_display, bestFbc); + *pbestFB = bestFbc; + return vi; +} + +Fl_Gl_Choice *Fl_X11_Gl_Window_Driver::find(int m, const int *alistp) +{ + Fl_X11_Gl_Choice *g = (Fl_X11_Gl_Choice*)Fl_Gl_Window_Driver::find_begin(m, alistp); + if (g) return g; + + const int *blist; + int list[32]; + + if (alistp) + blist = alistp; + else { + int n = 0; + if (m & FL_INDEX) { + list[n++] = GLX_BUFFER_SIZE; + list[n++] = 8; // glut tries many sizes, but this should work... + } else { + list[n++] = GLX_RGBA; + list[n++] = GLX_GREEN_SIZE; + list[n++] = (m & FL_RGB8) ? 8 : 1; + if (m & FL_ALPHA) { + list[n++] = GLX_ALPHA_SIZE; + list[n++] = (m & FL_RGB8) ? 8 : 1; + } + if (m & FL_ACCUM) { + list[n++] = GLX_ACCUM_GREEN_SIZE; + list[n++] = 1; + if (m & FL_ALPHA) { + list[n++] = GLX_ACCUM_ALPHA_SIZE; + list[n++] = 1; + } + } + } + if (m & FL_DOUBLE) { + list[n++] = GLX_DOUBLEBUFFER; + } + if (m & FL_DEPTH) { + list[n++] = GLX_DEPTH_SIZE; list[n++] = 1; + } + if (m & FL_STENCIL) { + list[n++] = GLX_STENCIL_SIZE; list[n++] = 1; + } + if (m & FL_STEREO) { + list[n++] = GLX_STEREO; + } +# if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) + if (m & FL_MULTISAMPLE) { + list[n++] = GLX_SAMPLES_SGIS; + list[n++] = 4; // value Glut uses + } +# endif + list[n] = 0; + blist = list; + } + + fl_open_display(); + XVisualInfo *visp = NULL; + GLXFBConfig best_fb = NULL; + if (m & FL_OPENGL3) { + visp = gl3_getvisual((const int *)blist, &best_fb); + } + if (!visp) { + visp = glXChooseVisual(fl_display, fl_screen, (int *)blist); + if (!visp) { +# if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) + if (m&FL_MULTISAMPLE) return find(m&~FL_MULTISAMPLE, 0); +# endif + return 0; + } + } + + g = new Fl_X11_Gl_Choice(m, alistp, first); + first = g; + + g->vis = visp; + g->best_fb = best_fb; + + if (/*MaxCmapsOfScreen(ScreenOfDisplay(fl_display,fl_screen))==1 && */ + visp->visualid == fl_visual->visualid && + !fl_getenv("MESA_PRIVATE_CMAP")) + g->colormap = fl_colormap; + else + g->colormap = XCreateColormap(fl_display, RootWindow(fl_display,fl_screen), + visp->visual, AllocNone); + return g; +} + +static bool ctxErrorOccurred = false; +static int ctxErrorHandler( Display *dpy, XErrorEvent *ev ) +{ + ctxErrorOccurred = true; + return 0; +} + +GLContext Fl_X11_Gl_Window_Driver::create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer) { + GLContext shared_ctx = 0; + if (context_list && nContext) shared_ctx = context_list[0]; + + typedef GLContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLContext, Bool, const int*); + // It is not necessary to create or make current to a context before calling glXGetProcAddressARB + static glXCreateContextAttribsARBProc glXCreateContextAttribsARB = +#if defined(HAVE_GLXGETPROCADDRESSARB) + (glXCreateContextAttribsARBProc)glXGetProcAddressARB((const GLubyte *)"glXCreateContextAttribsARB"); +#else + NULL; +#endif + + GLContext ctx = 0; + // Check for the GLX_ARB_create_context extension string and the function. + // If either is not present, use GLX 1.3 context creation method. + const char *glxExts = glXQueryExtensionsString(fl_display, fl_screen); + if (((Fl_X11_Gl_Choice*)g)->best_fb && strstr(glxExts, "GLX_ARB_create_context") && glXCreateContextAttribsARB ) { + int context_attribs[] = + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 2, + //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + //GLX_CONTEXT_PROFILE_MASK_ARB , GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + None + }; + ctxErrorOccurred = false; + XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler); + ctx = glXCreateContextAttribsARB(fl_display, ((Fl_X11_Gl_Choice*)g)->best_fb, shared_ctx, true, context_attribs); + XSync(fl_display, false); // Sync to ensure any errors generated are processed. + if (ctxErrorOccurred) ctx = 0; + XSetErrorHandler(oldHandler); + } + if (!ctx) { // use OpenGL 1-style context creation + ctx = glXCreateContext(fl_display, ((Fl_X11_Gl_Choice*)g)->vis, shared_ctx, true); + } + if (ctx) + add_context(ctx); +//glXMakeCurrent(fl_display, fl_xid(window), ctx);printf("%s\n", glGetString(GL_VERSION)); + return ctx; +} + +GLContext Fl_X11_Gl_Window_Driver::create_gl_context(XVisualInfo *vis) { + GLContext shared_ctx = 0; + if (context_list && nContext) shared_ctx = context_list[0]; + GLContext context = glXCreateContext(fl_display, vis, shared_ctx, 1); + if (context) + add_context(context); + return context; +} + +void Fl_X11_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context) { + if (context != cached_context || w != cached_window) { + cached_context = context; + cached_window = w; + glXMakeCurrent(fl_display, fl_xid(w), context); + } +} + +void Fl_X11_Gl_Window_Driver::delete_gl_context(GLContext context) { + if (cached_context == context) { + cached_context = 0; + cached_window = 0; + glXMakeCurrent(fl_display, 0, 0); + } + glXDestroyContext(fl_display, context); + del_context(context); +} + + +void Fl_X11_Gl_Window_Driver::make_overlay_current() { +#if HAVE_GL_OVERLAY + if (overlay() != pWindow) { + ((Fl_Gl_Window*)overlay())->make_current(); + } else +#endif + glDrawBuffer(GL_FRONT); +} + +void Fl_X11_Gl_Window_Driver::redraw_overlay() { + if (overlay() != pWindow) + ((Fl_Gl_Window*)overlay())->redraw(); + else + pWindow->damage(FL_DAMAGE_OVERLAY); +} + +#if HAVE_GL_OVERLAY + +// Methods on Fl_Gl_Window_Driver that create an overlay window. + +// Under X this is done by creating another window, of class _Fl_Gl_Overlay +// which is a subclass of Fl_Gl_Window except it uses the overlay planes. +// A pointer to this is stored in the "overlay" pointer of the Fl_Gl_Window. + +// If overlay hardware is unavailable, the overlay is +// "faked" by drawing into the main layers. This is indicated by +// setting overlay == this. + +extern XVisualInfo *fl_find_overlay_visual(); +extern XVisualInfo *fl_overlay_visual; +extern Colormap fl_overlay_colormap; +extern unsigned long fl_transparent_pixel; +//extern uchar fl_overlay; + +int Fl_X11_Gl_Window_Driver::overlay_color(Fl_Color i) { + if (Fl_Xlib_Graphics_Driver::fl_overlay) {glIndexi(int(fl_xpixel(i))); return 1;} + return 0; +} + + +class _Fl_Gl_Overlay : public Fl_Gl_Window { + void flush(); + void draw(); +public: + void show(); + _Fl_Gl_Overlay(int x, int y, int w, int h) : + Fl_Gl_Window(x,y,w,h) { + set_flag(INACTIVE); + } +}; + +void _Fl_Gl_Overlay::flush() { + make_current(); +#ifdef BOXX_BUGS + // The BoXX overlay is broken and you must not call swap-buffers. This + // code will make it work, but we lose because machines that do support + // double-buffered overlays will blink when they don't have to + glDrawBuffer(GL_FRONT); + draw(); +#else + draw(); + swap_buffers(); +#endif + glFlush(); + valid(1); +} + +void _Fl_Gl_Overlay::draw() { + if (!valid()) glClearIndex((GLfloat)fl_transparent_pixel); + if (damage() != FL_DAMAGE_EXPOSE) glClear(GL_COLOR_BUFFER_BIT); + Fl_Gl_Window *w = (Fl_Gl_Window *)parent(); + uchar save_valid = w->valid(); + w->valid(valid()); + Fl_Xlib_Graphics_Driver::fl_overlay = 1; + w->gl_driver()->draw_overlay(); + Fl_Xlib_Graphics_Driver::fl_overlay = 0; + valid(w->valid()); + w->valid(save_valid); +} + +void _Fl_Gl_Overlay::show() { + if (!shown()) { + fl_background_pixel = int(fl_transparent_pixel); + Fl_X::make_xid(this, fl_overlay_visual, fl_overlay_colormap); + fl_background_pixel = -1; + // find the outermost window to tell wm about the colormap: + Fl_Window *w = window(); + for (;;) {Fl_Window *w1 = w->window(); if (!w1) break; w = w1;} + XSetWMColormapWindows(fl_display, fl_xid(w), &(Fl_X::i(this)->xid), 1); + context(Fl_X11_Gl_Window_Driver::create_gl_context(fl_overlay_visual), 1); + valid(0); + } + Fl_Gl_Window::show(); +} + +void Fl_X11_Gl_Window_Driver::hide_overlay() { + if (overlay() && overlay() != pWindow) ((Fl_Gl_Window*)overlay())->hide(); +} + +int Fl_X11_Gl_Window_Driver::can_do_overlay() { + return fl_find_overlay_visual() != 0; +} + + +void Fl_X11_Gl_Window_Driver::make_overlay(void *¤t) { + if (current) return; + if (can_do_overlay()) { + _Fl_Gl_Overlay* o = new _Fl_Gl_Overlay(0, 0, pWindow->w(), pWindow->h()); + current = o; + pWindow->add(*o); + o->show(); + } else { + current = pWindow; // fake the overlay + } +} +#endif // HAVE_GL_OVERLAY + + +Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w) +{ + return new Fl_X11_Gl_Window_Driver(w); +} + +void Fl_X11_Gl_Window_Driver::before_show(int&) { + Fl_X11_Gl_Choice *g = (Fl_X11_Gl_Choice*)this->g(); + Fl_X::make_xid(pWindow, g->vis, g->colormap); + if (overlay() && overlay() != pWindow) ((Fl_Gl_Window*)overlay())->show(); +} + +float Fl_X11_Gl_Window_Driver::pixels_per_unit() +{ + int ns = Fl_Window_Driver::driver(pWindow)->screen_num(); + return Fl::screen_driver()->scale(ns); +} + +int Fl_X11_Gl_Window_Driver::mode_(int m, const int *a) { + int oldmode = mode(); + 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++) == + GLX_DOUBLEBUFFER + ) { m |= FL_DOUBLE; break; } + } + } + Fl_X11_Gl_Choice* oldg = (Fl_X11_Gl_Choice*)g(); + pWindow->context(0); + mode(m); alist(a); + if (pWindow->shown()) { + g( find(m, a) ); + // under X, if the visual changes we must make a new X window (yuck!): + Fl_X11_Gl_Choice* g = (Fl_X11_Gl_Choice*)this->g(); + if (!g || g->vis->visualid != oldg->vis->visualid || (oldmode^m)&FL_DOUBLE) { + pWindow->hide(); + pWindow->show(); + } + } else { + g(0); + } + return 1; +} + +void Fl_X11_Gl_Window_Driver::swap_buffers() { + glXSwapBuffers(fl_display, fl_xid(pWindow)); +} + +void Fl_X11_Gl_Window_Driver::resize(int is_a_resize, int W, int H) { + if (is_a_resize && !pWindow->resizable() && overlay() && overlay() != pWindow) { + ((Fl_Gl_Window*)overlay())->resize(0,0,W,H); + } +} + +char Fl_X11_Gl_Window_Driver::swap_type() {return copy;} + +void Fl_X11_Gl_Window_Driver::waitGL() { + glXWaitGL(); +} + + +void Fl_X11_Gl_Window_Driver::gl_visual(Fl_Gl_Choice *c) { + Fl_Gl_Window_Driver::gl_visual(c); + fl_visual = ((Fl_X11_Gl_Choice*)c)->vis; + fl_colormap = ((Fl_X11_Gl_Choice*)c)->colormap; +} + +void Fl_X11_Gl_Window_Driver::gl_start() { + glXWaitX(); +} + +#endif // HAVE_GL diff --git a/src/drivers/X11/Fl_X11_Window_Driver.cxx b/src/drivers/X11/Fl_X11_Window_Driver.cxx index 19fc70b09..d757aa752 100644 --- a/src/drivers/X11/Fl_X11_Window_Driver.cxx +++ b/src/drivers/X11/Fl_X11_Window_Driver.cxx @@ -40,7 +40,6 @@ extern XVisualInfo *fl_find_overlay_visual(); extern XVisualInfo *fl_overlay_visual; extern Colormap fl_overlay_colormap; extern unsigned long fl_transparent_pixel; -extern uchar fl_overlay; // changes how fl_color(x) works #endif Window fl_window; @@ -595,13 +594,13 @@ void _Fl_Overlay::flush() { #if defined(FLTK_USE_CAIRO) if (Fl::cairo_autolink_context()) Fl::cairo_make_current(this); // capture gc changes automatically to update the cairo context adequately #endif - fl_overlay = 1; + Fl_Xlib_Graphics_Driver::fl_overlay = 1; Fl_Overlay_Window *w = (Fl_Overlay_Window *)parent(); Fl_X *myi = Fl_X::i(this); if (damage() != FL_DAMAGE_EXPOSE) XClearWindow(fl_display, fl_xid(this)); fl_clip_region(myi->region); myi->region = 0; w->draw_overlay(); - fl_overlay = 0; + Fl_Xlib_Graphics_Driver::fl_overlay = 0; } #endif // HAVE_OVERLAY @@ -648,10 +647,10 @@ void Fl_X11_Window_Driver::flush_menu() { // capture gc changes automatically to update the cairo context adequately if(Fl::autolink_context()) Fl::cairo_make_current(fl_graphics_driver->gc()); # endif - fl_overlay = 1; + Fl_Xlib_Graphics_Driver::fl_overlay = 1; fl_clip_region(myi->region); myi->region = 0; current(pWindow); draw(); - fl_overlay = 0; + Fl_Xlib_Graphics_Driver::fl_overlay = 0; #else flush_Fl_Window(); #endif diff --git a/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx b/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx index 373cf9e4d..738b5a493 100644 --- a/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx @@ -16,7 +16,6 @@ #include "../../config_lib.h" -#ifdef FL_CFG_GFX_XLIB #include <FL/Fl_Copy_Surface.H> #include <FL/Fl.H> #include <FL/platform.H> @@ -91,5 +90,3 @@ void Fl_Xlib_Copy_Surface_Driver::translate(int x, int y) { void Fl_Xlib_Copy_Surface_Driver::untranslate() { ((Fl_Xlib_Graphics_Driver*)driver())->untranslate_all(); } - -#endif // FL_CFG_GFX_XLIB diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H index 4f1906d59..6340374ae 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H @@ -116,6 +116,7 @@ public: #if USE_XFT static void destroy_xft_draw(Window id); #endif + static int fl_overlay; // --- bitmap stuff Fl_Bitmask create_bitmask(int w, int h, const uchar *array); diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx index 15ea319bc..46f44460c 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx @@ -39,6 +39,7 @@ Fl_Graphics_Driver *Fl_Graphics_Driver::newMainGraphicsDriver() } GC Fl_Xlib_Graphics_Driver::gc_ = NULL; +int Fl_Xlib_Graphics_Driver::fl_overlay = 0; /* Reference to the current graphics context For back-compatibility only. The preferred procedure to get this pointer is diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_color.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_color.cxx index 937ed7c50..910681702 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_color.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_color.cxx @@ -96,16 +96,12 @@ static void figure_out_visual() { # if HAVE_OVERLAY /** HAVE_OVERLAY determines whether fl_xmap is one or two planes */ Fl_XColor fl_xmap[2][256]; -/** HAVE_OVERLAY determines whether fl_overlay is variable or defined as 0 */ -uchar fl_overlay; Colormap fl_overlay_colormap; XVisualInfo* fl_overlay_visual; ulong fl_transparent_pixel; # else /** HAVE_OVERLAY determines whether fl_xmap is one or two planes */ Fl_XColor fl_xmap[1][256]; -/** HAVE_OVERLAY determines whether fl_overlay is variable or defined as 0 */ -# define fl_overlay 0 # endif void Fl_Xlib_Graphics_Driver::color(Fl_Color i) { @@ -147,7 +143,7 @@ ulong fl_xpixel(uchar r,uchar g,uchar b) { // find closest entry in the colormap: Fl_Color i = fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256); - Fl_XColor &xmap = fl_xmap[fl_overlay][i]; + Fl_XColor &xmap = fl_xmap[Fl_Xlib_Graphics_Driver::fl_overlay][i]; if (xmap.mapped) return xmap.pixel; // if not black or white, change the entry to be an exact match: if (i != FL_COLOR_CUBE && i != 0xFF) @@ -198,7 +194,7 @@ ulong fl_xpixel(Fl_Color i) { return fl_xpixel((i >> 24) & 255, (i >> 16) & 255, (i >> 8) & 255); } - Fl_XColor &xmap = fl_xmap[fl_overlay][i]; + Fl_XColor &xmap = fl_xmap[Fl_Xlib_Graphics_Driver::fl_overlay][i]; if (xmap.mapped) return xmap.pixel; if (!beenhere) figure_out_visual(); @@ -209,7 +205,7 @@ ulong fl_xpixel(Fl_Color i) { # if USE_COLORMAP Colormap colormap = fl_colormap; # if HAVE_OVERLAY - if (fl_overlay) colormap = fl_overlay_colormap; else + if (Fl_Xlib_Graphics_Driver::fl_overlay) colormap = fl_overlay_colormap; else # endif if (fl_redmask) { # endif @@ -227,9 +223,9 @@ ulong fl_xpixel(Fl_Color i) { } # if HAVE_OVERLAY static XColor* ac[2]; - XColor*& allcolors = ac[fl_overlay]; + XColor*& allcolors = ac[Fl_Xlib_Graphics_Driver::fl_overlay]; static int nc[2]; - int& numcolors = nc[fl_overlay]; + int& numcolors = nc[Fl_Xlib_Graphics_Driver::fl_overlay]; # else static XColor *allcolors; static int numcolors; @@ -254,7 +250,7 @@ ulong fl_xpixel(Fl_Color i) { // of round-trips to the X server, even though other programs may alter // the colormap after this and make decisions here wrong. # if HAVE_OVERLAY - if (fl_overlay) numcolors = fl_overlay_visual->colormap_size; else + if (Fl_Xlib_Graphics_Driver::fl_overlay) numcolors = fl_overlay_visual->colormap_size; else # endif numcolors = fl_visual->colormap_size; if (!allcolors) allcolors = new XColor[numcolors]; @@ -267,7 +263,7 @@ ulong fl_xpixel(Fl_Color i) { unsigned int bestmatch = 0; for (unsigned int n = numcolors; n--;) { # if HAVE_OVERLAY - if (fl_overlay && n == fl_transparent_pixel) continue; + if (Fl_Xlib_Graphics_Driver::fl_overlay && n == fl_transparent_pixel) continue; # endif XColor &a = allcolors[n]; int d, t; diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx index 5c88ec100..2f38a8275 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx @@ -36,7 +36,6 @@ #if USE_OVERLAY // Currently Xft does not work with colormapped visuals, so this probably // does not work unless you have a true-color overlay. -extern bool fl_overlay; extern Colormap fl_overlay_colormap; extern XVisualInfo* fl_overlay_visual; #endif diff --git a/src/gl_draw.cxx b/src/gl_draw.cxx index d16e98a01..125e68c31 100644 --- a/src/gl_draw.cxx +++ b/src/gl_draw.cxx @@ -250,8 +250,6 @@ void gl_color(Fl_Color i) { 2) draw the texture using the current GL color. */ -static float gl_scale = 1; // scaling factor between FLTK and GL drawing units: GL = FLTK * gl_scale - // manages a fifo pile of pre-computed string textures class gl_texture_fifo { friend class Fl_Gl_Window_Driver; @@ -301,7 +299,7 @@ int gl_texture_fifo::already_known(const char *str, int n) for ( rank = 0; rank <= last; rank++) { if ((fifo[rank].str_len == n) && (fifo[rank].fdesc == gl_fontsize) && - (fifo[rank].scale == gl_scale) && + (fifo[rank].scale == Fl_Gl_Window_Driver::gl_scale) && (memcmp(str, fifo[rank].utf8, n) == 0)) { return rank; } @@ -332,8 +330,8 @@ void gl_texture_fifo::display_texture(int rank) glMatrixMode (GL_MODELVIEW); glPushMatrix(); glLoadIdentity (); - float winw = gl_scale * Fl_Window::current()->w(); - float winh = gl_scale * Fl_Window::current()->h(); + float winw = Fl_Gl_Window_Driver::gl_scale * Fl_Window::current()->w(); + float winh = Fl_Gl_Window_Driver::gl_scale * Fl_Window::current()->h(); // GL_COLOR_BUFFER_BIT for glBlendFunc, GL_ENABLE_BIT for glEnable / glDisable glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT); glDisable (GL_DEPTH_TEST); // ensure text is not removed by depth buffer test. @@ -358,7 +356,7 @@ void gl_texture_fifo::display_texture(int rank) //write the texture on screen glBegin (GL_QUADS); float ox = pos[0]; - float oy = pos[1] + height - gl_scale * fl_descent(); + float oy = pos[1] + height - Fl_Gl_Window_Driver::gl_scale * fl_descent(); glTexCoord2f (0.0f, 0.0f); // draw lower left in world coordinates glVertex2f (ox, oy); glTexCoord2f (0.0f, height); // draw upper left in world coordinates @@ -407,12 +405,12 @@ int gl_texture_fifo::compute_texture(const char* str, int n) fifo[current].str_len = n; // record length of text in utf8 fl_graphics_driver->font_descriptor(gl_fontsize); int w, h; - w = fl_width(fifo[current].utf8, n) * gl_scale; + w = fl_width(fifo[current].utf8, n) * Fl_Gl_Window_Driver::gl_scale; // Hack - make w be aligned w = (w + 3) & (~3); - h = fl_height() * gl_scale; + h = fl_height() * Fl_Gl_Window_Driver::gl_scale; - fifo[current].scale = gl_scale; + fifo[current].scale = Fl_Gl_Window_Driver::gl_scale; fifo[current].fdesc = gl_fontsize; char *alpha_buf = Fl_Gl_Window_Driver::global()->alpha_mask_for_string(str, n, w, h); @@ -628,173 +626,6 @@ void Fl_Gl_Window_Driver::draw_string_legacy_glut(const char* str, int n) glRasterPos2d(objX, objY); } - -#if defined(FL_CFG_GFX_XLIB) -# include "drivers/Xlib/Fl_Font.H" -# include <FL/platform.H> -# include <GL/glx.h> - -void Fl_X11_Gl_Window_Driver::draw_string_legacy(const char* str, int n) { - draw_string_legacy_get_list(str, n); -} - -int Fl_X11_Gl_Window_Driver::genlistsize() { -#if USE_XFT - return 256; -#else - return 0x10000; -#endif -} - -void Fl_X11_Gl_Window_Driver::gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize) { - /* This method should ONLY be triggered if our GL font texture pile mechanism - * is not working on this platform. This code might not reliably render glyphs - * from higher codepoints. */ - if (!fl_fontsize->listbase) { -#if USE_XFT - /* Ideally, for XFT, we need a glXUseXftFont implementation here... But we - * do not have such a thing. Instead, we try to find a legacy Xlib font that - * matches the current XFT font and use that. - * Ideally, we never come here - we hope the texture pile implementation - * will work correctly so that XFT can render the face directly without the - * need for this workaround. */ - XFontStruct *font = fl_xfont.value(); - int base = font->min_char_or_byte2; - int count = font->max_char_or_byte2 - base + 1; - fl_fontsize->listbase = glGenLists(genlistsize()); - glXUseXFont(font->fid, base, count, fl_fontsize->listbase+base); -#else - /* Not using XFT to render text - the legacy Xlib fonts can usually be rendered - * directly by using glXUseXFont mechanisms. */ - fl_fontsize->listbase = glGenLists(genlistsize()); -#endif // !USE_XFT - } - glListBase(fl_fontsize->listbase); -} - - -void Fl_X11_Gl_Window_Driver::get_list(Fl_Font_Descriptor *fd, int r) { -# if USE_XFT - /* We hope not to come here: We hope that any system using XFT will also - * have sufficient GL capability to support our font texture pile mechansim, - * allowing XFT to render the face directly. */ - // Face already set by gl_bitmap_font in this case. -# else - Fl_Xlib_Font_Descriptor *gl_fd = (Fl_Xlib_Font_Descriptor*)fd; - if (gl_fd->glok[r]) return; - gl_fd->glok[r] = 1; - unsigned int ii = r * 0x400; - for (int i = 0; i < 0x400; i++) { - XFontStruct *font = NULL; - unsigned short id; - fl_XGetUtf8FontAndGlyph(gl_fd->font, ii, &font, &id); - if (font) glXUseXFont(font->fid, id, 1, gl_fd->listbase+ii); - ii++; - } -# endif -} - -#if !USE_XFT -Fl_Font_Descriptor** Fl_X11_Gl_Window_Driver::fontnum_to_fontdescriptor(int fnum) { - Fl_Xlib_Fontdesc *s = ((Fl_Xlib_Fontdesc*)fl_fonts) + fnum; - return &(s->first); -} -#endif - -#if HAVE_GL_OVERLAY -extern uchar fl_overlay; -int Fl_X11_Gl_Window_Driver::overlay_color(Fl_Color i) { - if (fl_overlay) {glIndexi(int(fl_xpixel(i))); return 1;} - return 0; -} -#endif // HAVE_GL_OVERLAY - -#endif // FL_CFG_GFX_XLIB - - -#if defined(FL_CFG_GFX_GDI) -# include "drivers/GDI/Fl_Font.H" - -void Fl_WinAPI_Gl_Window_Driver::draw_string_legacy(const char* str, int n) { - draw_string_legacy_get_list(str, n); -} - -int Fl_WinAPI_Gl_Window_Driver::genlistsize() { - return 0x10000; -} - -void Fl_WinAPI_Gl_Window_Driver::gl_bitmap_font(Fl_Font_Descriptor *fl_fontsize) { - if (!fl_fontsize->listbase) { - fl_fontsize->listbase = glGenLists(genlistsize()); - } - glListBase(fl_fontsize->listbase); -} - -void Fl_WinAPI_Gl_Window_Driver::get_list(Fl_Font_Descriptor *fd, int r) { - Fl_GDI_Font_Descriptor* gl_fd = (Fl_GDI_Font_Descriptor*)fd; - if (gl_fd->glok[r]) return; - gl_fd->glok[r] = 1; - unsigned int ii = r * 0x400; - HFONT oldFid = (HFONT)SelectObject((HDC)fl_graphics_driver->gc(), gl_fd->fid); - wglUseFontBitmapsW((HDC)fl_graphics_driver->gc(), ii, 0x400, gl_fd->listbase+ii); - SelectObject((HDC)fl_graphics_driver->gc(), oldFid); -} - -#if HAVE_GL_OVERLAY -extern uchar fl_overlay; -extern int fl_overlay_depth; -int Fl_WinAPI_Gl_Window_Driver::overlay_color(Fl_Color i) { - if (fl_overlay && fl_overlay_depth) { - if (fl_overlay_depth < 8) { - // only black & white produce the expected colors. This could - // be improved by fixing the colormap set in Fl_Gl_Overlay.cxx - int size = 1<<fl_overlay_depth; - if (!i) glIndexi(size-2); - else if (i >= size-2) glIndexi(size-1); - else glIndexi(i); - } else { - glIndexi(i ? i : FL_GRAY_RAMP); - } - return 1; - } - return 0; -} -#endif // HAVE_GL_OVERLAY -#endif // FL_CFG_GFX_GDI - - -#if defined(FL_CFG_GFX_QUARTZ) -#include <FL/platform.H> -#include <FL/Fl_Image_Surface.H> - -/* 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) -{ - // write str to a bitmap just big enough - Fl_Image_Surface *surf = new Fl_Image_Surface(w, h); - Fl_Font f=fl_font(); Fl_Fontsize s=fl_size(); - Fl_Surface_Device::push_current(surf); - fl_color(FL_WHITE); - fl_font(f, s * gl_scale); - 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(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; -} - -#endif // FL_CFG_GFX_QUARTZ - /** \} \endcond diff --git a/src/gl_start.cxx b/src/gl_start.cxx index 250bca27e..f96786c8e 100644 --- a/src/gl_start.cxx +++ b/src/gl_start.cxx @@ -37,21 +37,21 @@ class Fl_Gl_Choice; #include <FL/Fl_Gl_Window.H> #include "Fl_Gl_Window_Driver.H" -static GLContext context; +GLContext Fl_Gl_Window_Driver::gl_start_context; static int clip_state_number=-1; static int pw, ph; float gl_start_scale = 1; -static Fl_Gl_Choice* gl_choice; +static Fl_Gl_Choice* gl_choice = NULL; /** Creates an OpenGL context */ void gl_start() { gl_start_scale = Fl_Display_Device::display_device()->driver()->scale(); - if (!context) { + if (!Fl_Gl_Window_Driver::gl_start_context) { if (!gl_choice) Fl::gl_visual(0); - context = Fl_Gl_Window_Driver::global()->create_gl_context(Fl_Window::current(), gl_choice); + Fl_Gl_Window_Driver::gl_start_context = Fl_Gl_Window_Driver::global()->create_gl_context(Fl_Window::current(), gl_choice); } - Fl_Gl_Window_Driver::global()->set_gl_context(Fl_Window::current(), context); + Fl_Gl_Window_Driver::global()->set_gl_context(Fl_Window::current(), Fl_Gl_Window_Driver::gl_start_context); Fl_Gl_Window_Driver::global()->gl_start(); if (pw != int(Fl_Window::current()->w() * gl_start_scale) || ph != int(Fl_Window::current()->h() * gl_start_scale)) { pw = int(Fl_Window::current()->w() * gl_start_scale); @@ -94,32 +94,6 @@ void Fl_Gl_Window_Driver::gl_visual(Fl_Gl_Choice *c) { gl_choice = c; } -#ifdef FL_CFG_GFX_QUARTZ -#include "drivers/Cocoa/Fl_Cocoa_Window_Driver.H" - -void Fl_Cocoa_Gl_Window_Driver::gl_start() { - Fl_Cocoa_Window_Driver::gl_start(context); -} - -#endif - - -#ifdef FL_CFG_GFX_XLIB -#include <FL/platform.H> -#include "Fl_Gl_Choice.H" - -void Fl_X11_Gl_Window_Driver::gl_visual(Fl_Gl_Choice *c) { - Fl_Gl_Window_Driver::gl_visual(c); - fl_visual = c->vis; - fl_colormap = c->colormap; -} - -void Fl_X11_Gl_Window_Driver::gl_start() { - glXWaitX(); -} - -#endif // FL_CFG_GFX_XLIB - int Fl::gl_visual(int mode, int *alist) { Fl_Gl_Choice *c = Fl_Gl_Window_Driver::global()->find(mode,alist); if (!c) return 0; |
