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/WinAPI | |
| parent | 1f55bfe65cc8ca6e7b79efad66a7c304a69b12fe (diff) | |
Create classes Fl_XXX_Gl_Window_Driver according to driver model.
Diffstat (limited to 'src/drivers/WinAPI')
| -rw-r--r-- | src/drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.cxx | 404 |
1 files changed, 404 insertions, 0 deletions
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 |
