/
Fl_OpenGL_Display_Device.cxx
144 lines (132 loc) · 4.6 KB
/
Fl_OpenGL_Display_Device.cxx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//
// "$Id$"
//
// implementation of class Fl_Gl_Device_Plugin for the Fast Light Tool Kit (FLTK).
//
// Copyright 2010-2017 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:
//
// http://www.fltk.org/COPYING.php
//
// Please report all bugs and problems to:
//
// http://www.fltk.org/str.php
//
#include "../../config_lib.h"
#include <FL/Fl_Gl_Window.H>
#include <FL/Fl_Image.H>
#include <FL/gl.h>
#include <string.h>
#include "Fl_OpenGL_Graphics_Driver.H"
#include "Fl_OpenGL_Display_Device.H"
// TODO: much of Fl_Gl_Choice should probably go here
Fl_OpenGL_Display_Device *Fl_OpenGL_Display_Device::display_device() {
static Fl_OpenGL_Display_Device *display = new Fl_OpenGL_Display_Device(new Fl_OpenGL_Graphics_Driver());
return display;
};
Fl_OpenGL_Display_Device::Fl_OpenGL_Display_Device(Fl_OpenGL_Graphics_Driver *graphics_driver)
: Fl_Surface_Device(graphics_driver)
{
}
#ifdef FL_CFG_GFX_QUARTZ
#include "../../Fl_Gl_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_Gl_Window_Driver *driver = (Fl_Cocoa_Gl_Window_Driver*)glw->gl_driver();
driver->GLcontext_makecurrent(glw->context());
driver->flush_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;
driver->flush_context();
return img;
}
#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
*/
{
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);
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);
//
int ns = Fl_Window_Driver::driver(glw)->screen_num();
float s = Fl::screen_driver()->scale(ns);
if (s != 1) {
x *= s; y *= s; w *= s; h *= s;
}
// Read a block of pixels from the frame buffer
int mByteWidth = w * 3;
mByteWidth = (mByteWidth + 3) & ~3; // Align to 4 bytes
uchar *baseAddress = new uchar[mByteWidth * h];
glReadPixels(x, glw->pixel_h() - (y+h), w, h,
GL_RGB, GL_UNSIGNED_BYTE,
baseAddress);
glPopClientAttrib();
// GL gives a bottom-to-top image, convert it to top-to-bottom
uchar *tmp = new uchar[mByteWidth];
uchar *p = baseAddress ;
uchar *q = baseAddress + (h-1)*mByteWidth;
for (int i = 0; i < h/2; i++, p += mByteWidth, q -= mByteWidth) {
memcpy(tmp, p, mByteWidth);
memcpy(p, q, mByteWidth);
memcpy(q, tmp, mByteWidth);
}
delete[] tmp;
Fl_RGB_Image *img = new Fl_RGB_Image(baseAddress, w, h, 3, mByteWidth);
img->alloc_array = 1;
return img;
}
#endif
//
// End of "$Id$".
//