blob: 87b0cb2fdaf6cdf21d87b8ef1702165d8a578032 [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 RGBQUAD* out;
31 int x, y;
32
33 r = (unsigned)r * a / 255;
34 g = (unsigned)g * a / 255;
35 b = (unsigned)b * a / 255;
36
37 out = data;
38 for (y = 0;y < width();y++) {
39 for (x = 0;x < height();x++) {
40 out->rgbRed = r;
41 out->rgbGreen = g;
42 out->rgbBlue = b;
43 out->rgbReserved = a;
44 out++;
45 }
46 }
47}
48
49void Surface::draw(int src_x, int src_y, int x, int y, int w, int h)
50{
51 HDC dc;
52
53 dc = CreateCompatibleDC(fl_gc);
54 if (!dc)
55 throw rdr::SystemException("CreateCompatibleDC", GetLastError());
56
57 if (!SelectObject(dc, bitmap))
58 throw rdr::SystemException("SelectObject", GetLastError());
59
60 if (!BitBlt(fl_gc, x, y, w, h, dc, src_x, src_y, SRCCOPY)) {
61 // If the desktop we're rendering to is inactive (like when the screen
62 // is locked or the UAC is active), then GDI calls will randomly fail.
63 // This is completely undocumented so we have no idea how best to deal
64 // with it. For now, we've only seen this error and for this function
65 // so only ignore this combination.
66 if (GetLastError() != ERROR_INVALID_HANDLE)
67 throw rdr::SystemException("BitBlt", GetLastError());
68 }
69
70 DeleteDC(dc);
71}
72
Pierre Ossman3d74d882017-01-02 19:49:52 +010073void Surface::draw(Surface* dst, int src_x, int src_y, int x, int y, int w, int h)
74{
75 HDC origdc, dstdc;
76
77 dstdc = CreateCompatibleDC(NULL);
78 if (!dstdc)
79 throw rdr::SystemException("CreateCompatibleDC", GetLastError());
80
81 if (!SelectObject(dstdc, dst->bitmap))
82 throw rdr::SystemException("SelectObject", GetLastError());
83
84 origdc = fl_gc;
85 fl_gc = dstdc;
86 draw(src_x, src_y, x, y, w, h);
87 fl_gc = origdc;
88
89 DeleteDC(dstdc);
90}
91
Pierre Ossmande6a5802017-01-02 20:07:10 +010092void Surface::blend(int src_x, int src_y, int x, int y, int w, int h)
93{
94 // Compositing doesn't work properly for window DC:s
95 assert(false);
96}
97
98void Surface::blend(Surface* dst, int src_x, int src_y, int x, int y, int w, int h)
99{
100 HDC dstdc, srcdc;
101 BLENDFUNCTION blend;
102
103 dstdc = CreateCompatibleDC(NULL);
104 if (!dstdc)
105 throw rdr::SystemException("CreateCompatibleDC", GetLastError());
106 srcdc = CreateCompatibleDC(NULL);
107 if (!srcdc)
108 throw rdr::SystemException("CreateCompatibleDC", GetLastError());
109
110 if (!SelectObject(dstdc, dst->bitmap))
111 throw rdr::SystemException("SelectObject", GetLastError());
112 if (!SelectObject(srcdc, bitmap))
113 throw rdr::SystemException("SelectObject", GetLastError());
114
115 blend.BlendOp = AC_SRC_OVER;
116 blend.BlendFlags = 0;
117 blend.SourceConstantAlpha = 255;
118 blend.AlphaFormat = AC_SRC_ALPHA;
119
120 if (!AlphaBlend(dstdc, x, y, w, h, srcdc, src_x, src_y, w, h, blend)) {
121 // If the desktop we're rendering to is inactive (like when the screen
122 // is locked or the UAC is active), then GDI calls will randomly fail.
123 // This is completely undocumented so we have no idea how best to deal
124 // with it. For now, we've only seen this error and for this function
125 // so only ignore this combination.
126 if (GetLastError() != ERROR_INVALID_HANDLE)
127 throw rdr::SystemException("BitBlt", GetLastError());
128 }
129
130 DeleteDC(srcdc);
131 DeleteDC(dstdc);
132}
133
Pierre Ossman403ac272017-01-02 17:00:41 +0100134void Surface::alloc()
135{
136 BITMAPINFOHEADER bih;
137
138 data = new RGBQUAD[width() * height()];
139
140 memset(&bih, 0, sizeof(bih));
141
142 bih.biSize = sizeof(BITMAPINFOHEADER);
143 bih.biBitCount = 32;
144 bih.biPlanes = 1;
145 bih.biWidth = width();
146 bih.biHeight = -height(); // Negative to get top-down
147 bih.biCompression = BI_RGB;
148
149 bitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bih,
150 DIB_RGB_COLORS, (void**)&data, NULL, 0);
151 if (!bitmap)
152 throw rdr::SystemException("CreateDIBSection", GetLastError());
153}
154
155void Surface::dealloc()
156{
157 DeleteObject(bitmap);
158}
159
160void Surface::update(const Fl_RGB_Image* image)
161{
162 const unsigned char* in;
163 RGBQUAD* out;
164 int x, y;
165
166 assert(image->w() == width());
167 assert(image->h() == height());
168
169 // Convert data and pre-multiply alpha
170 in = (const unsigned char*)image->data()[0];
171 out = data;
172 for (y = 0;y < image->w();y++) {
173 for (x = 0;x < image->h();x++) {
174 switch (image->d()) {
175 case 1:
176 out->rgbBlue = in[0];
177 out->rgbGreen = in[0];
178 out->rgbRed = in[0];
179 out->rgbReserved = 0xff;
180 break;
181 case 2:
182 out->rgbBlue = (unsigned)in[0] * in[1] / 255;
183 out->rgbGreen = (unsigned)in[0] * in[1] / 255;
184 out->rgbRed = (unsigned)in[0] * in[1] / 255;
185 out->rgbReserved = in[1];
186 break;
187 case 3:
188 out->rgbBlue = in[2];
189 out->rgbGreen = in[1];
190 out->rgbRed = in[0];
191 out->rgbReserved = 0xff;
192 break;
193 case 4:
194 out->rgbBlue = (unsigned)in[2] * in[3] / 255;
195 out->rgbGreen = (unsigned)in[1] * in[3] / 255;
196 out->rgbRed = (unsigned)in[0] * in[3] / 255;
197 out->rgbReserved = in[3];
198 break;
199 }
200 in += image->d();
201 out++;
202 }
203 if (image->ld() != 0)
204 in += image->ld() - image->w() * image->d();
205 }
206}
207