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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 | |