blob: 6562634dce84d0569bd3a3be7fc79d4c75312782 [file] [log] [blame]
Pierre Ossman403ac272017-01-02 17:00:41 +01001/* Copyright 2016 Pierre Ossman for Cendio AB
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19#include <assert.h>
20
21#include <FL/Fl_RGB_Image.H>
22#include <FL/x.H>
23
24#include <rdr/Exception.h>
25
26#include "Surface.h"
27
28void Surface::clear(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
29{
30 XRenderColor color;
31
32 color.red = (unsigned)r * 65535 / 255 * a / 255;
33 color.green = (unsigned)g * 65535 / 255 * a / 255;
34 color.blue = (unsigned)b * 65535 / 255 * a / 255;
35 color.alpha = (unsigned)a * 65535 / 255;
36
37 XRenderFillRectangle(fl_display, PictOpSrc, picture, &color,
38 0, 0, width(), height());
39}
40
41void Surface::draw(int src_x, int src_y, int x, int y, int w, int h)
42{
43 Picture winPict;
44
45 winPict = XRenderCreatePicture(fl_display, fl_window, visFormat, 0, NULL);
46 XRenderComposite(fl_display, PictOpSrc, picture, None, winPict,
47 src_x, src_y, 0, 0, x, y, w, h);
48 XRenderFreePicture(fl_display, winPict);
49}
50
Pierre Ossman3d74d882017-01-02 19:49:52 +010051void Surface::draw(Surface* dst, int src_x, int src_y, int x, int y, int w, int h)
52{
53 XRenderComposite(fl_display, PictOpSrc, picture, None, dst->picture,
54 src_x, src_y, 0, 0, x, y, w, h);
55}
56
Pierre Ossman455566e2017-02-10 16:37:52 +010057static Picture alpha_mask(int a)
Pierre Ossmande6a5802017-01-02 20:07:10 +010058{
Pierre Ossman455566e2017-02-10 16:37:52 +010059 Pixmap pixmap;
60 XRenderPictFormat* format;
61 XRenderPictureAttributes rep;
62 Picture pict;
63 XRenderColor color;
Pierre Ossmande6a5802017-01-02 20:07:10 +010064
Pierre Ossman455566e2017-02-10 16:37:52 +010065 if (a == 255)
66 return None;
67
68 pixmap = XCreatePixmap(fl_display, XDefaultRootWindow(fl_display),
69 1, 1, 8);
70
71 format = XRenderFindStandardFormat(fl_display, PictStandardA8);
72 rep.repeat = RepeatNormal;
73 pict = XRenderCreatePicture(fl_display, pixmap, format, CPRepeat, &rep);
74 XFreePixmap(fl_display, pixmap);
75
76 color.alpha = (unsigned)a * 65535 / 255;
77
78 XRenderFillRectangle(fl_display, PictOpSrc, pict, &color,
79 0, 0, 1, 1);
80
81 return pict;
Pierre Ossmande6a5802017-01-02 20:07:10 +010082}
83
Pierre Ossman455566e2017-02-10 16:37:52 +010084void Surface::blend(int src_x, int src_y, int x, int y, int w, int h, int a)
Pierre Ossmande6a5802017-01-02 20:07:10 +010085{
Pierre Ossman455566e2017-02-10 16:37:52 +010086 Picture winPict, alpha;
87
88 winPict = XRenderCreatePicture(fl_display, fl_window, visFormat, 0, NULL);
89 alpha = alpha_mask(a);
90 XRenderComposite(fl_display, PictOpOver, picture, alpha, winPict,
Pierre Ossmande6a5802017-01-02 20:07:10 +010091 src_x, src_y, 0, 0, x, y, w, h);
Pierre Ossman455566e2017-02-10 16:37:52 +010092 XRenderFreePicture(fl_display, winPict);
93
94 if (alpha != None)
95 XRenderFreePicture(fl_display, alpha);
96}
97
98void Surface::blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int h, int a)
99{
100 Picture alpha;
101
102 alpha = alpha_mask(a);
103 XRenderComposite(fl_display, PictOpOver, picture, alpha, dst->picture,
104 src_x, src_y, 0, 0, x, y, w, h);
105 if (alpha != None)
106 XRenderFreePicture(fl_display, alpha);
Pierre Ossmande6a5802017-01-02 20:07:10 +0100107}
108
109
Pierre Ossman403ac272017-01-02 17:00:41 +0100110void Surface::alloc()
111{
Pierre Ossmancc647db2018-10-25 10:36:21 +0200112 XRenderPictFormat templ;
Pierre Ossman403ac272017-01-02 17:00:41 +0100113 XRenderPictFormat* format;
114
115 // Might not be open at this point
116 fl_open_display();
117
118 pixmap = XCreatePixmap(fl_display, XDefaultRootWindow(fl_display),
119 width(), height(), 32);
120
Pierre Ossmancc647db2018-10-25 10:36:21 +0200121 // Our code assumes a BGRA byte order, regardless of what the endian
122 // of the machine is or the native byte order of XImage, so make sure
123 // we find such a format
124 templ.type = PictTypeDirect;
125 templ.depth = 32;
126#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
127 templ.direct.alpha = 0;
128 templ.direct.red = 8;
129 templ.direct.green = 16;
130 templ.direct.blue = 24;
131#else
132 templ.direct.alpha = 24;
133 templ.direct.red = 16;
134 templ.direct.green = 8;
135 templ.direct.blue = 0;
136#endif
137 templ.direct.alphaMask = 0xff;
138 templ.direct.redMask = 0xff;
139 templ.direct.greenMask = 0xff;
140 templ.direct.blueMask = 0xff;
141
142 format = XRenderFindFormat(fl_display, PictFormatType | PictFormatDepth |
143 PictFormatRed | PictFormatRedMask |
144 PictFormatGreen | PictFormatGreenMask |
145 PictFormatBlue | PictFormatBlueMask |
146 PictFormatAlpha | PictFormatAlphaMask,
147 &templ, 0);
148
149 if (!format)
150 throw rdr::Exception("XRenderFindFormat");
151
Pierre Ossman403ac272017-01-02 17:00:41 +0100152 picture = XRenderCreatePicture(fl_display, pixmap, format, 0, NULL);
153
154 visFormat = XRenderFindVisualFormat(fl_display, fl_visual->visual);
155}
156
157void Surface::dealloc()
158{
159 XRenderFreePicture(fl_display, picture);
160 XFreePixmap(fl_display, pixmap);
161}
162
163void Surface::update(const Fl_RGB_Image* image)
164{
165 XImage* img;
166 GC gc;
167
168 int x, y;
169 const unsigned char* in;
170 unsigned char* out;
171
172 assert(image->w() == width());
173 assert(image->h() == height());
174
175 img = XCreateImage(fl_display, CopyFromParent, 32,
176 ZPixmap, 0, NULL, width(), height(),
177 32, 0);
178 if (!img)
179 throw rdr::Exception("XCreateImage");
180
181 img->data = (char*)malloc(img->bytes_per_line * img->height);
182 if (!img->data)
183 throw rdr::Exception("malloc");
184
185 // Convert data and pre-multiply alpha
186 in = (const unsigned char*)image->data()[0];
187 out = (unsigned char*)img->data;
188 for (y = 0;y < img->height;y++) {
189 for (x = 0;x < img->width;x++) {
190 switch (image->d()) {
191 case 1:
192 *out++ = in[0];
193 *out++ = in[0];
194 *out++ = in[0];
195 *out++ = 0xff;
196 break;
197 case 2:
198 *out++ = (unsigned)in[0] * in[1] / 255;
199 *out++ = (unsigned)in[0] * in[1] / 255;
200 *out++ = (unsigned)in[0] * in[1] / 255;
201 *out++ = in[1];
202 break;
203 case 3:
204 *out++ = in[2];
205 *out++ = in[1];
206 *out++ = in[0];
207 *out++ = 0xff;
208 break;
209 case 4:
210 *out++ = (unsigned)in[2] * in[3] / 255;
211 *out++ = (unsigned)in[1] * in[3] / 255;
212 *out++ = (unsigned)in[0] * in[3] / 255;
213 *out++ = in[3];
214 break;
215 }
216 in += image->d();
217 }
218 if (image->ld() != 0)
219 in += image->ld() - image->w() * image->d();
220 }
221
222 gc = XCreateGC(fl_display, pixmap, 0, NULL);
223 XPutImage(fl_display, pixmap, gc, img,
224 0, 0, 0, 0, img->width, img->height);
225 XFreeGC(fl_display, gc);
226
227 XDestroyImage(img);
228}
229