summaryrefslogtreecommitdiff
path: root/src/Fl_Gl_Device_Plugin.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/Fl_Gl_Device_Plugin.cxx')
-rw-r--r--src/Fl_Gl_Device_Plugin.cxx134
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 $".
//