1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2021 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_VIDEO_RENDER_SW && !SDL_RENDER_DISABLED
24
25#include "SDL_draw.h"
26#include "SDL_blendfillrect.h"
27
28
29static int
30SDL_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 case SDL_BLENDMODE_MUL:
46 FILLRECT(Uint16, DRAW_SETPIXEL_MUL_RGB555);
47 break;
48 default:
49 FILLRECT(Uint16, DRAW_SETPIXEL_RGB555);
50 break;
51 }
52 return 0;
53}
54
55static int
56SDL_BlendFillRect_RGB565(SDL_Surface * dst, const SDL_Rect * rect,
57 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
58{
59 unsigned inva = 0xff - a;
60
61 switch (blendMode) {
62 case SDL_BLENDMODE_BLEND:
63 FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB565);
64 break;
65 case SDL_BLENDMODE_ADD:
66 FILLRECT(Uint16, DRAW_SETPIXEL_ADD_RGB565);
67 break;
68 case SDL_BLENDMODE_MOD:
69 FILLRECT(Uint16, DRAW_SETPIXEL_MOD_RGB565);
70 break;
71 case SDL_BLENDMODE_MUL:
72 FILLRECT(Uint16, DRAW_SETPIXEL_MUL_RGB565);
73 break;
74 default:
75 FILLRECT(Uint16, DRAW_SETPIXEL_RGB565);
76 break;
77 }
78 return 0;
79}
80
81static int
82SDL_BlendFillRect_RGB888(SDL_Surface * dst, const SDL_Rect * rect,
83 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
84{
85 unsigned inva = 0xff - a;
86
87 switch (blendMode) {
88 case SDL_BLENDMODE_BLEND:
89 FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGB888);
90 break;
91 case SDL_BLENDMODE_ADD:
92 FILLRECT(Uint32, DRAW_SETPIXEL_ADD_RGB888);
93 break;
94 case SDL_BLENDMODE_MOD:
95 FILLRECT(Uint32, DRAW_SETPIXEL_MOD_RGB888);
96 break;
97 case SDL_BLENDMODE_MUL:
98 FILLRECT(Uint32, DRAW_SETPIXEL_MUL_RGB888);
99 break;
100 default:
101 FILLRECT(Uint32, DRAW_SETPIXEL_RGB888);
102 break;
103 }
104 return 0;
105}
106
107static int
108SDL_BlendFillRect_ARGB8888(SDL_Surface * dst, const SDL_Rect * rect,
109 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
110{
111 unsigned inva = 0xff - a;
112
113 switch (blendMode) {
114 case SDL_BLENDMODE_BLEND:
115 FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888);
116 break;
117 case SDL_BLENDMODE_ADD:
118 FILLRECT(Uint32, DRAW_SETPIXEL_ADD_ARGB8888);
119 break;
120 case SDL_BLENDMODE_MOD:
121 FILLRECT(Uint32, DRAW_SETPIXEL_MOD_ARGB8888);
122 break;
123 case SDL_BLENDMODE_MUL:
124 FILLRECT(Uint32, DRAW_SETPIXEL_MUL_ARGB8888);
125 break;
126 default:
127 FILLRECT(Uint32, DRAW_SETPIXEL_ARGB8888);
128 break;
129 }
130 return 0;
131}
132
133static int
134SDL_BlendFillRect_RGB(SDL_Surface * dst, const SDL_Rect * rect,
135 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
136{
137 SDL_PixelFormat *fmt = dst->format;
138 unsigned inva = 0xff - a;
139
140 switch (fmt->BytesPerPixel) {
141 case 2:
142 switch (blendMode) {
143 case SDL_BLENDMODE_BLEND:
144 FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB);
145 break;
146 case SDL_BLENDMODE_ADD:
147 FILLRECT(Uint16, DRAW_SETPIXEL_ADD_RGB);
148 break;
149 case SDL_BLENDMODE_MOD:
150 FILLRECT(Uint16, DRAW_SETPIXEL_MOD_RGB);
151 break;
152 case SDL_BLENDMODE_MUL:
153 FILLRECT(Uint16, DRAW_SETPIXEL_MUL_RGB);
154 break;
155 default:
156 FILLRECT(Uint16, DRAW_SETPIXEL_RGB);
157 break;
158 }
159 return 0;
160 case 4:
161 switch (blendMode) {
162 case SDL_BLENDMODE_BLEND:
163 FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGB);
164 break;
165 case SDL_BLENDMODE_ADD:
166 FILLRECT(Uint32, DRAW_SETPIXEL_ADD_RGB);
167 break;
168 case SDL_BLENDMODE_MOD:
169 FILLRECT(Uint32, DRAW_SETPIXEL_MOD_RGB);
170 break;
171 case SDL_BLENDMODE_MUL:
172 FILLRECT(Uint32, DRAW_SETPIXEL_MUL_RGB);
173 break;
174 default:
175 FILLRECT(Uint32, DRAW_SETPIXEL_RGB);
176 break;
177 }
178 return 0;
179 default:
180 return SDL_Unsupported();
181 }
182}
183
184static int
185SDL_BlendFillRect_RGBA(SDL_Surface * dst, const SDL_Rect * rect,
186 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
187{
188 SDL_PixelFormat *fmt = dst->format;
189 unsigned inva = 0xff - a;
190
191 switch (fmt->BytesPerPixel) {
192 case 4:
193 switch (blendMode) {
194 case SDL_BLENDMODE_BLEND:
195 FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGBA);
196 break;
197 case SDL_BLENDMODE_ADD:
198 FILLRECT(Uint32, DRAW_SETPIXEL_ADD_RGBA);
199 break;
200 case SDL_BLENDMODE_MOD:
201 FILLRECT(Uint32, DRAW_SETPIXEL_MOD_RGBA);
202 break;
203 case SDL_BLENDMODE_MUL:
204 FILLRECT(Uint32, DRAW_SETPIXEL_MUL_RGBA);
205 break;
206 default:
207 FILLRECT(Uint32, DRAW_SETPIXEL_RGBA);
208 break;
209 }
210 return 0;
211 default:
212 return SDL_Unsupported();
213 }
214}
215
216int
217SDL_BlendFillRect(SDL_Surface * dst, const SDL_Rect * rect,
218 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
219{
220 SDL_Rect clipped;
221
222 if (!dst) {
223 return SDL_SetError("Passed NULL destination surface");
224 }
225
226 /* This function doesn't work on surfaces < 8 bpp */
227 if (dst->format->BitsPerPixel < 8) {
228 return SDL_SetError("SDL_BlendFillRect(): Unsupported surface format");
229 }
230
231 /* If 'rect' == NULL, then fill the whole surface */
232 if (rect) {
233 /* Perform clipping */
234 if (!SDL_IntersectRect(rect, &dst->clip_rect, &clipped)) {
235 return 0;
236 }
237 rect = &clipped;
238 } else {
239 rect = &dst->clip_rect;
240 }
241
242 if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
243 r = DRAW_MUL(r, a);
244 g = DRAW_MUL(g, a);
245 b = DRAW_MUL(b, a);
246 }
247
248 switch (dst->format->BitsPerPixel) {
249 case 15:
250 switch (dst->format->Rmask) {
251 case 0x7C00:
252 return SDL_BlendFillRect_RGB555(dst, rect, blendMode, r, g, b, a);
253 }
254 break;
255 case 16:
256 switch (dst->format->Rmask) {
257 case 0xF800:
258 return SDL_BlendFillRect_RGB565(dst, rect, blendMode, r, g, b, a);
259 }
260 break;
261 case 32:
262 switch (dst->format->Rmask) {
263 case 0x00FF0000:
264 if (!dst->format->Amask) {
265 return SDL_BlendFillRect_RGB888(dst, rect, blendMode, r, g, b, a);
266 } else {
267 return SDL_BlendFillRect_ARGB8888(dst, rect, blendMode, r, g, b, a);
268 }
269 /* break; -Wunreachable-code-break */
270 }
271 break;
272 default:
273 break;
274 }
275
276 if (!dst->format->Amask) {
277 return SDL_BlendFillRect_RGB(dst, rect, blendMode, r, g, b, a);
278 } else {
279 return SDL_BlendFillRect_RGBA(dst, rect, blendMode, r, g, b, a);
280 }
281}
282
283int
284SDL_BlendFillRects(SDL_Surface * dst, const SDL_Rect * rects, int count,
285 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
286{
287 SDL_Rect rect;
288 int i;
289 int (*func)(SDL_Surface * dst, const SDL_Rect * rect,
290 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) = NULL;
291 int status = 0;
292
293 if (!dst) {
294 return SDL_SetError("Passed NULL destination surface");
295 }
296
297 /* This function doesn't work on surfaces < 8 bpp */
298 if (dst->format->BitsPerPixel < 8) {
299 return SDL_SetError("SDL_BlendFillRects(): Unsupported surface format");
300 }
301
302 if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
303 r = DRAW_MUL(r, a);
304 g = DRAW_MUL(g, a);
305 b = DRAW_MUL(b, a);
306 }
307
308 /* FIXME: Does this function pointer slow things down significantly? */
309 switch (dst->format->BitsPerPixel) {
310 case 15:
311 switch (dst->format->Rmask) {
312 case 0x7C00:
313 func = SDL_BlendFillRect_RGB555;
314 }
315 break;
316 case 16:
317 switch (dst->format->Rmask) {
318 case 0xF800:
319 func = SDL_BlendFillRect_RGB565;
320 }
321 break;
322 case 32:
323 switch (dst->format->Rmask) {
324 case 0x00FF0000:
325 if (!dst->format->Amask) {
326 func = SDL_BlendFillRect_RGB888;
327 } else {
328 func = SDL_BlendFillRect_ARGB8888;
329 }
330 break;
331 }
332 break;
333 default:
334 break;
335 }
336
337 if (!func) {
338 if (!dst->format->Amask) {
339 func = SDL_BlendFillRect_RGB;
340 } else {
341 func = SDL_BlendFillRect_RGBA;
342 }
343 }
344
345 for (i = 0; i < count; ++i) {
346 /* Perform clipping */
347 if (!SDL_IntersectRect(&rects[i], &dst->clip_rect, &rect)) {
348 continue;
349 }
350 status = func(dst, &rect, blendMode, r, g, b, a);
351 }
352 return status;
353}
354
355#endif /* SDL_VIDEO_RENDER_SW && !SDL_RENDER_DISABLED */
356
357/* vi: set ts=4 sw=4 expandtab: */
358