From 06793c50fb99366a1008ea601c218b1cb6de0bf4 Mon Sep 17 00:00:00 2001 From: ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> Date: Tue, 16 Feb 2021 10:26:42 +0100 Subject: [PATCH] Create virtual Fl_RGB_Image* Fl_Gl_Window_Driver::capture_gl_rectangle() --- FL/Fl_Gl_Window.H | 1 + src/Fl_Gl_Window_Driver.H | 1 + .../Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx | 53 +++++++++++++++ .../OpenGL/Fl_OpenGL_Display_Device.cxx | 67 +++---------------- 4 files changed, 63 insertions(+), 59 deletions(-) diff --git a/FL/Fl_Gl_Window.H b/FL/Fl_Gl_Window.H index da8a35b84..0204c3efc 100644 --- a/FL/Fl_Gl_Window.H +++ b/FL/Fl_Gl_Window.H @@ -51,6 +51,7 @@ class Fl_Gl_Window_Driver; class FL_EXPORT Fl_Gl_Window : public Fl_Window { friend class Fl_Gl_Window_Driver; friend class _Fl_Gl_Overlay; + friend class Fl_OpenGL_Display_Device; Fl_Gl_Window_Driver *pGlWindowDriver; /** Returns a pointer to the window's Fl_Gl_Window_Driver object */ diff --git a/src/Fl_Gl_Window_Driver.H b/src/Fl_Gl_Window_Driver.H index d2670e2cc..ddc52c794 100644 --- a/src/Fl_Gl_Window_Driver.H +++ b/src/Fl_Gl_Window_Driver.H @@ -99,6 +99,7 @@ public: virtual char *alpha_mask_for_string(const char *str, int n, int w, int h); virtual int genlistsize() { return 0; } // support for gl_draw() virtual Fl_Font_Descriptor** fontnum_to_fontdescriptor(int fnum); + virtual Fl_RGB_Image* capture_gl_rectangle(int x, int y, int w, int h); }; #endif /* Fl_Gl_Window_Driver_H */ diff --git a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx index 188f4febf..a9df988c3 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx +++ b/src/drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx @@ -54,6 +54,7 @@ class Fl_Cocoa_Gl_Window_Driver : public Fl_Gl_Window_Driver { virtual void redraw_overlay(); virtual void gl_start(); virtual char *alpha_mask_for_string(const char *str, int n, int w, int h); + virtual Fl_RGB_Image* capture_gl_rectangle(int x, int y, int w, int h); }; // Describes crap needed to create a GLContext. @@ -245,4 +246,56 @@ void Fl_Cocoa_Gl_Window_Driver::gl_start() { Fl_Cocoa_Window_Driver::gl_start(gl_start_context); } +// convert BGRA to RGB and also exchange top and bottom +static uchar *convert_BGRA_to_RGB(uchar *baseAddress, int w, int h, int mByteWidth) +{ + uchar *newimg = new uchar[3*w*h]; + uchar *to = newimg; + for (int i = h-1; i >= 0; i--) { + uchar *from = baseAddress + i * mByteWidth; + for (int j = 0; j < w; j++, from += 4) { +#if defined(__ppc__) && __ppc__ + memcpy(to, from + 1, 3); + to += 3; +#else + *(to++) = *(from+2); + *(to++) = *(from+1); + *(to++) = *from; +#endif + } + } + delete[] baseAddress; + return newimg; +} + +Fl_RGB_Image* Fl_Cocoa_Gl_Window_Driver::capture_gl_rectangle(int x, int y, int w, int h) +{ + Fl_Gl_Window* glw = pWindow; + float factor = glw->pixels_per_unit(); + if (factor != 1) { + w *= factor; h *= factor; x *= factor; y *= factor; + } + Fl_Cocoa_Window_Driver::GLcontext_makecurrent(glw->context()); + Fl_Cocoa_Window_Driver::flush_context(glw->context()); // to capture also the overlay and for directGL demo + // Read OpenGL context pixels directly. + // For extra safety, save & restore OpenGL states that are changed + glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); + glPixelStorei(GL_PACK_ALIGNMENT, 4); /* Force 4-byte alignment */ + glPixelStorei(GL_PACK_ROW_LENGTH, 0); + glPixelStorei(GL_PACK_SKIP_ROWS, 0); + glPixelStorei(GL_PACK_SKIP_PIXELS, 0); + // Read a block of pixels from the frame buffer + int mByteWidth = w * 4; + mByteWidth = (mByteWidth + 3) & ~3; // Align to 4 bytes + uchar *baseAddress = new uchar[mByteWidth * h]; + glReadPixels(x, glw->pixel_h() - (y+h), w, h, + GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, baseAddress); + glPopClientAttrib(); + baseAddress = convert_BGRA_to_RGB(baseAddress, w, h, mByteWidth); + Fl_RGB_Image *img = new Fl_RGB_Image(baseAddress, w, h, 3, 3 * w); + img->alloc_array = 1; + Fl_Cocoa_Window_Driver::flush_context(glw->context()); + return img; +} + #endif // HAVE_GL diff --git a/src/drivers/OpenGL/Fl_OpenGL_Display_Device.cxx b/src/drivers/OpenGL/Fl_OpenGL_Display_Device.cxx index acd74bc95..b1fb688bc 100644 --- a/src/drivers/OpenGL/Fl_OpenGL_Display_Device.cxx +++ b/src/drivers/OpenGL/Fl_OpenGL_Display_Device.cxx @@ -16,7 +16,10 @@ #include "../../config_lib.h" #include +#include "../../Fl_Gl_Window_Driver.H" #include +#include "../../Fl_Screen_Driver.H" +#include "../../Fl_Window_Driver.H" #include #include @@ -35,69 +38,17 @@ Fl_OpenGL_Display_Device::Fl_OpenGL_Display_Device(Fl_OpenGL_Graphics_Driver *gr { } -#ifdef FL_CFG_GFX_QUARTZ -#include "../../Fl_Gl_Window_Driver.H" -#include "../Cocoa/Fl_Cocoa_Window_Driver.H" - -// convert BGRA to RGB and also exchange top and bottom -static uchar *convert_BGRA_to_RGB(uchar *baseAddress, int w, int h, int mByteWidth) -{ - uchar *newimg = new uchar[3*w*h]; - uchar *to = newimg; - for (int i = h-1; i >= 0; i--) { - uchar *from = baseAddress + i * mByteWidth; - for (int j = 0; j < w; j++, from += 4) { -#if defined(__ppc__) && __ppc__ - memcpy(to, from + 1, 3); - to += 3; -#else - *(to++) = *(from+2); - *(to++) = *(from+1); - *(to++) = *from; -#endif - } - } - delete[] baseAddress; - return newimg; -} - Fl_RGB_Image* Fl_OpenGL_Display_Device::capture_gl_rectangle(Fl_Gl_Window* glw, int x, int y, int w, int h) { - float factor = glw->pixels_per_unit(); - if (factor != 1) { - w *= factor; h *= factor; x *= factor; y *= factor; - } - Fl_Cocoa_Window_Driver::GLcontext_makecurrent(glw->context()); - Fl_Cocoa_Window_Driver::flush_context(glw->context()); // to capture also the overlay and for directGL demo - // Read OpenGL context pixels directly. - // For extra safety, save & restore OpenGL states that are changed - glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); - glPixelStorei(GL_PACK_ALIGNMENT, 4); /* Force 4-byte alignment */ - glPixelStorei(GL_PACK_ROW_LENGTH, 0); - glPixelStorei(GL_PACK_SKIP_ROWS, 0); - glPixelStorei(GL_PACK_SKIP_PIXELS, 0); - // Read a block of pixels from the frame buffer - int mByteWidth = w * 4; - mByteWidth = (mByteWidth + 3) & ~3; // Align to 4 bytes - uchar *baseAddress = new uchar[mByteWidth * h]; - glReadPixels(x, glw->pixel_h() - (y+h), w, h, - GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, baseAddress); - glPopClientAttrib(); - baseAddress = convert_BGRA_to_RGB(baseAddress, w, h, mByteWidth); - Fl_RGB_Image *img = new Fl_RGB_Image(baseAddress, w, h, 3, 3 * w); - img->alloc_array = 1; - Fl_Cocoa_Window_Driver::flush_context(glw->context()); - return img; + return glw->gl_driver()->capture_gl_rectangle(x, y, w, h); } -#else - -#include "../../Fl_Screen_Driver.H" -#include "../../Fl_Window_Driver.H" -Fl_RGB_Image* Fl_OpenGL_Display_Device::capture_gl_rectangle(Fl_Gl_Window *glw, int x, int y, int w, int h) -/* captures a rectangle of a Fl_Gl_Window window, and returns it as a RGB image +/* Captures a rectangle of a Fl_Gl_Window and returns it as a RGB image. + This is the platform-independent version. Some platforms may re-implement it. */ +Fl_RGB_Image* Fl_Gl_Window_Driver::capture_gl_rectangle(int x, int y, int w, int h) { + Fl_Gl_Window *glw = pWindow; glw->flush(); // forces a GL redraw, necessary for the glpuzzle demo // Read OpenGL context pixels directly. // For extra safety, save & restore OpenGL states that are changed @@ -135,5 +86,3 @@ Fl_RGB_Image* Fl_OpenGL_Display_Device::capture_gl_rectangle(Fl_Gl_Window *glw, img->alloc_array = 1; return img; } - -#endif