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