1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22
23 #if !SDL_RENDER_DISABLED
24
25 #include "SDL_draw.h"
26 #include "SDL_blendfillrect.h"
27
28
29 static int
SDL_BlendFillRect_RGB555(SDL_Surface * dst,const SDL_Rect * rect,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)30 SDL_BlendFillRect_RGB555(SDL_Surface * dst, const SDL_Rect * rect,
31 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
32 {
33 unsigned inva = 0xff - a;
34
35 switch (blendMode) {
36 case SDL_BLENDMODE_BLEND:
37 FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB555);
38 break;
39 case SDL_BLENDMODE_ADD:
40 FILLRECT(Uint16, DRAW_SETPIXEL_ADD_RGB555);
41 break;
42 case SDL_BLENDMODE_MOD:
43 FILLRECT(Uint16, DRAW_SETPIXEL_MOD_RGB555);
44 break;
45 default:
46 FILLRECT(Uint16, DRAW_SETPIXEL_RGB555);
47 break;
48 }
49 return 0;
50 }
51
52 static int
SDL_BlendFillRect_RGB565(SDL_Surface * dst,const SDL_Rect * rect,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)53 SDL_BlendFillRect_RGB565(SDL_Surface * dst, const SDL_Rect * rect,
54 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
55 {
56 unsigned inva = 0xff - a;
57
58 switch (blendMode) {
59 case SDL_BLENDMODE_BLEND:
60 FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB565);
61 break;
62 case SDL_BLENDMODE_ADD:
63 FILLRECT(Uint16, DRAW_SETPIXEL_ADD_RGB565);
64 break;
65 case SDL_BLENDMODE_MOD:
66 FILLRECT(Uint16, DRAW_SETPIXEL_MOD_RGB565);
67 break;
68 default:
69 FILLRECT(Uint16, DRAW_SETPIXEL_RGB565);
70 break;
71 }
72 return 0;
73 }
74
75 static int
SDL_BlendFillRect_RGB888(SDL_Surface * dst,const SDL_Rect * rect,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)76 SDL_BlendFillRect_RGB888(SDL_Surface * dst, const SDL_Rect * rect,
77 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
78 {
79 unsigned inva = 0xff - a;
80
81 switch (blendMode) {
82 case SDL_BLENDMODE_BLEND:
83 FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGB888);
84 break;
85 case SDL_BLENDMODE_ADD:
86 FILLRECT(Uint32, DRAW_SETPIXEL_ADD_RGB888);
87 break;
88 case SDL_BLENDMODE_MOD:
89 FILLRECT(Uint32, DRAW_SETPIXEL_MOD_RGB888);
90 break;
91 default:
92 FILLRECT(Uint32, DRAW_SETPIXEL_RGB888);
93 break;
94 }
95 return 0;
96 }
97
98 static int
SDL_BlendFillRect_ARGB8888(SDL_Surface * dst,const SDL_Rect * rect,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)99 SDL_BlendFillRect_ARGB8888(SDL_Surface * dst, const SDL_Rect * rect,
100 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
101 {
102 unsigned inva = 0xff - a;
103
104 switch (blendMode) {
105 case SDL_BLENDMODE_BLEND:
106 FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888);
107 break;
108 case SDL_BLENDMODE_ADD:
109 FILLRECT(Uint32, DRAW_SETPIXEL_ADD_ARGB8888);
110 break;
111 case SDL_BLENDMODE_MOD:
112 FILLRECT(Uint32, DRAW_SETPIXEL_MOD_ARGB8888);
113 break;
114 default:
115 FILLRECT(Uint32, DRAW_SETPIXEL_ARGB8888);
116 break;
117 }
118 return 0;
119 }
120
121 static int
SDL_BlendFillRect_RGB(SDL_Surface * dst,const SDL_Rect * rect,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)122 SDL_BlendFillRect_RGB(SDL_Surface * dst, const SDL_Rect * rect,
123 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
124 {
125 SDL_PixelFormat *fmt = dst->format;
126 unsigned inva = 0xff - a;
127
128 switch (fmt->BytesPerPixel) {
129 case 2:
130 switch (blendMode) {
131 case SDL_BLENDMODE_BLEND:
132 FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB);
133 break;
134 case SDL_BLENDMODE_ADD:
135 FILLRECT(Uint16, DRAW_SETPIXEL_ADD_RGB);
136 break;
137 case SDL_BLENDMODE_MOD:
138 FILLRECT(Uint16, DRAW_SETPIXEL_MOD_RGB);
139 break;
140 default:
141 FILLRECT(Uint16, DRAW_SETPIXEL_RGB);
142 break;
143 }
144 return 0;
145 case 4:
146 switch (blendMode) {
147 case SDL_BLENDMODE_BLEND:
148 FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGB);
149 break;
150 case SDL_BLENDMODE_ADD:
151 FILLRECT(Uint32, DRAW_SETPIXEL_ADD_RGB);
152 break;
153 case SDL_BLENDMODE_MOD:
154 FILLRECT(Uint32, DRAW_SETPIXEL_MOD_RGB);
155 break;
156 default:
157 FILLRECT(Uint32, DRAW_SETPIXEL_RGB);
158 break;
159 }
160 return 0;
161 default:
162 return SDL_Unsupported();
163 }
164 }
165
166 static int
SDL_BlendFillRect_RGBA(SDL_Surface * dst,const SDL_Rect * rect,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)167 SDL_BlendFillRect_RGBA(SDL_Surface * dst, const SDL_Rect * rect,
168 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
169 {
170 SDL_PixelFormat *fmt = dst->format;
171 unsigned inva = 0xff - a;
172
173 switch (fmt->BytesPerPixel) {
174 case 4:
175 switch (blendMode) {
176 case SDL_BLENDMODE_BLEND:
177 FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGBA);
178 break;
179 case SDL_BLENDMODE_ADD:
180 FILLRECT(Uint32, DRAW_SETPIXEL_ADD_RGBA);
181 break;
182 case SDL_BLENDMODE_MOD:
183 FILLRECT(Uint32, DRAW_SETPIXEL_MOD_RGBA);
184 break;
185 default:
186 FILLRECT(Uint32, DRAW_SETPIXEL_RGBA);
187 break;
188 }
189 return 0;
190 default:
191 return SDL_Unsupported();
192 }
193 }
194
195 int
SDL_BlendFillRect(SDL_Surface * dst,const SDL_Rect * rect,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)196 SDL_BlendFillRect(SDL_Surface * dst, const SDL_Rect * rect,
197 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
198 {
199 SDL_Rect clipped;
200
201 if (!dst) {
202 return SDL_SetError("Passed NULL destination surface");
203 }
204
205 /* This function doesn't work on surfaces < 8 bpp */
206 if (dst->format->BitsPerPixel < 8) {
207 return SDL_SetError("SDL_BlendFillRect(): Unsupported surface format");
208 }
209
210 /* If 'rect' == NULL, then fill the whole surface */
211 if (rect) {
212 /* Perform clipping */
213 if (!SDL_IntersectRect(rect, &dst->clip_rect, &clipped)) {
214 return 0;
215 }
216 rect = &clipped;
217 } else {
218 rect = &dst->clip_rect;
219 }
220
221 if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
222 r = DRAW_MUL(r, a);
223 g = DRAW_MUL(g, a);
224 b = DRAW_MUL(b, a);
225 }
226
227 switch (dst->format->BitsPerPixel) {
228 case 15:
229 switch (dst->format->Rmask) {
230 case 0x7C00:
231 return SDL_BlendFillRect_RGB555(dst, rect, blendMode, r, g, b, a);
232 }
233 break;
234 case 16:
235 switch (dst->format->Rmask) {
236 case 0xF800:
237 return SDL_BlendFillRect_RGB565(dst, rect, blendMode, r, g, b, a);
238 }
239 break;
240 case 32:
241 switch (dst->format->Rmask) {
242 case 0x00FF0000:
243 if (!dst->format->Amask) {
244 return SDL_BlendFillRect_RGB888(dst, rect, blendMode, r, g, b, a);
245 } else {
246 return SDL_BlendFillRect_ARGB8888(dst, rect, blendMode, r, g, b, a);
247 }
248 /* break; -Wunreachable-code-break */
249 }
250 break;
251 default:
252 break;
253 }
254
255 if (!dst->format->Amask) {
256 return SDL_BlendFillRect_RGB(dst, rect, blendMode, r, g, b, a);
257 } else {
258 return SDL_BlendFillRect_RGBA(dst, rect, blendMode, r, g, b, a);
259 }
260 }
261
262 int
SDL_BlendFillRects(SDL_Surface * dst,const SDL_Rect * rects,int count,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)263 SDL_BlendFillRects(SDL_Surface * dst, const SDL_Rect * rects, int count,
264 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
265 {
266 SDL_Rect rect;
267 int i;
268 int (*func)(SDL_Surface * dst, const SDL_Rect * rect,
269 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) = NULL;
270 int status = 0;
271
272 if (!dst) {
273 return SDL_SetError("Passed NULL destination surface");
274 }
275
276 /* This function doesn't work on surfaces < 8 bpp */
277 if (dst->format->BitsPerPixel < 8) {
278 return SDL_SetError("SDL_BlendFillRects(): Unsupported surface format");
279 }
280
281 if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
282 r = DRAW_MUL(r, a);
283 g = DRAW_MUL(g, a);
284 b = DRAW_MUL(b, a);
285 }
286
287 /* FIXME: Does this function pointer slow things down significantly? */
288 switch (dst->format->BitsPerPixel) {
289 case 15:
290 switch (dst->format->Rmask) {
291 case 0x7C00:
292 func = SDL_BlendFillRect_RGB555;
293 }
294 break;
295 case 16:
296 switch (dst->format->Rmask) {
297 case 0xF800:
298 func = SDL_BlendFillRect_RGB565;
299 }
300 break;
301 case 32:
302 switch (dst->format->Rmask) {
303 case 0x00FF0000:
304 if (!dst->format->Amask) {
305 func = SDL_BlendFillRect_RGB888;
306 } else {
307 func = SDL_BlendFillRect_ARGB8888;
308 }
309 break;
310 }
311 break;
312 default:
313 break;
314 }
315
316 if (!func) {
317 if (!dst->format->Amask) {
318 func = SDL_BlendFillRect_RGB;
319 } else {
320 func = SDL_BlendFillRect_RGBA;
321 }
322 }
323
324 for (i = 0; i < count; ++i) {
325 /* Perform clipping */
326 if (!SDL_IntersectRect(&rects[i], &dst->clip_rect, &rect)) {
327 continue;
328 }
329 status = func(dst, &rect, blendMode, r, g, b, a);
330 }
331 return status;
332 }
333
334 #endif /* !SDL_RENDER_DISABLED */
335
336 /* vi: set ts=4 sw=4 expandtab: */
337