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_blendfillrect.h" |
27 | |
28 | |
29 | static int |
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 | case SDL_BLENDMODE_MUL: |
46 | FILLRECT(Uint16, DRAW_SETPIXEL_MUL_RGB555); |
47 | break; |
48 | default: |
49 | FILLRECT(Uint16, DRAW_SETPIXEL_RGB555); |
50 | break; |
51 | } |
52 | return 0; |
53 | } |
54 | |
55 | static int |
56 | SDL_BlendFillRect_RGB565(SDL_Surface * dst, const SDL_Rect * rect, |
57 | SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) |
58 | { |
59 | unsigned inva = 0xff - a; |
60 | |
61 | switch (blendMode) { |
62 | case SDL_BLENDMODE_BLEND: |
63 | FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB565); |
64 | break; |
65 | case SDL_BLENDMODE_ADD: |
66 | FILLRECT(Uint16, DRAW_SETPIXEL_ADD_RGB565); |
67 | break; |
68 | case SDL_BLENDMODE_MOD: |
69 | FILLRECT(Uint16, DRAW_SETPIXEL_MOD_RGB565); |
70 | break; |
71 | case SDL_BLENDMODE_MUL: |
72 | FILLRECT(Uint16, DRAW_SETPIXEL_MUL_RGB565); |
73 | break; |
74 | default: |
75 | FILLRECT(Uint16, DRAW_SETPIXEL_RGB565); |
76 | break; |
77 | } |
78 | return 0; |
79 | } |
80 | |
81 | static int |
82 | SDL_BlendFillRect_RGB888(SDL_Surface * dst, const SDL_Rect * rect, |
83 | SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) |
84 | { |
85 | unsigned inva = 0xff - a; |
86 | |
87 | switch (blendMode) { |
88 | case SDL_BLENDMODE_BLEND: |
89 | FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGB888); |
90 | break; |
91 | case SDL_BLENDMODE_ADD: |
92 | FILLRECT(Uint32, DRAW_SETPIXEL_ADD_RGB888); |
93 | break; |
94 | case SDL_BLENDMODE_MOD: |
95 | FILLRECT(Uint32, DRAW_SETPIXEL_MOD_RGB888); |
96 | break; |
97 | case SDL_BLENDMODE_MUL: |
98 | FILLRECT(Uint32, DRAW_SETPIXEL_MUL_RGB888); |
99 | break; |
100 | default: |
101 | FILLRECT(Uint32, DRAW_SETPIXEL_RGB888); |
102 | break; |
103 | } |
104 | return 0; |
105 | } |
106 | |
107 | static int |
108 | SDL_BlendFillRect_ARGB8888(SDL_Surface * dst, const SDL_Rect * rect, |
109 | SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) |
110 | { |
111 | unsigned inva = 0xff - a; |
112 | |
113 | switch (blendMode) { |
114 | case SDL_BLENDMODE_BLEND: |
115 | FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888); |
116 | break; |
117 | case SDL_BLENDMODE_ADD: |
118 | FILLRECT(Uint32, DRAW_SETPIXEL_ADD_ARGB8888); |
119 | break; |
120 | case SDL_BLENDMODE_MOD: |
121 | FILLRECT(Uint32, DRAW_SETPIXEL_MOD_ARGB8888); |
122 | break; |
123 | case SDL_BLENDMODE_MUL: |
124 | FILLRECT(Uint32, DRAW_SETPIXEL_MUL_ARGB8888); |
125 | break; |
126 | default: |
127 | FILLRECT(Uint32, DRAW_SETPIXEL_ARGB8888); |
128 | break; |
129 | } |
130 | return 0; |
131 | } |
132 | |
133 | static int |
134 | SDL_BlendFillRect_RGB(SDL_Surface * dst, const SDL_Rect * rect, |
135 | SDL_BlendMode blendMode, Uint8 r, 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 | FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB); |
145 | break; |
146 | case SDL_BLENDMODE_ADD: |
147 | FILLRECT(Uint16, DRAW_SETPIXEL_ADD_RGB); |
148 | break; |
149 | case SDL_BLENDMODE_MOD: |
150 | FILLRECT(Uint16, DRAW_SETPIXEL_MOD_RGB); |
151 | break; |
152 | case SDL_BLENDMODE_MUL: |
153 | FILLRECT(Uint16, DRAW_SETPIXEL_MUL_RGB); |
154 | break; |
155 | default: |
156 | FILLRECT(Uint16, DRAW_SETPIXEL_RGB); |
157 | break; |
158 | } |
159 | return 0; |
160 | case 4: |
161 | switch (blendMode) { |
162 | case SDL_BLENDMODE_BLEND: |
163 | FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGB); |
164 | break; |
165 | case SDL_BLENDMODE_ADD: |
166 | FILLRECT(Uint32, DRAW_SETPIXEL_ADD_RGB); |
167 | break; |
168 | case SDL_BLENDMODE_MOD: |
169 | FILLRECT(Uint32, DRAW_SETPIXEL_MOD_RGB); |
170 | break; |
171 | case SDL_BLENDMODE_MUL: |
172 | FILLRECT(Uint32, DRAW_SETPIXEL_MUL_RGB); |
173 | break; |
174 | default: |
175 | FILLRECT(Uint32, DRAW_SETPIXEL_RGB); |
176 | break; |
177 | } |
178 | return 0; |
179 | default: |
180 | return SDL_Unsupported(); |
181 | } |
182 | } |
183 | |
184 | static int |
185 | SDL_BlendFillRect_RGBA(SDL_Surface * dst, const SDL_Rect * rect, |
186 | SDL_BlendMode blendMode, Uint8 r, 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 | FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGBA); |
196 | break; |
197 | case SDL_BLENDMODE_ADD: |
198 | FILLRECT(Uint32, DRAW_SETPIXEL_ADD_RGBA); |
199 | break; |
200 | case SDL_BLENDMODE_MOD: |
201 | FILLRECT(Uint32, DRAW_SETPIXEL_MOD_RGBA); |
202 | break; |
203 | case SDL_BLENDMODE_MUL: |
204 | FILLRECT(Uint32, DRAW_SETPIXEL_MUL_RGBA); |
205 | break; |
206 | default: |
207 | FILLRECT(Uint32, DRAW_SETPIXEL_RGBA); |
208 | break; |
209 | } |
210 | return 0; |
211 | default: |
212 | return SDL_Unsupported(); |
213 | } |
214 | } |
215 | |
216 | int |
217 | SDL_BlendFillRect(SDL_Surface * dst, const SDL_Rect * rect, |
218 | SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) |
219 | { |
220 | SDL_Rect clipped; |
221 | |
222 | if (!dst) { |
223 | return SDL_SetError("Passed NULL destination surface" ); |
224 | } |
225 | |
226 | /* This function doesn't work on surfaces < 8 bpp */ |
227 | if (dst->format->BitsPerPixel < 8) { |
228 | return SDL_SetError("SDL_BlendFillRect(): Unsupported surface format" ); |
229 | } |
230 | |
231 | /* If 'rect' == NULL, then fill the whole surface */ |
232 | if (rect) { |
233 | /* Perform clipping */ |
234 | if (!SDL_IntersectRect(rect, &dst->clip_rect, &clipped)) { |
235 | return 0; |
236 | } |
237 | rect = &clipped; |
238 | } else { |
239 | rect = &dst->clip_rect; |
240 | } |
241 | |
242 | if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) { |
243 | r = DRAW_MUL(r, a); |
244 | g = DRAW_MUL(g, a); |
245 | b = DRAW_MUL(b, a); |
246 | } |
247 | |
248 | switch (dst->format->BitsPerPixel) { |
249 | case 15: |
250 | switch (dst->format->Rmask) { |
251 | case 0x7C00: |
252 | return SDL_BlendFillRect_RGB555(dst, rect, blendMode, r, g, b, a); |
253 | } |
254 | break; |
255 | case 16: |
256 | switch (dst->format->Rmask) { |
257 | case 0xF800: |
258 | return SDL_BlendFillRect_RGB565(dst, rect, blendMode, r, g, b, a); |
259 | } |
260 | break; |
261 | case 32: |
262 | switch (dst->format->Rmask) { |
263 | case 0x00FF0000: |
264 | if (!dst->format->Amask) { |
265 | return SDL_BlendFillRect_RGB888(dst, rect, blendMode, r, g, b, a); |
266 | } else { |
267 | return SDL_BlendFillRect_ARGB8888(dst, rect, blendMode, r, g, b, a); |
268 | } |
269 | /* break; -Wunreachable-code-break */ |
270 | } |
271 | break; |
272 | default: |
273 | break; |
274 | } |
275 | |
276 | if (!dst->format->Amask) { |
277 | return SDL_BlendFillRect_RGB(dst, rect, blendMode, r, g, b, a); |
278 | } else { |
279 | return SDL_BlendFillRect_RGBA(dst, rect, blendMode, r, g, b, a); |
280 | } |
281 | } |
282 | |
283 | int |
284 | SDL_BlendFillRects(SDL_Surface * dst, const SDL_Rect * rects, int count, |
285 | SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) |
286 | { |
287 | SDL_Rect rect; |
288 | int i; |
289 | int (*func)(SDL_Surface * dst, const SDL_Rect * rect, |
290 | SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) = NULL; |
291 | int status = 0; |
292 | |
293 | if (!dst) { |
294 | return SDL_SetError("Passed NULL destination surface" ); |
295 | } |
296 | |
297 | /* This function doesn't work on surfaces < 8 bpp */ |
298 | if (dst->format->BitsPerPixel < 8) { |
299 | return SDL_SetError("SDL_BlendFillRects(): Unsupported surface format" ); |
300 | } |
301 | |
302 | if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) { |
303 | r = DRAW_MUL(r, a); |
304 | g = DRAW_MUL(g, a); |
305 | b = DRAW_MUL(b, a); |
306 | } |
307 | |
308 | /* FIXME: Does this function pointer slow things down significantly? */ |
309 | switch (dst->format->BitsPerPixel) { |
310 | case 15: |
311 | switch (dst->format->Rmask) { |
312 | case 0x7C00: |
313 | func = SDL_BlendFillRect_RGB555; |
314 | } |
315 | break; |
316 | case 16: |
317 | switch (dst->format->Rmask) { |
318 | case 0xF800: |
319 | func = SDL_BlendFillRect_RGB565; |
320 | } |
321 | break; |
322 | case 32: |
323 | switch (dst->format->Rmask) { |
324 | case 0x00FF0000: |
325 | if (!dst->format->Amask) { |
326 | func = SDL_BlendFillRect_RGB888; |
327 | } else { |
328 | func = SDL_BlendFillRect_ARGB8888; |
329 | } |
330 | break; |
331 | } |
332 | break; |
333 | default: |
334 | break; |
335 | } |
336 | |
337 | if (!func) { |
338 | if (!dst->format->Amask) { |
339 | func = SDL_BlendFillRect_RGB; |
340 | } else { |
341 | func = SDL_BlendFillRect_RGBA; |
342 | } |
343 | } |
344 | |
345 | for (i = 0; i < count; ++i) { |
346 | /* Perform clipping */ |
347 | if (!SDL_IntersectRect(&rects[i], &dst->clip_rect, &rect)) { |
348 | continue; |
349 | } |
350 | status = func(dst, &rect, blendMode, r, g, b, a); |
351 | } |
352 | return status; |
353 | } |
354 | |
355 | #endif /* SDL_VIDEO_RENDER_SW && !SDL_RENDER_DISABLED */ |
356 | |
357 | /* vi: set ts=4 sw=4 expandtab: */ |
358 | |