1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2020 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 
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     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 
55 static int
SDL_BlendFillRect_RGB565(SDL_Surface * dst,const SDL_Rect * rect,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)56 SDL_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 
81 static int
SDL_BlendFillRect_RGB888(SDL_Surface * dst,const SDL_Rect * rect,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)82 SDL_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 
107 static int
SDL_BlendFillRect_ARGB8888(SDL_Surface * dst,const SDL_Rect * rect,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)108 SDL_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 
133 static int
SDL_BlendFillRect_RGB(SDL_Surface * dst,const SDL_Rect * rect,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)134 SDL_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 
184 static int
SDL_BlendFillRect_RGBA(SDL_Surface * dst,const SDL_Rect * rect,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)185 SDL_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 
216 int
SDL_BlendFillRect(SDL_Surface * dst,const SDL_Rect * rect,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)217 SDL_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 
283 int
SDL_BlendFillRects(SDL_Surface * dst,const SDL_Rect * rects,int count,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)284 SDL_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