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
29static int
30SDL_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
55static int
56SDL_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
81static int
82SDL_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
107static int
108SDL_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
133static int
134SDL_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
184static int
185SDL_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
216int
217SDL_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
277int
278SDL_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