diff options
| author | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2021-02-16 09:29:13 +0100 |
|---|---|---|
| committer | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2021-02-16 09:29:13 +0100 |
| commit | 1adaa3def2138fafd40b9d9df212a068c57cdbf4 (patch) | |
| tree | 0898ea907c763d197d5137dc299eef8005c16de1 /src/drivers | |
| parent | 1f55bfe65cc8ca6e7b79efad66a7c304a69b12fe (diff) | |
Create classes Fl_XXX_Gl_Window_Driver according to driver model.
Diffstat (limited to 'src/drivers')
18 files changed, 1214 insertions, 65 deletions
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 |
