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_blendpoint.h"
27 
28 
29 static int
SDL_BlendPoint_RGB555(SDL_Surface * dst,int x,int y,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)30 SDL_BlendPoint_RGB555(SDL_Surface * dst, int x, int y, SDL_BlendMode blendMode, Uint8 r,
31                       Uint8 g, Uint8 b, Uint8 a)
32 {
33     unsigned inva = 0xff - a;
34 
35     switch (blendMode) {
36     case SDL_BLENDMODE_BLEND:
37         DRAW_SETPIXELXY_BLEND_RGB555(x, y);
38         break;
39     case SDL_BLENDMODE_ADD:
40         DRAW_SETPIXELXY_ADD_RGB555(x, y);
41         break;
42     case SDL_BLENDMODE_MOD:
43         DRAW_SETPIXELXY_MOD_RGB555(x, y);
44         break;
45     case SDL_BLENDMODE_MUL:
46         DRAW_SETPIXELXY_MUL_RGB555(x, y);
47         break;
48     default:
49         DRAW_SETPIXELXY_RGB555(x, y);
50         break;
51     }
52     return 0;
53 }
54 
55 static int
SDL_BlendPoint_RGB565(SDL_Surface * dst,int x,int y,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)56 SDL_BlendPoint_RGB565(SDL_Surface * dst, int x, int y, SDL_BlendMode blendMode, Uint8 r,
57                       Uint8 g, Uint8 b, Uint8 a)
58 {
59     unsigned inva = 0xff - a;
60 
61     switch (blendMode) {
62     case SDL_BLENDMODE_BLEND:
63         DRAW_SETPIXELXY_BLEND_RGB565(x, y);
64         break;
65     case SDL_BLENDMODE_ADD:
66         DRAW_SETPIXELXY_ADD_RGB565(x, y);
67         break;
68     case SDL_BLENDMODE_MOD:
69         DRAW_SETPIXELXY_MOD_RGB565(x, y);
70         break;
71     case SDL_BLENDMODE_MUL:
72         DRAW_SETPIXELXY_MUL_RGB565(x, y);
73         break;
74     default:
75         DRAW_SETPIXELXY_RGB565(x, y);
76         break;
77     }
78     return 0;
79 }
80 
81 static int
SDL_BlendPoint_RGB888(SDL_Surface * dst,int x,int y,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)82 SDL_BlendPoint_RGB888(SDL_Surface * dst, int x, int y, SDL_BlendMode blendMode, Uint8 r,
83                       Uint8 g, Uint8 b, Uint8 a)
84 {
85     unsigned inva = 0xff - a;
86 
87     switch (blendMode) {
88     case SDL_BLENDMODE_BLEND:
89         DRAW_SETPIXELXY_BLEND_RGB888(x, y);
90         break;
91     case SDL_BLENDMODE_ADD:
92         DRAW_SETPIXELXY_ADD_RGB888(x, y);
93         break;
94     case SDL_BLENDMODE_MOD:
95         DRAW_SETPIXELXY_MOD_RGB888(x, y);
96         break;
97     case SDL_BLENDMODE_MUL:
98         DRAW_SETPIXELXY_MUL_RGB888(x, y);
99         break;
100     default:
101         DRAW_SETPIXELXY_RGB888(x, y);
102         break;
103     }
104     return 0;
105 }
106 
107 static int
SDL_BlendPoint_ARGB8888(SDL_Surface * dst,int x,int y,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)108 SDL_BlendPoint_ARGB8888(SDL_Surface * dst, int x, int y, SDL_BlendMode blendMode,
109                         Uint8 r, Uint8 g, Uint8 b, Uint8 a)
110 {
111     unsigned inva = 0xff - a;
112 
113     switch (blendMode) {
114     case SDL_BLENDMODE_BLEND:
115         DRAW_SETPIXELXY_BLEND_ARGB8888(x, y);
116         break;
117     case SDL_BLENDMODE_ADD:
118         DRAW_SETPIXELXY_ADD_ARGB8888(x, y);
119         break;
120     case SDL_BLENDMODE_MOD:
121         DRAW_SETPIXELXY_MOD_ARGB8888(x, y);
122         break;
123     case SDL_BLENDMODE_MUL:
124         DRAW_SETPIXELXY_MUL_ARGB8888(x, y);
125         break;
126     default:
127         DRAW_SETPIXELXY_ARGB8888(x, y);
128         break;
129     }
130     return 0;
131 }
132 
133 static int
SDL_BlendPoint_RGB(SDL_Surface * dst,int x,int y,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)134 SDL_BlendPoint_RGB(SDL_Surface * dst, int x, int y, SDL_BlendMode blendMode, Uint8 r,
135                    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             DRAW_SETPIXELXY2_BLEND_RGB(x, y);
145             break;
146         case SDL_BLENDMODE_ADD:
147             DRAW_SETPIXELXY2_ADD_RGB(x, y);
148             break;
149         case SDL_BLENDMODE_MOD:
150             DRAW_SETPIXELXY2_MOD_RGB(x, y);
151             break;
152         case SDL_BLENDMODE_MUL:
153             DRAW_SETPIXELXY2_MUL_RGB(x, y);
154             break;
155         default:
156             DRAW_SETPIXELXY2_RGB(x, y);
157             break;
158         }
159         return 0;
160     case 4:
161         switch (blendMode) {
162         case SDL_BLENDMODE_BLEND:
163             DRAW_SETPIXELXY4_BLEND_RGB(x, y);
164             break;
165         case SDL_BLENDMODE_ADD:
166             DRAW_SETPIXELXY4_ADD_RGB(x, y);
167             break;
168         case SDL_BLENDMODE_MOD:
169             DRAW_SETPIXELXY4_MOD_RGB(x, y);
170             break;
171         case SDL_BLENDMODE_MUL:
172             DRAW_SETPIXELXY4_MUL_RGB(x, y);
173             break;
174         default:
175             DRAW_SETPIXELXY4_RGB(x, y);
176             break;
177         }
178         return 0;
179     default:
180         return SDL_Unsupported();
181     }
182 }
183 
184 static int
SDL_BlendPoint_RGBA(SDL_Surface * dst,int x,int y,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)185 SDL_BlendPoint_RGBA(SDL_Surface * dst, int x, int y, SDL_BlendMode blendMode, Uint8 r,
186                     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             DRAW_SETPIXELXY4_BLEND_RGBA(x, y);
196             break;
197         case SDL_BLENDMODE_ADD:
198             DRAW_SETPIXELXY4_ADD_RGBA(x, y);
199             break;
200         case SDL_BLENDMODE_MOD:
201             DRAW_SETPIXELXY4_MOD_RGBA(x, y);
202             break;
203         case SDL_BLENDMODE_MUL:
204             DRAW_SETPIXELXY4_MUL_RGBA(x, y);
205             break;
206         default:
207             DRAW_SETPIXELXY4_RGBA(x, y);
208             break;
209         }
210         return 0;
211     default:
212         return SDL_Unsupported();
213     }
214 }
215 
216 int
SDL_BlendPoint(SDL_Surface * dst,int x,int y,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)217 SDL_BlendPoint(SDL_Surface * dst, int x, int y, SDL_BlendMode blendMode, Uint8 r,
218                Uint8 g, Uint8 b, Uint8 a)
219 {
220     if (!dst) {
221         return SDL_SetError("Passed NULL destination surface");
222     }
223 
224     /* This function doesn't work on surfaces < 8 bpp */
225     if (dst->format->BitsPerPixel < 8) {
226         return SDL_SetError("SDL_BlendPoint(): Unsupported surface format");
227     }
228 
229     /* Perform clipping */
230     if (x < dst->clip_rect.x || y < dst->clip_rect.y ||
231         x >= (dst->clip_rect.x + dst->clip_rect.w) ||
232         y >= (dst->clip_rect.y + dst->clip_rect.h)) {
233         return 0;
234     }
235 
236     if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
237         r = DRAW_MUL(r, a);
238         g = DRAW_MUL(g, a);
239         b = DRAW_MUL(b, a);
240     }
241 
242     switch (dst->format->BitsPerPixel) {
243     case 15:
244         switch (dst->format->Rmask) {
245         case 0x7C00:
246             return SDL_BlendPoint_RGB555(dst, x, y, blendMode, r, g, b, a);
247         }
248         break;
249     case 16:
250         switch (dst->format->Rmask) {
251         case 0xF800:
252             return SDL_BlendPoint_RGB565(dst, x, y, blendMode, r, g, b, a);
253         }
254         break;
255     case 32:
256         switch (dst->format->Rmask) {
257         case 0x00FF0000:
258             if (!dst->format->Amask) {
259                 return SDL_BlendPoint_RGB888(dst, x, y, blendMode, r, g, b, a);
260             } else {
261                 return SDL_BlendPoint_ARGB8888(dst, x, y, blendMode, r, g, b, a);
262             }
263             /* break; -Wunreachable-code-break */
264         }
265         break;
266     default:
267         break;
268     }
269 
270     if (!dst->format->Amask) {
271         return SDL_BlendPoint_RGB(dst, x, y, blendMode, r, g, b, a);
272     } else {
273         return SDL_BlendPoint_RGBA(dst, x, y, blendMode, r, g, b, a);
274     }
275 }
276 
277 int
SDL_BlendPoints(SDL_Surface * dst,const SDL_Point * points,int count,SDL_BlendMode blendMode,Uint8 r,Uint8 g,Uint8 b,Uint8 a)278 SDL_BlendPoints(SDL_Surface * dst, const SDL_Point * points, int count,
279                 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
280 {
281     int minx, miny;
282     int maxx, maxy;
283     int i;
284     int x, y;
285     int (*func)(SDL_Surface * dst, int x, int y,
286                 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) = NULL;
287     int status = 0;
288 
289     if (!dst) {
290         return SDL_SetError("Passed NULL destination surface");
291     }
292 
293     /* This function doesn't work on surfaces < 8 bpp */
294     if (dst->format->BitsPerPixel < 8) {
295         return SDL_SetError("SDL_BlendPoints(): Unsupported surface format");
296     }
297 
298     if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
299         r = DRAW_MUL(r, a);
300         g = DRAW_MUL(g, a);
301         b = DRAW_MUL(b, a);
302     }
303 
304     /* FIXME: Does this function pointer slow things down significantly? */
305     switch (dst->format->BitsPerPixel) {
306     case 15:
307         switch (dst->format->Rmask) {
308         case 0x7C00:
309             func = SDL_BlendPoint_RGB555;
310             break;
311         }
312         break;
313     case 16:
314         switch (dst->format->Rmask) {
315         case 0xF800:
316             func = SDL_BlendPoint_RGB565;
317             break;
318         }
319         break;
320     case 32:
321         switch (dst->format->Rmask) {
322         case 0x00FF0000:
323             if (!dst->format->Amask) {
324                 func = SDL_BlendPoint_RGB888;
325             } else {
326                 func = SDL_BlendPoint_ARGB8888;
327             }
328             break;
329         }
330         break;
331     default:
332         break;
333     }
334 
335     if (!func) {
336         if (!dst->format->Amask) {
337             func = SDL_BlendPoint_RGB;
338         } else {
339             func = SDL_BlendPoint_RGBA;
340         }
341     }
342 
343     minx = dst->clip_rect.x;
344     maxx = dst->clip_rect.x + dst->clip_rect.w - 1;
345     miny = dst->clip_rect.y;
346     maxy = dst->clip_rect.y + dst->clip_rect.h - 1;
347 
348     for (i = 0; i < count; ++i) {
349         x = points[i].x;
350         y = points[i].y;
351 
352         if (x < minx || x > maxx || y < miny || y > maxy) {
353             continue;
354         }
355         status = func(dst, x, y, blendMode, r, g, b, a);
356     }
357     return status;
358 }
359 
360 #endif /* SDL_VIDEO_RENDER_SW && !SDL_RENDER_DISABLED */
361 
362 /* vi: set ts=4 sw=4 expandtab: */
363