diff options
Diffstat (limited to 'src/Fl_Gl_Device_Plugin.cxx')
-rw-r--r-- | src/Fl_Gl_Device_Plugin.cxx | 134 |
1 files changed, 81 insertions, 53 deletions
diff --git a/src/Fl_Gl_Device_Plugin.cxx b/src/Fl_Gl_Device_Plugin.cxx index 313cd8e..9720091 100644 --- a/src/Fl_Gl_Device_Plugin.cxx +++ b/src/Fl_Gl_Device_Plugin.cxx @@ -1,9 +1,9 @@ // -// "$Id: Fl_Gl_Device_Plugin.cxx 10051 2014-01-10 16:50:55Z manolo $" +// "$Id: Fl_Gl_Device_Plugin.cxx 11943 2016-09-13 11:51:24Z manolo $" // // implementation of class Fl_Gl_Device_Plugin for the Fast Light Tool Kit (FLTK). // -// Copyright 2010 by Bill Spitzak and others. +// Copyright 2010-2014 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 @@ -20,26 +20,47 @@ #include <FL/Fl_Printer.H> #include <FL/Fl_Gl_Window.H> #include "Fl_Gl_Choice.H" +#include <FL/Fl_RGB_Image.H> #include "FL/Fl.H" -#ifndef __APPLE__ -#include "FL/fl_draw.H" -#endif #if defined(__APPLE__) -static void imgProviderReleaseData (void *info, const void *data, size_t size) +uchar *convert_BGRA_to_RGB(uchar *baseAddress, int w, int h, int mByteWidth) { - free((void *)data); + uchar *newimg = new uchar[3*w*h]; + uchar *to = newimg; + for (int i = 0; i < h; 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; } #endif -static void print_gl_window(Fl_Gl_Window *glw, int x, int y, int height) +static Fl_RGB_Image* 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 + stored from bottom to top. + */ { #if defined(__APPLE__) const int bytesperpixel = 4; + float factor = glw->pixels_per_unit(); + if (factor > 1) { + w *= factor; h *= factor; x *= factor; y *= factor; + } #else const int bytesperpixel = 3; #endif - glw->flush(); // forces a GL redraw necessary for the glpuzzle demo + 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 glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); @@ -48,66 +69,73 @@ static void print_gl_window(Fl_Gl_Window *glw, int x, int y, int height) glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); // Read a block of pixels from the frame buffer - int mByteWidth = glw->w() * bytesperpixel; + int mByteWidth = w * bytesperpixel; mByteWidth = (mByteWidth + 3) & ~3; // Align to 4 bytes - uchar *baseAddress = (uchar*)malloc(mByteWidth * glw->h()); - glReadPixels(0, 0, glw->w(), glw->h(), + uchar *baseAddress = new uchar[mByteWidth * h]; + glReadPixels(x, glw->pixel_h() - (y+h), w, h, #if defined(__APPLE__) - GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, + GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, #else - GL_RGB, GL_UNSIGNED_BYTE, + GL_RGB, GL_UNSIGNED_BYTE, #endif - baseAddress); + baseAddress); glPopClientAttrib(); #if defined(__APPLE__) -// kCGBitmapByteOrder32Host and CGBitmapInfo are supposed to arrive with 10.4 -// but some 10.4 don't have kCGBitmapByteOrder32Host, so we play a little #define game -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4 -#define kCGBitmapByteOrder32Host 0 -#define CGBitmapInfo CGImageAlphaInfo -#elif ! defined(kCGBitmapByteOrder32Host) -#ifdef __BIG_ENDIAN__ -#define kCGBitmapByteOrder32Host (4 << 12) -#else /* Little endian. */ -#define kCGBitmapByteOrder32Host (2 << 12) -#endif + baseAddress = convert_BGRA_to_RGB(baseAddress, w, h, mByteWidth); + mByteWidth = 3 * w; #endif - CGColorSpaceRef cSpace = CGColorSpaceCreateDeviceRGB(); - CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, baseAddress, mByteWidth * glw->h(), imgProviderReleaseData); - CGImageRef image = CGImageCreate(glw->w(), glw->h(), 8, 8*bytesperpixel, mByteWidth, cSpace, - (CGBitmapInfo)(kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host), - provider, NULL, false, kCGRenderingIntentDefault); - if(image == NULL) return; - CGContextSaveGState(fl_gc); - CGContextTranslateCTM(fl_gc, 0, height); - CGContextScaleCTM(fl_gc, 1.0f, -1.0f); - CGRect rect = { { x, height - y - glw->h() }, { glw->w(), glw->h() } }; - Fl_X::q_begin_image(rect, 0, 0, glw->w(), glw->h()); - CGContextDrawImage(fl_gc, rect, image); - Fl_X::q_end_image(); - CGContextRestoreGState(fl_gc); - CGImageRelease(image); - CGColorSpaceRelease(cSpace); - CGDataProviderRelease(provider); -#else - fl_draw_image(baseAddress + (glw->h() - 1) * mByteWidth, x, y , glw->w(), glw->h(), bytesperpixel, - mByteWidth); - free(baseAddress); -#endif // __APPLE__ + Fl_RGB_Image *img = new Fl_RGB_Image(baseAddress, w, h, 3, mByteWidth); + img->alloc_array = 1; + return img; +} + +#ifdef __APPLE__ +static void imgProviderReleaseData (void *info, const void *data, size_t size) +{ + delete (Fl_RGB_Image *)info; } +#endif /** - This class will make sure that OpenGL printing is available if fltk_gl - was linked to the program. + This class will make sure that OpenGL printing/screen capture is available if fltk_gl + was linked to the program */ class Fl_Gl_Device_Plugin : public Fl_Device_Plugin { public: Fl_Gl_Device_Plugin() : Fl_Device_Plugin(name()) { } virtual const char *name() { return "opengl.device.fltk.org"; } - virtual int print(Fl_Widget *w, int x, int y, int height) { + virtual int print(Fl_Widget *w, int x, int y, int height /*useless*/) { Fl_Gl_Window *glw = w->as_gl_window(); if (!glw) return 0; - print_gl_window(glw, x, y, height); - return 1; + Fl_RGB_Image *img = capture_gl_rectangle(glw, 0, 0, glw->w(), glw->h()); +#ifdef __APPLE__ + if (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) { + // convert the image to CGImage, and draw it at full res (useful on retina display) + CGColorSpaceRef cSpace = CGColorSpaceCreateDeviceRGB(); + CGDataProviderRef provider = CGDataProviderCreateWithData(img, img->array, img->ld() * img->h(), imgProviderReleaseData); + CGImageRef cgimg = CGImageCreate(img->w(), img->h(), 8, 24, img->ld(), cSpace, + (CGBitmapInfo)(kCGImageAlphaNone), + provider, NULL, false, kCGRenderingIntentDefault); + CGColorSpaceRelease(cSpace); + CGDataProviderRelease(provider); + CGContextDrawImage(fl_gc, CGRectMake(0, 0, glw->w(), glw->h()), cgimg); + CFRelease(cgimg); + return 1; + } else if (img->w() > glw->w()) { + Fl_RGB_Image *img2 = (Fl_RGB_Image*)img->copy(glw->w(), glw->h()); + delete img; + img = img2; + } +#endif + int ld = img->ld() ? img->ld() : img->w() * img->d(); + fl_draw_image(img->array + (img->h() - 1) * ld, x, y , img->w(), img->h(), 3, - ld); + delete img; + return 1; + } + virtual Fl_RGB_Image* rectangle_capture(Fl_Widget *widget, int x, int y, int w, int h) { + Fl_Gl_Window *glw = widget->as_gl_window(); + if (!glw) return NULL; + return capture_gl_rectangle(glw, x, y, w, h); } }; @@ -118,5 +146,5 @@ static Fl_Gl_Device_Plugin Gl_Device_Plugin; FL_EXPORT int fl_gl_load_plugin = 0; // -// End of "$Id: Fl_Gl_Device_Plugin.cxx 10051 2014-01-10 16:50:55Z manolo $". +// End of "$Id: Fl_Gl_Device_Plugin.cxx 11943 2016-09-13 11:51:24Z manolo $". // |