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