summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/render/software
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/render/software
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/render/software')
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_blendfillrect.c371
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_blendfillrect.h30
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_blendline.c986
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_blendline.h30
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_blendpoint.c376
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_blendpoint.h30
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_draw.h723
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_drawline.c199
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_drawline.h30
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_drawpoint.c108
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_drawpoint.h30
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_render_sw.c1202
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_render_sw_c.h27
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_rotate.c612
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_rotate.h30
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_triangle.c945
-rw-r--r--contrib/SDL-3.2.8/src/render/software/SDL_triangle.h42
17 files changed, 5771 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_blendfillrect.c b/contrib/SDL-3.2.8/src/render/software/SDL_blendfillrect.c
new file mode 100644
index 0000000..4e5c7f8
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_blendfillrect.c
@@ -0,0 +1,371 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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#ifdef SDL_VIDEO_RENDER_SW
24
25#include "SDL_draw.h"
26#include "SDL_blendfillrect.h"
27
28static bool SDL_BlendFillRect_RGB555(SDL_Surface *dst, const SDL_Rect *rect,
29 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
30{
31 unsigned inva = 0xff - a;
32
33 switch (blendMode) {
34 case SDL_BLENDMODE_BLEND:
35 FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB555);
36 break;
37 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
38 FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB555);
39 break;
40 case SDL_BLENDMODE_ADD:
41 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
42 FILLRECT(Uint16, DRAW_SETPIXEL_ADD_RGB555);
43 break;
44 case SDL_BLENDMODE_MOD:
45 FILLRECT(Uint16, DRAW_SETPIXEL_MOD_RGB555);
46 break;
47 case SDL_BLENDMODE_MUL:
48 FILLRECT(Uint16, DRAW_SETPIXEL_MUL_RGB555);
49 break;
50 default:
51 FILLRECT(Uint16, DRAW_SETPIXEL_RGB555);
52 break;
53 }
54 return true;
55}
56
57static bool SDL_BlendFillRect_RGB565(SDL_Surface *dst, const SDL_Rect *rect,
58 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
59{
60 unsigned inva = 0xff - a;
61
62 switch (blendMode) {
63 case SDL_BLENDMODE_BLEND:
64 FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB565);
65 break;
66 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
67 FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB565);
68 break;
69 case SDL_BLENDMODE_ADD:
70 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
71 FILLRECT(Uint16, DRAW_SETPIXEL_ADD_RGB565);
72 break;
73 case SDL_BLENDMODE_MOD:
74 FILLRECT(Uint16, DRAW_SETPIXEL_MOD_RGB565);
75 break;
76 case SDL_BLENDMODE_MUL:
77 FILLRECT(Uint16, DRAW_SETPIXEL_MUL_RGB565);
78 break;
79 default:
80 FILLRECT(Uint16, DRAW_SETPIXEL_RGB565);
81 break;
82 }
83 return true;
84}
85
86static bool SDL_BlendFillRect_XRGB8888(SDL_Surface *dst, const SDL_Rect *rect,
87 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
88{
89 unsigned inva = 0xff - a;
90
91 switch (blendMode) {
92 case SDL_BLENDMODE_BLEND:
93 FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_XRGB8888);
94 break;
95 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
96 FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888);
97 break;
98 case SDL_BLENDMODE_ADD:
99 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
100 FILLRECT(Uint32, DRAW_SETPIXEL_ADD_XRGB8888);
101 break;
102 case SDL_BLENDMODE_MOD:
103 FILLRECT(Uint32, DRAW_SETPIXEL_MOD_XRGB8888);
104 break;
105 case SDL_BLENDMODE_MUL:
106 FILLRECT(Uint32, DRAW_SETPIXEL_MUL_XRGB8888);
107 break;
108 default:
109 FILLRECT(Uint32, DRAW_SETPIXEL_XRGB8888);
110 break;
111 }
112 return true;
113}
114
115static bool SDL_BlendFillRect_ARGB8888(SDL_Surface *dst, const SDL_Rect *rect,
116 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
117{
118 unsigned inva = 0xff - a;
119
120 switch (blendMode) {
121 case SDL_BLENDMODE_BLEND:
122 FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888);
123 break;
124 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
125 FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888);
126 break;
127 case SDL_BLENDMODE_ADD:
128 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
129 FILLRECT(Uint32, DRAW_SETPIXEL_ADD_ARGB8888);
130 break;
131 case SDL_BLENDMODE_MOD:
132 FILLRECT(Uint32, DRAW_SETPIXEL_MOD_ARGB8888);
133 break;
134 case SDL_BLENDMODE_MUL:
135 FILLRECT(Uint32, DRAW_SETPIXEL_MUL_ARGB8888);
136 break;
137 default:
138 FILLRECT(Uint32, DRAW_SETPIXEL_ARGB8888);
139 break;
140 }
141 return true;
142}
143
144static bool SDL_BlendFillRect_RGB(SDL_Surface *dst, const SDL_Rect *rect,
145 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
146{
147 const SDL_PixelFormatDetails *fmt = dst->fmt;
148 unsigned inva = 0xff - a;
149
150 switch (fmt->bytes_per_pixel) {
151 case 2:
152 switch (blendMode) {
153 case SDL_BLENDMODE_BLEND:
154 FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB);
155 break;
156 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
157 FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB);
158 break;
159 case SDL_BLENDMODE_ADD:
160 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
161 FILLRECT(Uint16, DRAW_SETPIXEL_ADD_RGB);
162 break;
163 case SDL_BLENDMODE_MOD:
164 FILLRECT(Uint16, DRAW_SETPIXEL_MOD_RGB);
165 break;
166 case SDL_BLENDMODE_MUL:
167 FILLRECT(Uint16, DRAW_SETPIXEL_MUL_RGB);
168 break;
169 default:
170 FILLRECT(Uint16, DRAW_SETPIXEL_RGB);
171 break;
172 }
173 return true;
174 case 4:
175 switch (blendMode) {
176 case SDL_BLENDMODE_BLEND:
177 FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGB);
178 break;
179 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
180 FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGB);
181 break;
182 case SDL_BLENDMODE_ADD:
183 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
184 FILLRECT(Uint32, DRAW_SETPIXEL_ADD_RGB);
185 break;
186 case SDL_BLENDMODE_MOD:
187 FILLRECT(Uint32, DRAW_SETPIXEL_MOD_RGB);
188 break;
189 case SDL_BLENDMODE_MUL:
190 FILLRECT(Uint32, DRAW_SETPIXEL_MUL_RGB);
191 break;
192 default:
193 FILLRECT(Uint32, DRAW_SETPIXEL_RGB);
194 break;
195 }
196 return true;
197 default:
198 return SDL_Unsupported();
199 }
200}
201
202static bool SDL_BlendFillRect_RGBA(SDL_Surface *dst, const SDL_Rect *rect,
203 SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
204{
205 const SDL_PixelFormatDetails *fmt = dst->fmt;
206 unsigned inva = 0xff - a;
207
208 switch (fmt->bytes_per_pixel) {
209 case 4:
210 switch (blendMode) {
211 case SDL_BLENDMODE_BLEND:
212 FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGBA);
213 break;
214 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
215 FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGBA);
216 break;
217 case SDL_BLENDMODE_ADD:
218 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
219 FILLRECT(Uint32, DRAW_SETPIXEL_ADD_RGBA);
220 break;
221 case SDL_BLENDMODE_MOD:
222 FILLRECT(Uint32, DRAW_SETPIXEL_MOD_RGBA);
223 break;
224 case SDL_BLENDMODE_MUL:
225 FILLRECT(Uint32, DRAW_SETPIXEL_MUL_RGBA);
226 break;
227 default:
228 FILLRECT(Uint32, DRAW_SETPIXEL_RGBA);
229 break;
230 }
231 return true;
232 default:
233 return SDL_Unsupported();
234 }
235}
236
237bool SDL_BlendFillRect(SDL_Surface *dst, const SDL_Rect *rect, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
238{
239 SDL_Rect clipped;
240
241 if (!SDL_SurfaceValid(dst)) {
242 return SDL_InvalidParamError("SDL_BlendFillRect(): dst");
243 }
244
245 // This function doesn't work on surfaces < 8 bpp
246 if (SDL_BITSPERPIXEL(dst->format) < 8) {
247 return SDL_SetError("SDL_BlendFillRect(): Unsupported surface format");
248 }
249
250 // If 'rect' == NULL, then fill the whole surface
251 if (rect) {
252 // Perform clipping
253 if (!SDL_GetRectIntersection(rect, &dst->clip_rect, &clipped)) {
254 return true;
255 }
256 rect = &clipped;
257 } else {
258 rect = &dst->clip_rect;
259 }
260
261 if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
262 r = DRAW_MUL(r, a);
263 g = DRAW_MUL(g, a);
264 b = DRAW_MUL(b, a);
265 }
266
267 switch (dst->fmt->bits_per_pixel) {
268 case 15:
269 switch (dst->fmt->Rmask) {
270 case 0x7C00:
271 return SDL_BlendFillRect_RGB555(dst, rect, blendMode, r, g, b, a);
272 }
273 break;
274 case 16:
275 switch (dst->fmt->Rmask) {
276 case 0xF800:
277 return SDL_BlendFillRect_RGB565(dst, rect, blendMode, r, g, b, a);
278 }
279 break;
280 case 32:
281 switch (dst->fmt->Rmask) {
282 case 0x00FF0000:
283 if (!dst->fmt->Amask) {
284 return SDL_BlendFillRect_XRGB8888(dst, rect, blendMode, r, g, b, a);
285 } else {
286 return SDL_BlendFillRect_ARGB8888(dst, rect, blendMode, r, g, b, a);
287 }
288 // break; -Wunreachable-code-break
289 }
290 break;
291 default:
292 break;
293 }
294
295 if (!dst->fmt->Amask) {
296 return SDL_BlendFillRect_RGB(dst, rect, blendMode, r, g, b, a);
297 } else {
298 return SDL_BlendFillRect_RGBA(dst, rect, blendMode, r, g, b, a);
299 }
300}
301
302bool SDL_BlendFillRects(SDL_Surface *dst, const SDL_Rect *rects, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
303{
304 SDL_Rect rect;
305 int i;
306 bool (*func)(SDL_Surface * dst, const SDL_Rect *rect, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) = NULL;
307 bool result = true;
308
309 if (!SDL_SurfaceValid(dst)) {
310 return SDL_InvalidParamError("SDL_BlendFillRects(): dst");
311 }
312
313 // This function doesn't work on surfaces < 8 bpp
314 if (dst->fmt->bits_per_pixel < 8) {
315 return SDL_SetError("SDL_BlendFillRects(): Unsupported surface format");
316 }
317
318 if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
319 r = DRAW_MUL(r, a);
320 g = DRAW_MUL(g, a);
321 b = DRAW_MUL(b, a);
322 }
323
324 // FIXME: Does this function pointer slow things down significantly?
325 switch (dst->fmt->bits_per_pixel) {
326 case 15:
327 switch (dst->fmt->Rmask) {
328 case 0x7C00:
329 func = SDL_BlendFillRect_RGB555;
330 }
331 break;
332 case 16:
333 switch (dst->fmt->Rmask) {
334 case 0xF800:
335 func = SDL_BlendFillRect_RGB565;
336 }
337 break;
338 case 32:
339 switch (dst->fmt->Rmask) {
340 case 0x00FF0000:
341 if (!dst->fmt->Amask) {
342 func = SDL_BlendFillRect_XRGB8888;
343 } else {
344 func = SDL_BlendFillRect_ARGB8888;
345 }
346 break;
347 }
348 break;
349 default:
350 break;
351 }
352
353 if (!func) {
354 if (!dst->fmt->Amask) {
355 func = SDL_BlendFillRect_RGB;
356 } else {
357 func = SDL_BlendFillRect_RGBA;
358 }
359 }
360
361 for (i = 0; i < count; ++i) {
362 // Perform clipping
363 if (!SDL_GetRectIntersection(&rects[i], &dst->clip_rect, &rect)) {
364 continue;
365 }
366 result = func(dst, &rect, blendMode, r, g, b, a);
367 }
368 return result;
369}
370
371#endif // SDL_VIDEO_RENDER_SW
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_blendfillrect.h b/contrib/SDL-3.2.8/src/render/software/SDL_blendfillrect.h
new file mode 100644
index 0000000..c1ff439
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_blendfillrect.h
@@ -0,0 +1,30 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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
22#ifndef SDL_blendfillrect_h_
23#define SDL_blendfillrect_h_
24
25#include "SDL_internal.h"
26
27extern bool SDL_BlendFillRect(SDL_Surface *dst, const SDL_Rect *rect, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
28extern bool SDL_BlendFillRects(SDL_Surface *dst, const SDL_Rect *rects, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
29
30#endif // SDL_blendfillrect_h_
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_blendline.c b/contrib/SDL-3.2.8/src/render/software/SDL_blendline.c
new file mode 100644
index 0000000..53be2f1
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_blendline.c
@@ -0,0 +1,986 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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#ifdef SDL_VIDEO_RENDER_SW
24
25#include "SDL_draw.h"
26#include "SDL_blendline.h"
27#include "SDL_blendpoint.h"
28
29static void SDL_BlendLine_RGB2(SDL_Surface *dst, int x1, int y1, int x2, int y2,
30 SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
31 bool draw_end)
32{
33 const SDL_PixelFormatDetails *fmt = dst->fmt;
34 unsigned r, g, b, a, inva;
35
36 if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
37 r = DRAW_MUL(_r, _a);
38 g = DRAW_MUL(_g, _a);
39 b = DRAW_MUL(_b, _a);
40 a = _a;
41 } else {
42 r = _r;
43 g = _g;
44 b = _b;
45 a = _a;
46 }
47 inva = (a ^ 0xff);
48
49 if (y1 == y2) {
50 switch (blendMode) {
51 case SDL_BLENDMODE_BLEND:
52 HLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB, draw_end);
53 break;
54 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
55 HLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end);
56 break;
57 case SDL_BLENDMODE_ADD:
58 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
59 HLINE(Uint16, DRAW_SETPIXEL_ADD_RGB, draw_end);
60 break;
61 case SDL_BLENDMODE_MOD:
62 HLINE(Uint16, DRAW_SETPIXEL_MOD_RGB, draw_end);
63 break;
64 case SDL_BLENDMODE_MUL:
65 HLINE(Uint16, DRAW_SETPIXEL_MUL_RGB, draw_end);
66 break;
67 default:
68 HLINE(Uint16, DRAW_SETPIXEL_RGB, draw_end);
69 break;
70 }
71 } else if (x1 == x2) {
72 switch (blendMode) {
73 case SDL_BLENDMODE_BLEND:
74 VLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB, draw_end);
75 break;
76 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
77 VLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end);
78 break;
79 case SDL_BLENDMODE_ADD:
80 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
81 VLINE(Uint16, DRAW_SETPIXEL_ADD_RGB, draw_end);
82 break;
83 case SDL_BLENDMODE_MOD:
84 VLINE(Uint16, DRAW_SETPIXEL_MOD_RGB, draw_end);
85 break;
86 case SDL_BLENDMODE_MUL:
87 VLINE(Uint16, DRAW_SETPIXEL_MUL_RGB, draw_end);
88 break;
89 default:
90 VLINE(Uint16, DRAW_SETPIXEL_RGB, draw_end);
91 break;
92 }
93 } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
94 switch (blendMode) {
95 case SDL_BLENDMODE_BLEND:
96 DLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB, draw_end);
97 break;
98 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
99 DLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end);
100 break;
101 case SDL_BLENDMODE_ADD:
102 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
103 DLINE(Uint16, DRAW_SETPIXEL_ADD_RGB, draw_end);
104 break;
105 case SDL_BLENDMODE_MOD:
106 DLINE(Uint16, DRAW_SETPIXEL_MOD_RGB, draw_end);
107 break;
108 case SDL_BLENDMODE_MUL:
109 DLINE(Uint16, DRAW_SETPIXEL_MUL_RGB, draw_end);
110 break;
111 default:
112 DLINE(Uint16, DRAW_SETPIXEL_RGB, draw_end);
113 break;
114 }
115 } else {
116 switch (blendMode) {
117 case SDL_BLENDMODE_BLEND:
118 AALINE(x1, y1, x2, y2,
119 DRAW_SETPIXELXY2_BLEND_RGB, DRAW_SETPIXELXY2_BLEND_RGB,
120 draw_end);
121 break;
122 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
123 AALINE(x1, y1, x2, y2,
124 DRAW_SETPIXELXY2_BLEND_CLAMPED_RGB, DRAW_SETPIXELXY2_BLEND_CLAMPED_RGB,
125 draw_end);
126 break;
127 case SDL_BLENDMODE_ADD:
128 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
129 AALINE(x1, y1, x2, y2,
130 DRAW_SETPIXELXY2_ADD_RGB, DRAW_SETPIXELXY2_ADD_RGB,
131 draw_end);
132 break;
133 case SDL_BLENDMODE_MOD:
134 AALINE(x1, y1, x2, y2,
135 DRAW_SETPIXELXY2_MOD_RGB, DRAW_SETPIXELXY2_MOD_RGB,
136 draw_end);
137 break;
138 case SDL_BLENDMODE_MUL:
139 AALINE(x1, y1, x2, y2,
140 DRAW_SETPIXELXY2_MUL_RGB, DRAW_SETPIXELXY2_MUL_RGB,
141 draw_end);
142 break;
143 default:
144 AALINE(x1, y1, x2, y2,
145 DRAW_SETPIXELXY2_RGB, DRAW_SETPIXELXY2_BLEND_RGB,
146 draw_end);
147 break;
148 }
149 }
150}
151
152static void SDL_BlendLine_RGB555(SDL_Surface *dst, int x1, int y1, int x2, int y2,
153 SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
154 bool draw_end)
155{
156 unsigned r, g, b, a, inva;
157
158 if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
159 r = DRAW_MUL(_r, _a);
160 g = DRAW_MUL(_g, _a);
161 b = DRAW_MUL(_b, _a);
162 a = _a;
163 } else {
164 r = _r;
165 g = _g;
166 b = _b;
167 a = _a;
168 }
169 inva = (a ^ 0xff);
170
171 if (y1 == y2) {
172 switch (blendMode) {
173 case SDL_BLENDMODE_BLEND:
174 HLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB555, draw_end);
175 break;
176 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
177 HLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB555, draw_end);
178 break;
179 case SDL_BLENDMODE_ADD:
180 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
181 HLINE(Uint16, DRAW_SETPIXEL_ADD_RGB555, draw_end);
182 break;
183 case SDL_BLENDMODE_MOD:
184 HLINE(Uint16, DRAW_SETPIXEL_MOD_RGB555, draw_end);
185 break;
186 case SDL_BLENDMODE_MUL:
187 HLINE(Uint16, DRAW_SETPIXEL_MUL_RGB555, draw_end);
188 break;
189 default:
190 HLINE(Uint16, DRAW_SETPIXEL_RGB555, draw_end);
191 break;
192 }
193 } else if (x1 == x2) {
194 switch (blendMode) {
195 case SDL_BLENDMODE_BLEND:
196 VLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB555, draw_end);
197 break;
198 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
199 VLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB555, draw_end);
200 break;
201 case SDL_BLENDMODE_ADD:
202 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
203 VLINE(Uint16, DRAW_SETPIXEL_ADD_RGB555, draw_end);
204 break;
205 case SDL_BLENDMODE_MOD:
206 VLINE(Uint16, DRAW_SETPIXEL_MOD_RGB555, draw_end);
207 break;
208 case SDL_BLENDMODE_MUL:
209 VLINE(Uint16, DRAW_SETPIXEL_MUL_RGB555, draw_end);
210 break;
211 default:
212 VLINE(Uint16, DRAW_SETPIXEL_RGB555, draw_end);
213 break;
214 }
215 } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
216 switch (blendMode) {
217 case SDL_BLENDMODE_BLEND:
218 DLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB555, draw_end);
219 break;
220 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
221 DLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB555, draw_end);
222 break;
223 case SDL_BLENDMODE_ADD:
224 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
225 DLINE(Uint16, DRAW_SETPIXEL_ADD_RGB555, draw_end);
226 break;
227 case SDL_BLENDMODE_MOD:
228 DLINE(Uint16, DRAW_SETPIXEL_MOD_RGB555, draw_end);
229 break;
230 case SDL_BLENDMODE_MUL:
231 DLINE(Uint16, DRAW_SETPIXEL_MUL_RGB555, draw_end);
232 break;
233 default:
234 DLINE(Uint16, DRAW_SETPIXEL_RGB555, draw_end);
235 break;
236 }
237 } else {
238 switch (blendMode) {
239 case SDL_BLENDMODE_BLEND:
240 AALINE(x1, y1, x2, y2,
241 DRAW_SETPIXELXY_BLEND_RGB555, DRAW_SETPIXELXY_BLEND_RGB555,
242 draw_end);
243 break;
244 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
245 AALINE(x1, y1, x2, y2,
246 DRAW_SETPIXELXY_BLEND_CLAMPED_RGB555, DRAW_SETPIXELXY_BLEND_CLAMPED_RGB555,
247 draw_end);
248 break;
249 case SDL_BLENDMODE_ADD:
250 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
251 AALINE(x1, y1, x2, y2,
252 DRAW_SETPIXELXY_ADD_RGB555, DRAW_SETPIXELXY_ADD_RGB555,
253 draw_end);
254 break;
255 case SDL_BLENDMODE_MOD:
256 AALINE(x1, y1, x2, y2,
257 DRAW_SETPIXELXY_MOD_RGB555, DRAW_SETPIXELXY_MOD_RGB555,
258 draw_end);
259 break;
260 case SDL_BLENDMODE_MUL:
261 AALINE(x1, y1, x2, y2,
262 DRAW_SETPIXELXY_MUL_RGB555, DRAW_SETPIXELXY_MUL_RGB555,
263 draw_end);
264 break;
265 default:
266 AALINE(x1, y1, x2, y2,
267 DRAW_SETPIXELXY_RGB555, DRAW_SETPIXELXY_BLEND_RGB555,
268 draw_end);
269 break;
270 }
271 }
272}
273
274static void SDL_BlendLine_RGB565(SDL_Surface *dst, int x1, int y1, int x2, int y2,
275 SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
276 bool draw_end)
277{
278 unsigned r, g, b, a, inva;
279
280 if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
281 r = DRAW_MUL(_r, _a);
282 g = DRAW_MUL(_g, _a);
283 b = DRAW_MUL(_b, _a);
284 a = _a;
285 } else {
286 r = _r;
287 g = _g;
288 b = _b;
289 a = _a;
290 }
291 inva = (a ^ 0xff);
292
293 if (y1 == y2) {
294 switch (blendMode) {
295 case SDL_BLENDMODE_BLEND:
296 HLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB565, draw_end);
297 break;
298 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
299 HLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB565, draw_end);
300 break;
301 case SDL_BLENDMODE_ADD:
302 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
303 HLINE(Uint16, DRAW_SETPIXEL_ADD_RGB565, draw_end);
304 break;
305 case SDL_BLENDMODE_MOD:
306 HLINE(Uint16, DRAW_SETPIXEL_MOD_RGB565, draw_end);
307 break;
308 case SDL_BLENDMODE_MUL:
309 HLINE(Uint16, DRAW_SETPIXEL_MUL_RGB565, draw_end);
310 break;
311 default:
312 HLINE(Uint16, DRAW_SETPIXEL_RGB565, draw_end);
313 break;
314 }
315 } else if (x1 == x2) {
316 switch (blendMode) {
317 case SDL_BLENDMODE_BLEND:
318 VLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB565, draw_end);
319 break;
320 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
321 VLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB565, draw_end);
322 break;
323 case SDL_BLENDMODE_ADD:
324 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
325 VLINE(Uint16, DRAW_SETPIXEL_ADD_RGB565, draw_end);
326 break;
327 case SDL_BLENDMODE_MOD:
328 VLINE(Uint16, DRAW_SETPIXEL_MOD_RGB565, draw_end);
329 break;
330 case SDL_BLENDMODE_MUL:
331 VLINE(Uint16, DRAW_SETPIXEL_MUL_RGB565, draw_end);
332 break;
333 default:
334 VLINE(Uint16, DRAW_SETPIXEL_RGB565, draw_end);
335 break;
336 }
337 } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
338 switch (blendMode) {
339 case SDL_BLENDMODE_BLEND:
340 DLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB565, draw_end);
341 break;
342 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
343 DLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB565, draw_end);
344 break;
345 case SDL_BLENDMODE_ADD:
346 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
347 DLINE(Uint16, DRAW_SETPIXEL_ADD_RGB565, draw_end);
348 break;
349 case SDL_BLENDMODE_MOD:
350 DLINE(Uint16, DRAW_SETPIXEL_MOD_RGB565, draw_end);
351 break;
352 case SDL_BLENDMODE_MUL:
353 DLINE(Uint16, DRAW_SETPIXEL_MUL_RGB565, draw_end);
354 break;
355 default:
356 DLINE(Uint16, DRAW_SETPIXEL_RGB565, draw_end);
357 break;
358 }
359 } else {
360 switch (blendMode) {
361 case SDL_BLENDMODE_BLEND:
362 AALINE(x1, y1, x2, y2,
363 DRAW_SETPIXELXY_BLEND_RGB565, DRAW_SETPIXELXY_BLEND_RGB565,
364 draw_end);
365 break;
366 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
367 AALINE(x1, y1, x2, y2,
368 DRAW_SETPIXELXY_BLEND_CLAMPED_RGB565, DRAW_SETPIXELXY_BLEND_CLAMPED_RGB565,
369 draw_end);
370 break;
371 case SDL_BLENDMODE_ADD:
372 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
373 AALINE(x1, y1, x2, y2,
374 DRAW_SETPIXELXY_ADD_RGB565, DRAW_SETPIXELXY_ADD_RGB565,
375 draw_end);
376 break;
377 case SDL_BLENDMODE_MOD:
378 AALINE(x1, y1, x2, y2,
379 DRAW_SETPIXELXY_MOD_RGB565, DRAW_SETPIXELXY_MOD_RGB565,
380 draw_end);
381 break;
382 case SDL_BLENDMODE_MUL:
383 AALINE(x1, y1, x2, y2,
384 DRAW_SETPIXELXY_MUL_RGB565, DRAW_SETPIXELXY_MUL_RGB565,
385 draw_end);
386 break;
387 default:
388 AALINE(x1, y1, x2, y2,
389 DRAW_SETPIXELXY_RGB565, DRAW_SETPIXELXY_BLEND_RGB565,
390 draw_end);
391 break;
392 }
393 }
394}
395
396static void SDL_BlendLine_RGB4(SDL_Surface *dst, int x1, int y1, int x2, int y2,
397 SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
398 bool draw_end)
399{
400 const SDL_PixelFormatDetails *fmt = dst->fmt;
401 unsigned r, g, b, a, inva;
402
403 if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
404 r = DRAW_MUL(_r, _a);
405 g = DRAW_MUL(_g, _a);
406 b = DRAW_MUL(_b, _a);
407 a = _a;
408 } else {
409 r = _r;
410 g = _g;
411 b = _b;
412 a = _a;
413 }
414 inva = (a ^ 0xff);
415
416 if (y1 == y2) {
417 switch (blendMode) {
418 case SDL_BLENDMODE_BLEND:
419 HLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB, draw_end);
420 break;
421 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
422 HLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end);
423 break;
424 case SDL_BLENDMODE_ADD:
425 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
426 HLINE(Uint32, DRAW_SETPIXEL_ADD_RGB, draw_end);
427 break;
428 case SDL_BLENDMODE_MOD:
429 HLINE(Uint32, DRAW_SETPIXEL_MOD_RGB, draw_end);
430 break;
431 case SDL_BLENDMODE_MUL:
432 HLINE(Uint32, DRAW_SETPIXEL_MUL_RGB, draw_end);
433 break;
434 default:
435 HLINE(Uint32, DRAW_SETPIXEL_RGB, draw_end);
436 break;
437 }
438 } else if (x1 == x2) {
439 switch (blendMode) {
440 case SDL_BLENDMODE_BLEND:
441 VLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB, draw_end);
442 break;
443 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
444 VLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end);
445 break;
446 case SDL_BLENDMODE_ADD:
447 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
448 VLINE(Uint32, DRAW_SETPIXEL_ADD_RGB, draw_end);
449 break;
450 case SDL_BLENDMODE_MOD:
451 VLINE(Uint32, DRAW_SETPIXEL_MOD_RGB, draw_end);
452 break;
453 case SDL_BLENDMODE_MUL:
454 VLINE(Uint32, DRAW_SETPIXEL_MUL_RGB, draw_end);
455 break;
456 default:
457 VLINE(Uint32, DRAW_SETPIXEL_RGB, draw_end);
458 break;
459 }
460 } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
461 switch (blendMode) {
462 case SDL_BLENDMODE_BLEND:
463 DLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB, draw_end);
464 break;
465 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
466 DLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end);
467 break;
468 case SDL_BLENDMODE_ADD:
469 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
470 DLINE(Uint32, DRAW_SETPIXEL_ADD_RGB, draw_end);
471 break;
472 case SDL_BLENDMODE_MOD:
473 DLINE(Uint32, DRAW_SETPIXEL_MOD_RGB, draw_end);
474 break;
475 case SDL_BLENDMODE_MUL:
476 DLINE(Uint32, DRAW_SETPIXEL_MUL_RGB, draw_end);
477 break;
478 default:
479 DLINE(Uint32, DRAW_SETPIXEL_RGB, draw_end);
480 break;
481 }
482 } else {
483 switch (blendMode) {
484 case SDL_BLENDMODE_BLEND:
485 AALINE(x1, y1, x2, y2,
486 DRAW_SETPIXELXY4_BLEND_RGB, DRAW_SETPIXELXY4_BLEND_RGB,
487 draw_end);
488 break;
489 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
490 AALINE(x1, y1, x2, y2,
491 DRAW_SETPIXELXY4_BLEND_CLAMPED_RGB, DRAW_SETPIXELXY4_BLEND_CLAMPED_RGB,
492 draw_end);
493 break;
494 case SDL_BLENDMODE_ADD:
495 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
496 AALINE(x1, y1, x2, y2,
497 DRAW_SETPIXELXY4_ADD_RGB, DRAW_SETPIXELXY4_ADD_RGB,
498 draw_end);
499 break;
500 case SDL_BLENDMODE_MOD:
501 AALINE(x1, y1, x2, y2,
502 DRAW_SETPIXELXY4_MOD_RGB, DRAW_SETPIXELXY4_MOD_RGB,
503 draw_end);
504 break;
505 case SDL_BLENDMODE_MUL:
506 AALINE(x1, y1, x2, y2,
507 DRAW_SETPIXELXY4_MUL_RGB, DRAW_SETPIXELXY4_MUL_RGB,
508 draw_end);
509 break;
510 default:
511 AALINE(x1, y1, x2, y2,
512 DRAW_SETPIXELXY4_RGB, DRAW_SETPIXELXY4_BLEND_RGB,
513 draw_end);
514 break;
515 }
516 }
517}
518
519static void SDL_BlendLine_RGBA4(SDL_Surface *dst, int x1, int y1, int x2, int y2,
520 SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
521 bool draw_end)
522{
523 const SDL_PixelFormatDetails *fmt = dst->fmt;
524 unsigned r, g, b, a, inva;
525
526 if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
527 r = DRAW_MUL(_r, _a);
528 g = DRAW_MUL(_g, _a);
529 b = DRAW_MUL(_b, _a);
530 a = _a;
531 } else {
532 r = _r;
533 g = _g;
534 b = _b;
535 a = _a;
536 }
537 inva = (a ^ 0xff);
538
539 if (y1 == y2) {
540 switch (blendMode) {
541 case SDL_BLENDMODE_BLEND:
542 HLINE(Uint32, DRAW_SETPIXEL_BLEND_RGBA, draw_end);
543 break;
544 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
545 HLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGBA, draw_end);
546 break;
547 case SDL_BLENDMODE_ADD:
548 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
549 HLINE(Uint32, DRAW_SETPIXEL_ADD_RGBA, draw_end);
550 break;
551 case SDL_BLENDMODE_MOD:
552 HLINE(Uint32, DRAW_SETPIXEL_MOD_RGBA, draw_end);
553 break;
554 case SDL_BLENDMODE_MUL:
555 HLINE(Uint32, DRAW_SETPIXEL_MUL_RGBA, draw_end);
556 break;
557 default:
558 HLINE(Uint32, DRAW_SETPIXEL_RGBA, draw_end);
559 break;
560 }
561 } else if (x1 == x2) {
562 switch (blendMode) {
563 case SDL_BLENDMODE_BLEND:
564 VLINE(Uint32, DRAW_SETPIXEL_BLEND_RGBA, draw_end);
565 break;
566 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
567 VLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGBA, draw_end);
568 break;
569 case SDL_BLENDMODE_ADD:
570 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
571 VLINE(Uint32, DRAW_SETPIXEL_ADD_RGBA, draw_end);
572 break;
573 case SDL_BLENDMODE_MOD:
574 VLINE(Uint32, DRAW_SETPIXEL_MOD_RGBA, draw_end);
575 break;
576 case SDL_BLENDMODE_MUL:
577 VLINE(Uint32, DRAW_SETPIXEL_MUL_RGBA, draw_end);
578 break;
579 default:
580 VLINE(Uint32, DRAW_SETPIXEL_RGBA, draw_end);
581 break;
582 }
583 } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
584 switch (blendMode) {
585 case SDL_BLENDMODE_BLEND:
586 DLINE(Uint32, DRAW_SETPIXEL_BLEND_RGBA, draw_end);
587 break;
588 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
589 DLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGBA, draw_end);
590 break;
591 case SDL_BLENDMODE_ADD:
592 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
593 DLINE(Uint32, DRAW_SETPIXEL_ADD_RGBA, draw_end);
594 break;
595 case SDL_BLENDMODE_MOD:
596 DLINE(Uint32, DRAW_SETPIXEL_MOD_RGBA, draw_end);
597 break;
598 case SDL_BLENDMODE_MUL:
599 DLINE(Uint32, DRAW_SETPIXEL_MUL_RGBA, draw_end);
600 break;
601 default:
602 DLINE(Uint32, DRAW_SETPIXEL_RGBA, draw_end);
603 break;
604 }
605 } else {
606 switch (blendMode) {
607 case SDL_BLENDMODE_BLEND:
608 AALINE(x1, y1, x2, y2,
609 DRAW_SETPIXELXY4_BLEND_RGBA, DRAW_SETPIXELXY4_BLEND_RGBA,
610 draw_end);
611 break;
612 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
613 AALINE(x1, y1, x2, y2,
614 DRAW_SETPIXELXY4_BLEND_CLAMPED_RGBA, DRAW_SETPIXELXY4_BLEND_CLAMPED_RGBA,
615 draw_end);
616 break;
617 case SDL_BLENDMODE_ADD:
618 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
619 AALINE(x1, y1, x2, y2,
620 DRAW_SETPIXELXY4_ADD_RGBA, DRAW_SETPIXELXY4_ADD_RGBA,
621 draw_end);
622 break;
623 case SDL_BLENDMODE_MOD:
624 AALINE(x1, y1, x2, y2,
625 DRAW_SETPIXELXY4_MOD_RGBA, DRAW_SETPIXELXY4_MOD_RGBA,
626 draw_end);
627 break;
628 case SDL_BLENDMODE_MUL:
629 AALINE(x1, y1, x2, y2,
630 DRAW_SETPIXELXY4_MUL_RGBA, DRAW_SETPIXELXY4_MUL_RGBA,
631 draw_end);
632 break;
633 default:
634 AALINE(x1, y1, x2, y2,
635 DRAW_SETPIXELXY4_RGBA, DRAW_SETPIXELXY4_BLEND_RGBA,
636 draw_end);
637 break;
638 }
639 }
640}
641
642static void SDL_BlendLine_XRGB8888(SDL_Surface *dst, int x1, int y1, int x2, int y2,
643 SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
644 bool draw_end)
645{
646 unsigned r, g, b, a, inva;
647
648 if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
649 r = DRAW_MUL(_r, _a);
650 g = DRAW_MUL(_g, _a);
651 b = DRAW_MUL(_b, _a);
652 a = _a;
653 } else {
654 r = _r;
655 g = _g;
656 b = _b;
657 a = _a;
658 }
659 inva = (a ^ 0xff);
660
661 if (y1 == y2) {
662 switch (blendMode) {
663 case SDL_BLENDMODE_BLEND:
664 HLINE(Uint32, DRAW_SETPIXEL_BLEND_XRGB8888, draw_end);
665 break;
666 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
667 HLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888, draw_end);
668 break;
669 case SDL_BLENDMODE_ADD:
670 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
671 HLINE(Uint32, DRAW_SETPIXEL_ADD_XRGB8888, draw_end);
672 break;
673 case SDL_BLENDMODE_MOD:
674 HLINE(Uint32, DRAW_SETPIXEL_MOD_XRGB8888, draw_end);
675 break;
676 case SDL_BLENDMODE_MUL:
677 HLINE(Uint32, DRAW_SETPIXEL_MUL_XRGB8888, draw_end);
678 break;
679 default:
680 HLINE(Uint32, DRAW_SETPIXEL_XRGB8888, draw_end);
681 break;
682 }
683 } else if (x1 == x2) {
684 switch (blendMode) {
685 case SDL_BLENDMODE_BLEND:
686 VLINE(Uint32, DRAW_SETPIXEL_BLEND_XRGB8888, draw_end);
687 break;
688 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
689 VLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888, draw_end);
690 break;
691 case SDL_BLENDMODE_ADD:
692 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
693 VLINE(Uint32, DRAW_SETPIXEL_ADD_XRGB8888, draw_end);
694 break;
695 case SDL_BLENDMODE_MOD:
696 VLINE(Uint32, DRAW_SETPIXEL_MOD_XRGB8888, draw_end);
697 break;
698 case SDL_BLENDMODE_MUL:
699 VLINE(Uint32, DRAW_SETPIXEL_MUL_XRGB8888, draw_end);
700 break;
701 default:
702 VLINE(Uint32, DRAW_SETPIXEL_XRGB8888, draw_end);
703 break;
704 }
705 } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
706 switch (blendMode) {
707 case SDL_BLENDMODE_BLEND:
708 DLINE(Uint32, DRAW_SETPIXEL_BLEND_XRGB8888, draw_end);
709 break;
710 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
711 DLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888, draw_end);
712 break;
713 case SDL_BLENDMODE_ADD:
714 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
715 DLINE(Uint32, DRAW_SETPIXEL_ADD_XRGB8888, draw_end);
716 break;
717 case SDL_BLENDMODE_MOD:
718 DLINE(Uint32, DRAW_SETPIXEL_MOD_XRGB8888, draw_end);
719 break;
720 case SDL_BLENDMODE_MUL:
721 DLINE(Uint32, DRAW_SETPIXEL_MUL_XRGB8888, draw_end);
722 break;
723 default:
724 DLINE(Uint32, DRAW_SETPIXEL_XRGB8888, draw_end);
725 break;
726 }
727 } else {
728 switch (blendMode) {
729 case SDL_BLENDMODE_BLEND:
730 AALINE(x1, y1, x2, y2,
731 DRAW_SETPIXELXY_BLEND_XRGB8888, DRAW_SETPIXELXY_BLEND_XRGB8888,
732 draw_end);
733 break;
734 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
735 AALINE(x1, y1, x2, y2,
736 DRAW_SETPIXELXY_BLEND_CLAMPED_XRGB8888, DRAW_SETPIXELXY_BLEND_CLAMPED_XRGB8888,
737 draw_end);
738 break;
739 case SDL_BLENDMODE_ADD:
740 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
741 AALINE(x1, y1, x2, y2,
742 DRAW_SETPIXELXY_ADD_XRGB8888, DRAW_SETPIXELXY_ADD_XRGB8888,
743 draw_end);
744 break;
745 case SDL_BLENDMODE_MOD:
746 AALINE(x1, y1, x2, y2,
747 DRAW_SETPIXELXY_MOD_XRGB8888, DRAW_SETPIXELXY_MOD_XRGB8888,
748 draw_end);
749 break;
750 case SDL_BLENDMODE_MUL:
751 AALINE(x1, y1, x2, y2,
752 DRAW_SETPIXELXY_MUL_XRGB8888, DRAW_SETPIXELXY_MUL_XRGB8888,
753 draw_end);
754 break;
755 default:
756 AALINE(x1, y1, x2, y2,
757 DRAW_SETPIXELXY_XRGB8888, DRAW_SETPIXELXY_BLEND_XRGB8888,
758 draw_end);
759 break;
760 }
761 }
762}
763
764static void SDL_BlendLine_ARGB8888(SDL_Surface *dst, int x1, int y1, int x2, int y2,
765 SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
766 bool draw_end)
767{
768 unsigned r, g, b, a, inva;
769
770 if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
771 r = DRAW_MUL(_r, _a);
772 g = DRAW_MUL(_g, _a);
773 b = DRAW_MUL(_b, _a);
774 a = _a;
775 } else {
776 r = _r;
777 g = _g;
778 b = _b;
779 a = _a;
780 }
781 inva = (a ^ 0xff);
782
783 if (y1 == y2) {
784 switch (blendMode) {
785 case SDL_BLENDMODE_BLEND:
786 HLINE(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888, draw_end);
787 break;
788 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
789 HLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888, draw_end);
790 break;
791 case SDL_BLENDMODE_ADD:
792 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
793 HLINE(Uint32, DRAW_SETPIXEL_ADD_ARGB8888, draw_end);
794 break;
795 case SDL_BLENDMODE_MOD:
796 HLINE(Uint32, DRAW_SETPIXEL_MOD_ARGB8888, draw_end);
797 break;
798 case SDL_BLENDMODE_MUL:
799 HLINE(Uint32, DRAW_SETPIXEL_MUL_ARGB8888, draw_end);
800 break;
801 default:
802 HLINE(Uint32, DRAW_SETPIXEL_ARGB8888, draw_end);
803 break;
804 }
805 } else if (x1 == x2) {
806 switch (blendMode) {
807 case SDL_BLENDMODE_BLEND:
808 VLINE(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888, draw_end);
809 break;
810 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
811 VLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888, draw_end);
812 break;
813 case SDL_BLENDMODE_ADD:
814 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
815 VLINE(Uint32, DRAW_SETPIXEL_ADD_ARGB8888, draw_end);
816 break;
817 case SDL_BLENDMODE_MOD:
818 VLINE(Uint32, DRAW_SETPIXEL_MOD_ARGB8888, draw_end);
819 break;
820 case SDL_BLENDMODE_MUL:
821 VLINE(Uint32, DRAW_SETPIXEL_MUL_ARGB8888, draw_end);
822 break;
823 default:
824 VLINE(Uint32, DRAW_SETPIXEL_ARGB8888, draw_end);
825 break;
826 }
827 } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
828 switch (blendMode) {
829 case SDL_BLENDMODE_BLEND:
830 DLINE(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888, draw_end);
831 break;
832 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
833 DLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888, draw_end);
834 break;
835 case SDL_BLENDMODE_ADD:
836 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
837 DLINE(Uint32, DRAW_SETPIXEL_ADD_ARGB8888, draw_end);
838 break;
839 case SDL_BLENDMODE_MOD:
840 DLINE(Uint32, DRAW_SETPIXEL_MOD_ARGB8888, draw_end);
841 break;
842 case SDL_BLENDMODE_MUL:
843 DLINE(Uint32, DRAW_SETPIXEL_MUL_ARGB8888, draw_end);
844 break;
845 default:
846 DLINE(Uint32, DRAW_SETPIXEL_ARGB8888, draw_end);
847 break;
848 }
849 } else {
850 switch (blendMode) {
851 case SDL_BLENDMODE_BLEND:
852 AALINE(x1, y1, x2, y2,
853 DRAW_SETPIXELXY_BLEND_ARGB8888, DRAW_SETPIXELXY_BLEND_ARGB8888,
854 draw_end);
855 break;
856 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
857 AALINE(x1, y1, x2, y2,
858 DRAW_SETPIXELXY_BLEND_CLAMPED_ARGB8888, DRAW_SETPIXELXY_BLEND_CLAMPED_ARGB8888,
859 draw_end);
860 break;
861 case SDL_BLENDMODE_ADD:
862 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
863 AALINE(x1, y1, x2, y2,
864 DRAW_SETPIXELXY_ADD_ARGB8888, DRAW_SETPIXELXY_ADD_ARGB8888,
865 draw_end);
866 break;
867 case SDL_BLENDMODE_MOD:
868 AALINE(x1, y1, x2, y2,
869 DRAW_SETPIXELXY_MOD_ARGB8888, DRAW_SETPIXELXY_MOD_ARGB8888,
870 draw_end);
871 break;
872 case SDL_BLENDMODE_MUL:
873 AALINE(x1, y1, x2, y2,
874 DRAW_SETPIXELXY_MUL_ARGB8888, DRAW_SETPIXELXY_MUL_ARGB8888,
875 draw_end);
876 break;
877 default:
878 AALINE(x1, y1, x2, y2,
879 DRAW_SETPIXELXY_ARGB8888, DRAW_SETPIXELXY_BLEND_ARGB8888,
880 draw_end);
881 break;
882 }
883 }
884}
885
886typedef void (*BlendLineFunc)(SDL_Surface *dst,
887 int x1, int y1, int x2, int y2,
888 SDL_BlendMode blendMode,
889 Uint8 r, Uint8 g, Uint8 b, Uint8 a,
890 bool draw_end);
891
892static BlendLineFunc SDL_CalculateBlendLineFunc(const SDL_PixelFormatDetails *fmt)
893{
894 switch (fmt->bytes_per_pixel) {
895 case 2:
896 if (fmt->Rmask == 0x7C00) {
897 return SDL_BlendLine_RGB555;
898 } else if (fmt->Rmask == 0xF800) {
899 return SDL_BlendLine_RGB565;
900 } else {
901 return SDL_BlendLine_RGB2;
902 }
903 // break; -Wunreachable-code-break
904 case 4:
905 if (fmt->Rmask == 0x00FF0000) {
906 if (fmt->Amask) {
907 return SDL_BlendLine_ARGB8888;
908 } else {
909 return SDL_BlendLine_XRGB8888;
910 }
911 } else {
912 if (fmt->Amask) {
913 return SDL_BlendLine_RGBA4;
914 } else {
915 return SDL_BlendLine_RGB4;
916 }
917 }
918 }
919 return NULL;
920}
921
922bool SDL_BlendLine(SDL_Surface *dst, int x1, int y1, int x2, int y2, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
923{
924 BlendLineFunc func;
925
926 if (!SDL_SurfaceValid(dst)) {
927 return SDL_InvalidParamError("SDL_BlendLine(): dst");
928 }
929
930 func = SDL_CalculateBlendLineFunc(dst->fmt);
931 if (!func) {
932 return SDL_SetError("SDL_BlendLine(): Unsupported surface format");
933 }
934
935 // Perform clipping
936 // FIXME: We don't actually want to clip, as it may change line slope
937 if (!SDL_GetRectAndLineIntersection(&dst->clip_rect, &x1, &y1, &x2, &y2)) {
938 return true;
939 }
940
941 func(dst, x1, y1, x2, y2, blendMode, r, g, b, a, true);
942 return true;
943}
944
945bool SDL_BlendLines(SDL_Surface *dst, const SDL_Point *points, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
946{
947 int i;
948 int x1, y1;
949 int x2, y2;
950 bool draw_end;
951 BlendLineFunc func;
952
953 if (!SDL_SurfaceValid(dst)) {
954 return SDL_SetError("SDL_BlendLines(): Passed NULL destination surface");
955 }
956
957 func = SDL_CalculateBlendLineFunc(dst->fmt);
958 if (!func) {
959 return SDL_SetError("SDL_BlendLines(): Unsupported surface format");
960 }
961
962 for (i = 1; i < count; ++i) {
963 x1 = points[i - 1].x;
964 y1 = points[i - 1].y;
965 x2 = points[i].x;
966 y2 = points[i].y;
967
968 // Perform clipping
969 // FIXME: We don't actually want to clip, as it may change line slope
970 if (!SDL_GetRectAndLineIntersection(&dst->clip_rect, &x1, &y1, &x2, &y2)) {
971 continue;
972 }
973
974 // Draw the end if it was clipped
975 draw_end = (x2 != points[i].x || y2 != points[i].y);
976
977 func(dst, x1, y1, x2, y2, blendMode, r, g, b, a, draw_end);
978 }
979 if (points[0].x != points[count - 1].x || points[0].y != points[count - 1].y) {
980 SDL_BlendPoint(dst, points[count - 1].x, points[count - 1].y,
981 blendMode, r, g, b, a);
982 }
983 return true;
984}
985
986#endif // SDL_VIDEO_RENDER_SW
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_blendline.h b/contrib/SDL-3.2.8/src/render/software/SDL_blendline.h
new file mode 100644
index 0000000..c9a8b20
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_blendline.h
@@ -0,0 +1,30 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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
22#ifndef SDL_blendline_h_
23#define SDL_blendline_h_
24
25#include "SDL_internal.h"
26
27extern bool SDL_BlendLine(SDL_Surface *dst, int x1, int y1, int x2, int y2, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
28extern bool SDL_BlendLines(SDL_Surface *dst, const SDL_Point *points, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
29
30#endif // SDL_blendline_h_
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_blendpoint.c b/contrib/SDL-3.2.8/src/render/software/SDL_blendpoint.c
new file mode 100644
index 0000000..e408453
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_blendpoint.c
@@ -0,0 +1,376 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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#ifdef SDL_VIDEO_RENDER_SW
24
25#include "SDL_draw.h"
26#include "SDL_blendpoint.h"
27
28static bool SDL_BlendPoint_RGB555(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r,
29 Uint8 g, Uint8 b, Uint8 a)
30{
31 unsigned inva = 0xff - a;
32
33 switch (blendMode) {
34 case SDL_BLENDMODE_BLEND:
35 DRAW_SETPIXELXY_BLEND_RGB555(x, y);
36 break;
37 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
38 DRAW_SETPIXELXY_BLEND_CLAMPED_RGB555(x, y);
39 break;
40 case SDL_BLENDMODE_ADD:
41 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
42 DRAW_SETPIXELXY_ADD_RGB555(x, y);
43 break;
44 case SDL_BLENDMODE_MOD:
45 DRAW_SETPIXELXY_MOD_RGB555(x, y);
46 break;
47 case SDL_BLENDMODE_MUL:
48 DRAW_SETPIXELXY_MUL_RGB555(x, y);
49 break;
50 default:
51 DRAW_SETPIXELXY_RGB555(x, y);
52 break;
53 }
54 return true;
55}
56
57static bool SDL_BlendPoint_RGB565(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r,
58 Uint8 g, Uint8 b, Uint8 a)
59{
60 unsigned inva = 0xff - a;
61
62 switch (blendMode) {
63 case SDL_BLENDMODE_BLEND:
64 DRAW_SETPIXELXY_BLEND_RGB565(x, y);
65 break;
66 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
67 DRAW_SETPIXELXY_BLEND_CLAMPED_RGB565(x, y);
68 break;
69 case SDL_BLENDMODE_ADD:
70 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
71 DRAW_SETPIXELXY_ADD_RGB565(x, y);
72 break;
73 case SDL_BLENDMODE_MOD:
74 DRAW_SETPIXELXY_MOD_RGB565(x, y);
75 break;
76 case SDL_BLENDMODE_MUL:
77 DRAW_SETPIXELXY_MUL_RGB565(x, y);
78 break;
79 default:
80 DRAW_SETPIXELXY_RGB565(x, y);
81 break;
82 }
83 return true;
84}
85
86static bool SDL_BlendPoint_XRGB8888(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r,
87 Uint8 g, Uint8 b, Uint8 a)
88{
89 unsigned inva = 0xff - a;
90
91 switch (blendMode) {
92 case SDL_BLENDMODE_BLEND:
93 DRAW_SETPIXELXY_BLEND_XRGB8888(x, y);
94 break;
95 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
96 DRAW_SETPIXELXY_BLEND_CLAMPED_XRGB8888(x, y);
97 break;
98 case SDL_BLENDMODE_ADD:
99 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
100 DRAW_SETPIXELXY_ADD_XRGB8888(x, y);
101 break;
102 case SDL_BLENDMODE_MOD:
103 DRAW_SETPIXELXY_MOD_XRGB8888(x, y);
104 break;
105 case SDL_BLENDMODE_MUL:
106 DRAW_SETPIXELXY_MUL_XRGB8888(x, y);
107 break;
108 default:
109 DRAW_SETPIXELXY_XRGB8888(x, y);
110 break;
111 }
112 return true;
113}
114
115static bool SDL_BlendPoint_ARGB8888(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode,
116 Uint8 r, Uint8 g, Uint8 b, Uint8 a)
117{
118 unsigned inva = 0xff - a;
119
120 switch (blendMode) {
121 case SDL_BLENDMODE_BLEND:
122 DRAW_SETPIXELXY_BLEND_ARGB8888(x, y);
123 break;
124 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
125 DRAW_SETPIXELXY_BLEND_CLAMPED_ARGB8888(x, y);
126 break;
127 case SDL_BLENDMODE_ADD:
128 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
129 DRAW_SETPIXELXY_ADD_ARGB8888(x, y);
130 break;
131 case SDL_BLENDMODE_MOD:
132 DRAW_SETPIXELXY_MOD_ARGB8888(x, y);
133 break;
134 case SDL_BLENDMODE_MUL:
135 DRAW_SETPIXELXY_MUL_ARGB8888(x, y);
136 break;
137 default:
138 DRAW_SETPIXELXY_ARGB8888(x, y);
139 break;
140 }
141 return true;
142}
143
144static bool SDL_BlendPoint_RGB(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r,
145 Uint8 g, Uint8 b, Uint8 a)
146{
147 const SDL_PixelFormatDetails *fmt = dst->fmt;
148 unsigned inva = 0xff - a;
149
150 switch (fmt->bytes_per_pixel) {
151 case 2:
152 switch (blendMode) {
153 case SDL_BLENDMODE_BLEND:
154 DRAW_SETPIXELXY2_BLEND_RGB(x, y);
155 break;
156 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
157 DRAW_SETPIXELXY2_BLEND_CLAMPED_RGB(x, y);
158 break;
159 case SDL_BLENDMODE_ADD:
160 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
161 DRAW_SETPIXELXY2_ADD_RGB(x, y);
162 break;
163 case SDL_BLENDMODE_MOD:
164 DRAW_SETPIXELXY2_MOD_RGB(x, y);
165 break;
166 case SDL_BLENDMODE_MUL:
167 DRAW_SETPIXELXY2_MUL_RGB(x, y);
168 break;
169 default:
170 DRAW_SETPIXELXY2_RGB(x, y);
171 break;
172 }
173 return true;
174 case 4:
175 switch (blendMode) {
176 case SDL_BLENDMODE_BLEND:
177 DRAW_SETPIXELXY4_BLEND_RGB(x, y);
178 break;
179 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
180 DRAW_SETPIXELXY4_BLEND_CLAMPED_RGB(x, y);
181 break;
182 case SDL_BLENDMODE_ADD:
183 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
184 DRAW_SETPIXELXY4_ADD_RGB(x, y);
185 break;
186 case SDL_BLENDMODE_MOD:
187 DRAW_SETPIXELXY4_MOD_RGB(x, y);
188 break;
189 case SDL_BLENDMODE_MUL:
190 DRAW_SETPIXELXY4_MUL_RGB(x, y);
191 break;
192 default:
193 DRAW_SETPIXELXY4_RGB(x, y);
194 break;
195 }
196 return true;
197 default:
198 return SDL_Unsupported();
199 }
200}
201
202static bool SDL_BlendPoint_RGBA(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r,
203 Uint8 g, Uint8 b, Uint8 a)
204{
205 const SDL_PixelFormatDetails *fmt = dst->fmt;
206 unsigned inva = 0xff - a;
207
208 switch (fmt->bytes_per_pixel) {
209 case 4:
210 switch (blendMode) {
211 case SDL_BLENDMODE_BLEND:
212 DRAW_SETPIXELXY4_BLEND_RGBA(x, y);
213 break;
214 case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
215 DRAW_SETPIXELXY4_BLEND_CLAMPED_RGBA(x, y);
216 break;
217 case SDL_BLENDMODE_ADD:
218 case SDL_BLENDMODE_ADD_PREMULTIPLIED:
219 DRAW_SETPIXELXY4_ADD_RGBA(x, y);
220 break;
221 case SDL_BLENDMODE_MOD:
222 DRAW_SETPIXELXY4_MOD_RGBA(x, y);
223 break;
224 case SDL_BLENDMODE_MUL:
225 DRAW_SETPIXELXY4_MUL_RGBA(x, y);
226 break;
227 default:
228 DRAW_SETPIXELXY4_RGBA(x, y);
229 break;
230 }
231 return true;
232 default:
233 return SDL_Unsupported();
234 }
235}
236
237bool SDL_BlendPoint(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
238{
239 if (!SDL_SurfaceValid(dst)) {
240 return SDL_InvalidParamError("SDL_BlendPoint(): dst");
241 }
242
243 // This function doesn't work on surfaces < 8 bpp
244 if (SDL_BITSPERPIXEL(dst->format) < 8) {
245 return SDL_SetError("SDL_BlendPoint(): Unsupported surface format");
246 }
247
248 // Perform clipping
249 if (x < dst->clip_rect.x || y < dst->clip_rect.y ||
250 x >= (dst->clip_rect.x + dst->clip_rect.w) ||
251 y >= (dst->clip_rect.y + dst->clip_rect.h)) {
252 return true;
253 }
254
255 if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
256 r = DRAW_MUL(r, a);
257 g = DRAW_MUL(g, a);
258 b = DRAW_MUL(b, a);
259 }
260
261 switch (dst->fmt->bits_per_pixel) {
262 case 15:
263 switch (dst->fmt->Rmask) {
264 case 0x7C00:
265 return SDL_BlendPoint_RGB555(dst, x, y, blendMode, r, g, b, a);
266 }
267 break;
268 case 16:
269 switch (dst->fmt->Rmask) {
270 case 0xF800:
271 return SDL_BlendPoint_RGB565(dst, x, y, blendMode, r, g, b, a);
272 }
273 break;
274 case 32:
275 switch (dst->fmt->Rmask) {
276 case 0x00FF0000:
277 if (!dst->fmt->Amask) {
278 return SDL_BlendPoint_XRGB8888(dst, x, y, blendMode, r, g, b, a);
279 } else {
280 return SDL_BlendPoint_ARGB8888(dst, x, y, blendMode, r, g, b, a);
281 }
282 // break; -Wunreachable-code-break
283 }
284 break;
285 default:
286 break;
287 }
288
289 if (!dst->fmt->Amask) {
290 return SDL_BlendPoint_RGB(dst, x, y, blendMode, r, g, b, a);
291 } else {
292 return SDL_BlendPoint_RGBA(dst, x, y, blendMode, r, g, b, a);
293 }
294}
295
296bool SDL_BlendPoints(SDL_Surface *dst, const SDL_Point *points, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
297{
298 int minx, miny;
299 int maxx, maxy;
300 int i;
301 int x, y;
302 bool (*func)(SDL_Surface * dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) = NULL;
303 bool result = true;
304
305 if (!SDL_SurfaceValid(dst)) {
306 return SDL_InvalidParamError("SDL_BlendPoints(): dst");
307 }
308
309 // This function doesn't work on surfaces < 8 bpp
310 if (dst->fmt->bits_per_pixel < 8) {
311 return SDL_SetError("SDL_BlendPoints(): Unsupported surface format");
312 }
313
314 if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
315 r = DRAW_MUL(r, a);
316 g = DRAW_MUL(g, a);
317 b = DRAW_MUL(b, a);
318 }
319
320 // FIXME: Does this function pointer slow things down significantly?
321 switch (dst->fmt->bits_per_pixel) {
322 case 15:
323 switch (dst->fmt->Rmask) {
324 case 0x7C00:
325 func = SDL_BlendPoint_RGB555;
326 break;
327 }
328 break;
329 case 16:
330 switch (dst->fmt->Rmask) {
331 case 0xF800:
332 func = SDL_BlendPoint_RGB565;
333 break;
334 }
335 break;
336 case 32:
337 switch (dst->fmt->Rmask) {
338 case 0x00FF0000:
339 if (!dst->fmt->Amask) {
340 func = SDL_BlendPoint_XRGB8888;
341 } else {
342 func = SDL_BlendPoint_ARGB8888;
343 }
344 break;
345 }
346 break;
347 default:
348 break;
349 }
350
351 if (!func) {
352 if (!dst->fmt->Amask) {
353 func = SDL_BlendPoint_RGB;
354 } else {
355 func = SDL_BlendPoint_RGBA;
356 }
357 }
358
359 minx = dst->clip_rect.x;
360 maxx = dst->clip_rect.x + dst->clip_rect.w - 1;
361 miny = dst->clip_rect.y;
362 maxy = dst->clip_rect.y + dst->clip_rect.h - 1;
363
364 for (i = 0; i < count; ++i) {
365 x = points[i].x;
366 y = points[i].y;
367
368 if (x < minx || x > maxx || y < miny || y > maxy) {
369 continue;
370 }
371 result = func(dst, x, y, blendMode, r, g, b, a);
372 }
373 return result;
374}
375
376#endif // SDL_VIDEO_RENDER_SW
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_blendpoint.h b/contrib/SDL-3.2.8/src/render/software/SDL_blendpoint.h
new file mode 100644
index 0000000..6dfe49a
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_blendpoint.h
@@ -0,0 +1,30 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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
22#ifndef SDL_blendpoint_h_
23#define SDL_blendpoint_h_
24
25#include "SDL_internal.h"
26
27extern bool SDL_BlendPoint(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
28extern bool SDL_BlendPoints(SDL_Surface *dst, const SDL_Point *points, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
29
30#endif // SDL_blendpoint_h_
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_draw.h b/contrib/SDL-3.2.8/src/render/software/SDL_draw.h
new file mode 100644
index 0000000..ec77527
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_draw.h
@@ -0,0 +1,723 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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#include "../../video/SDL_surface_c.h"
24
25/* This code assumes that r, g, b, a are the source color,
26 * and in the blend and add case, the RGB values are premultiplied by a.
27 */
28
29#define DRAW_MUL(_a, _b) (((unsigned)(_a) * (_b)) / 255)
30
31#define DRAW_FASTSETPIXEL(type) \
32 *pixel = (type)color
33
34#define DRAW_FASTSETPIXEL1 DRAW_FASTSETPIXEL(Uint8)
35#define DRAW_FASTSETPIXEL2 DRAW_FASTSETPIXEL(Uint16)
36#define DRAW_FASTSETPIXEL4 DRAW_FASTSETPIXEL(Uint32)
37
38#define DRAW_FASTSETPIXELXY(x, y, type, bpp, color) \
39 *(type *)((Uint8 *)dst->pixels + (y)*dst->pitch + (x)*bpp) = (type)color
40
41#define DRAW_FASTSETPIXELXY1(x, y) DRAW_FASTSETPIXELXY(x, y, Uint8, 1, color)
42#define DRAW_FASTSETPIXELXY2(x, y) DRAW_FASTSETPIXELXY(x, y, Uint16, 2, color)
43#define DRAW_FASTSETPIXELXY4(x, y) DRAW_FASTSETPIXELXY(x, y, Uint32, 4, color)
44
45#define DRAW_SETPIXEL(setpixel) \
46 do { \
47 unsigned sr = r, sg = g, sb = b, sa = a; \
48 (void)sa; \
49 setpixel; \
50 } while (0)
51
52#define DRAW_SETPIXEL_BLEND(getpixel, setpixel) \
53 do { \
54 unsigned sr, sg, sb, sa = 0xFF; \
55 getpixel; \
56 sr = DRAW_MUL(inva, sr) + r; \
57 sg = DRAW_MUL(inva, sg) + g; \
58 sb = DRAW_MUL(inva, sb) + b; \
59 sa = DRAW_MUL(inva, sa) + a; \
60 setpixel; \
61 } while (0)
62
63#define DRAW_SETPIXEL_BLEND_CLAMPED(getpixel, setpixel) \
64 do { \
65 unsigned sr, sg, sb, sa = 0xFF; \
66 getpixel; \
67 sr = DRAW_MUL(inva, sr) + r; \
68 if (sr > 0xff) \
69 sr = 0xff; \
70 sg = DRAW_MUL(inva, sg) + g; \
71 if (sg > 0xff) \
72 sg = 0xff; \
73 sb = DRAW_MUL(inva, sb) + b; \
74 if (sb > 0xff) \
75 sb = 0xff; \
76 sa = DRAW_MUL(inva, sa) + a; \
77 if (sa > 0xff) \
78 sa = 0xff; \
79 setpixel; \
80 } while (0)
81
82#define DRAW_SETPIXEL_ADD(getpixel, setpixel) \
83 do { \
84 unsigned sr, sg, sb, sa; \
85 (void)sa; \
86 getpixel; \
87 sr += r; \
88 if (sr > 0xff) \
89 sr = 0xff; \
90 sg += g; \
91 if (sg > 0xff) \
92 sg = 0xff; \
93 sb += b; \
94 if (sb > 0xff) \
95 sb = 0xff; \
96 setpixel; \
97 } while (0)
98
99#define DRAW_SETPIXEL_MOD(getpixel, setpixel) \
100 do { \
101 unsigned sr, sg, sb, sa; \
102 (void)sa; \
103 getpixel; \
104 sr = DRAW_MUL(sr, r); \
105 sg = DRAW_MUL(sg, g); \
106 sb = DRAW_MUL(sb, b); \
107 setpixel; \
108 } while (0)
109
110#define DRAW_SETPIXEL_MUL(getpixel, setpixel) \
111 do { \
112 unsigned sr, sg, sb, sa; \
113 (void)sa; \
114 getpixel; \
115 sr = DRAW_MUL(sr, r) + DRAW_MUL(inva, sr); \
116 if (sr > 0xff) \
117 sr = 0xff; \
118 sg = DRAW_MUL(sg, g) + DRAW_MUL(inva, sg); \
119 if (sg > 0xff) \
120 sg = 0xff; \
121 sb = DRAW_MUL(sb, b) + DRAW_MUL(inva, sb); \
122 if (sb > 0xff) \
123 sb = 0xff; \
124 setpixel; \
125 } while (0)
126
127#define DRAW_SETPIXELXY(x, y, type, bpp, op) \
128 do { \
129 type *pixel = (type *)((Uint8 *)dst->pixels + (y)*dst->pitch + (x)*bpp); \
130 op; \
131 } while (0)
132
133/*
134 * Define draw operators for RGB555
135 */
136
137#define DRAW_SETPIXEL_RGB555 \
138 DRAW_SETPIXEL(RGB555_FROM_RGB(*pixel, sr, sg, sb))
139
140#define DRAW_SETPIXEL_BLEND_RGB555 \
141 DRAW_SETPIXEL_BLEND(RGB_FROM_RGB555(*pixel, sr, sg, sb), \
142 RGB555_FROM_RGB(*pixel, sr, sg, sb))
143
144#define DRAW_SETPIXEL_BLEND_CLAMPED_RGB555 \
145 DRAW_SETPIXEL_BLEND_CLAMPED(RGB_FROM_RGB555(*pixel, sr, sg, sb), \
146 RGB555_FROM_RGB(*pixel, sr, sg, sb))
147
148#define DRAW_SETPIXEL_ADD_RGB555 \
149 DRAW_SETPIXEL_ADD(RGB_FROM_RGB555(*pixel, sr, sg, sb), \
150 RGB555_FROM_RGB(*pixel, sr, sg, sb))
151
152#define DRAW_SETPIXEL_MOD_RGB555 \
153 DRAW_SETPIXEL_MOD(RGB_FROM_RGB555(*pixel, sr, sg, sb), \
154 RGB555_FROM_RGB(*pixel, sr, sg, sb))
155
156#define DRAW_SETPIXEL_MUL_RGB555 \
157 DRAW_SETPIXEL_MUL(RGB_FROM_RGB555(*pixel, sr, sg, sb), \
158 RGB555_FROM_RGB(*pixel, sr, sg, sb))
159
160#define DRAW_SETPIXELXY_RGB555(x, y) \
161 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_RGB555)
162
163#define DRAW_SETPIXELXY_BLEND_RGB555(x, y) \
164 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_RGB555)
165
166#define DRAW_SETPIXELXY_BLEND_CLAMPED_RGB555(x, y) \
167 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_CLAMPED_RGB555)
168
169#define DRAW_SETPIXELXY_ADD_RGB555(x, y) \
170 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_ADD_RGB555)
171
172#define DRAW_SETPIXELXY_MOD_RGB555(x, y) \
173 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MOD_RGB555)
174
175#define DRAW_SETPIXELXY_MUL_RGB555(x, y) \
176 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MUL_RGB555)
177
178/*
179 * Define draw operators for RGB565
180 */
181
182#define DRAW_SETPIXEL_RGB565 \
183 DRAW_SETPIXEL(RGB565_FROM_RGB(*pixel, sr, sg, sb))
184
185#define DRAW_SETPIXEL_BLEND_RGB565 \
186 DRAW_SETPIXEL_BLEND(RGB_FROM_RGB565(*pixel, sr, sg, sb), \
187 RGB565_FROM_RGB(*pixel, sr, sg, sb))
188
189#define DRAW_SETPIXEL_BLEND_CLAMPED_RGB565 \
190 DRAW_SETPIXEL_BLEND_CLAMPED(RGB_FROM_RGB565(*pixel, sr, sg, sb), \
191 RGB565_FROM_RGB(*pixel, sr, sg, sb))
192
193#define DRAW_SETPIXEL_ADD_RGB565 \
194 DRAW_SETPIXEL_ADD(RGB_FROM_RGB565(*pixel, sr, sg, sb), \
195 RGB565_FROM_RGB(*pixel, sr, sg, sb))
196
197#define DRAW_SETPIXEL_MOD_RGB565 \
198 DRAW_SETPIXEL_MOD(RGB_FROM_RGB565(*pixel, sr, sg, sb), \
199 RGB565_FROM_RGB(*pixel, sr, sg, sb))
200
201#define DRAW_SETPIXEL_MUL_RGB565 \
202 DRAW_SETPIXEL_MUL(RGB_FROM_RGB565(*pixel, sr, sg, sb), \
203 RGB565_FROM_RGB(*pixel, sr, sg, sb))
204
205#define DRAW_SETPIXELXY_RGB565(x, y) \
206 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_RGB565)
207
208#define DRAW_SETPIXELXY_BLEND_RGB565(x, y) \
209 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_RGB565)
210
211#define DRAW_SETPIXELXY_BLEND_CLAMPED_RGB565(x, y) \
212 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_CLAMPED_RGB565)
213
214#define DRAW_SETPIXELXY_ADD_RGB565(x, y) \
215 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_ADD_RGB565)
216
217#define DRAW_SETPIXELXY_MOD_RGB565(x, y) \
218 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MOD_RGB565)
219
220#define DRAW_SETPIXELXY_MUL_RGB565(x, y) \
221 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MUL_RGB565)
222
223/*
224 * Define draw operators for RGB888
225 */
226
227#define DRAW_SETPIXEL_XRGB8888 \
228 DRAW_SETPIXEL(XRGB8888_FROM_RGB(*pixel, sr, sg, sb))
229
230#define DRAW_SETPIXEL_BLEND_XRGB8888 \
231 DRAW_SETPIXEL_BLEND(RGB_FROM_XRGB8888(*pixel, sr, sg, sb), \
232 XRGB8888_FROM_RGB(*pixel, sr, sg, sb))
233
234#define DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888 \
235 DRAW_SETPIXEL_BLEND_CLAMPED(RGB_FROM_XRGB8888(*pixel, sr, sg, sb), \
236 XRGB8888_FROM_RGB(*pixel, sr, sg, sb))
237
238#define DRAW_SETPIXEL_ADD_XRGB8888 \
239 DRAW_SETPIXEL_ADD(RGB_FROM_XRGB8888(*pixel, sr, sg, sb), \
240 XRGB8888_FROM_RGB(*pixel, sr, sg, sb))
241
242#define DRAW_SETPIXEL_MOD_XRGB8888 \
243 DRAW_SETPIXEL_MOD(RGB_FROM_XRGB8888(*pixel, sr, sg, sb), \
244 XRGB8888_FROM_RGB(*pixel, sr, sg, sb))
245
246#define DRAW_SETPIXEL_MUL_XRGB8888 \
247 DRAW_SETPIXEL_MUL(RGB_FROM_XRGB8888(*pixel, sr, sg, sb), \
248 XRGB8888_FROM_RGB(*pixel, sr, sg, sb))
249
250#define DRAW_SETPIXELXY_XRGB8888(x, y) \
251 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_XRGB8888)
252
253#define DRAW_SETPIXELXY_BLEND_XRGB8888(x, y) \
254 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_XRGB8888)
255
256#define DRAW_SETPIXELXY_BLEND_CLAMPED_XRGB8888(x, y) \
257 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888)
258
259#define DRAW_SETPIXELXY_ADD_XRGB8888(x, y) \
260 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_ADD_XRGB8888)
261
262#define DRAW_SETPIXELXY_MOD_XRGB8888(x, y) \
263 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MOD_XRGB8888)
264
265#define DRAW_SETPIXELXY_MUL_XRGB8888(x, y) \
266 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MUL_XRGB8888)
267
268/*
269 * Define draw operators for ARGB8888
270 */
271
272#define DRAW_SETPIXEL_ARGB8888 \
273 DRAW_SETPIXEL(ARGB8888_FROM_RGBA(*pixel, sr, sg, sb, sa))
274
275#define DRAW_SETPIXEL_BLEND_ARGB8888 \
276 DRAW_SETPIXEL_BLEND(RGBA_FROM_ARGB8888(*pixel, sr, sg, sb, sa), \
277 ARGB8888_FROM_RGBA(*pixel, sr, sg, sb, sa))
278
279#define DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888 \
280 DRAW_SETPIXEL_BLEND_CLAMPED(RGBA_FROM_ARGB8888(*pixel, sr, sg, sb, sa), \
281 ARGB8888_FROM_RGBA(*pixel, sr, sg, sb, sa))
282
283#define DRAW_SETPIXEL_ADD_ARGB8888 \
284 DRAW_SETPIXEL_ADD(RGBA_FROM_ARGB8888(*pixel, sr, sg, sb, sa), \
285 ARGB8888_FROM_RGBA(*pixel, sr, sg, sb, sa))
286
287#define DRAW_SETPIXEL_MOD_ARGB8888 \
288 DRAW_SETPIXEL_MOD(RGBA_FROM_ARGB8888(*pixel, sr, sg, sb, sa), \
289 ARGB8888_FROM_RGBA(*pixel, sr, sg, sb, sa))
290
291#define DRAW_SETPIXEL_MUL_ARGB8888 \
292 DRAW_SETPIXEL_MUL(RGBA_FROM_ARGB8888(*pixel, sr, sg, sb, sa), \
293 ARGB8888_FROM_RGBA(*pixel, sr, sg, sb, sa))
294
295#define DRAW_SETPIXELXY_ARGB8888(x, y) \
296 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_ARGB8888)
297
298#define DRAW_SETPIXELXY_BLEND_ARGB8888(x, y) \
299 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_ARGB8888)
300
301#define DRAW_SETPIXELXY_BLEND_CLAMPED_ARGB8888(x, y) \
302 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888)
303
304#define DRAW_SETPIXELXY_ADD_ARGB8888(x, y) \
305 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_ADD_ARGB8888)
306
307#define DRAW_SETPIXELXY_MOD_ARGB8888(x, y) \
308 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MOD_ARGB8888)
309
310#define DRAW_SETPIXELXY_MUL_ARGB8888(x, y) \
311 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MUL_ARGB8888)
312
313/*
314 * Define draw operators for general RGB
315 */
316
317#define DRAW_SETPIXEL_RGB \
318 DRAW_SETPIXEL(PIXEL_FROM_RGB(*pixel, fmt, sr, sg, sb))
319
320#define DRAW_SETPIXEL_BLEND_RGB \
321 DRAW_SETPIXEL_BLEND(RGB_FROM_PIXEL(*pixel, fmt, sr, sg, sb), \
322 PIXEL_FROM_RGB(*pixel, fmt, sr, sg, sb))
323
324#define DRAW_SETPIXEL_BLEND_CLAMPED_RGB \
325 DRAW_SETPIXEL_BLEND_CLAMPED(RGB_FROM_PIXEL(*pixel, fmt, sr, sg, sb), \
326 PIXEL_FROM_RGB(*pixel, fmt, sr, sg, sb))
327
328#define DRAW_SETPIXEL_ADD_RGB \
329 DRAW_SETPIXEL_ADD(RGB_FROM_PIXEL(*pixel, fmt, sr, sg, sb), \
330 PIXEL_FROM_RGB(*pixel, fmt, sr, sg, sb))
331
332#define DRAW_SETPIXEL_MOD_RGB \
333 DRAW_SETPIXEL_MOD(RGB_FROM_PIXEL(*pixel, fmt, sr, sg, sb), \
334 PIXEL_FROM_RGB(*pixel, fmt, sr, sg, sb))
335
336#define DRAW_SETPIXEL_MUL_RGB \
337 DRAW_SETPIXEL_MUL(RGB_FROM_PIXEL(*pixel, fmt, sr, sg, sb), \
338 PIXEL_FROM_RGB(*pixel, fmt, sr, sg, sb))
339
340#define DRAW_SETPIXELXY2_RGB(x, y) \
341 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_RGB)
342
343#define DRAW_SETPIXELXY4_RGB(x, y) \
344 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_RGB)
345
346#define DRAW_SETPIXELXY2_BLEND_RGB(x, y) \
347 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_RGB)
348
349#define DRAW_SETPIXELXY2_BLEND_CLAMPED_RGB(x, y) \
350 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_CLAMPED_RGB)
351
352#define DRAW_SETPIXELXY4_BLEND_RGB(x, y) \
353 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_RGB)
354
355#define DRAW_SETPIXELXY4_BLEND_CLAMPED_RGB(x, y) \
356 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_CLAMPED_RGB)
357
358#define DRAW_SETPIXELXY2_ADD_RGB(x, y) \
359 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_ADD_RGB)
360
361#define DRAW_SETPIXELXY4_ADD_RGB(x, y) \
362 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_ADD_RGB)
363
364#define DRAW_SETPIXELXY2_MOD_RGB(x, y) \
365 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MOD_RGB)
366
367#define DRAW_SETPIXELXY4_MOD_RGB(x, y) \
368 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MOD_RGB)
369
370#define DRAW_SETPIXELXY2_MUL_RGB(x, y) \
371 DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MUL_RGB)
372
373#define DRAW_SETPIXELXY4_MUL_RGB(x, y) \
374 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MUL_RGB)
375
376/*
377 * Define draw operators for general RGBA
378 */
379
380#define DRAW_SETPIXEL_RGBA \
381 DRAW_SETPIXEL(PIXEL_FROM_RGBA(*pixel, fmt, sr, sg, sb, sa))
382
383#define DRAW_SETPIXEL_BLEND_RGBA \
384 DRAW_SETPIXEL_BLEND(RGBA_FROM_PIXEL(*pixel, fmt, sr, sg, sb, sa), \
385 PIXEL_FROM_RGBA(*pixel, fmt, sr, sg, sb, sa))
386
387#define DRAW_SETPIXEL_BLEND_CLAMPED_RGBA \
388 DRAW_SETPIXEL_BLEND_CLAMPED(RGBA_FROM_PIXEL(*pixel, fmt, sr, sg, sb, sa), \
389 PIXEL_FROM_RGBA(*pixel, fmt, sr, sg, sb, sa))
390
391#define DRAW_SETPIXEL_ADD_RGBA \
392 DRAW_SETPIXEL_ADD(RGBA_FROM_PIXEL(*pixel, fmt, sr, sg, sb, sa), \
393 PIXEL_FROM_RGBA(*pixel, fmt, sr, sg, sb, sa))
394
395#define DRAW_SETPIXEL_MOD_RGBA \
396 DRAW_SETPIXEL_MOD(RGBA_FROM_PIXEL(*pixel, fmt, sr, sg, sb, sa), \
397 PIXEL_FROM_RGBA(*pixel, fmt, sr, sg, sb, sa))
398
399#define DRAW_SETPIXEL_MUL_RGBA \
400 DRAW_SETPIXEL_MUL(RGBA_FROM_PIXEL(*pixel, fmt, sr, sg, sb, sa), \
401 PIXEL_FROM_RGBA(*pixel, fmt, sr, sg, sb, sa))
402
403#define DRAW_SETPIXELXY4_RGBA(x, y) \
404 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_RGBA)
405
406#define DRAW_SETPIXELXY4_BLEND_RGBA(x, y) \
407 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_RGBA)
408
409#define DRAW_SETPIXELXY4_BLEND_CLAMPED_RGBA(x, y) \
410 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_CLAMPED_RGBA)
411
412#define DRAW_SETPIXELXY4_ADD_RGBA(x, y) \
413 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_ADD_RGBA)
414
415#define DRAW_SETPIXELXY4_MOD_RGBA(x, y) \
416 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MOD_RGBA)
417
418#define DRAW_SETPIXELXY4_MUL_RGBA(x, y) \
419 DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MUL_RGBA)
420
421/*
422 * Define line drawing macro
423 */
424
425#define ABS(_x) ((_x) < 0 ? -(_x) : (_x))
426
427// Horizontal line
428#define HLINE(type, op, draw_end) \
429 { \
430 int length; \
431 int pitch = (dst->pitch / dst->fmt->bytes_per_pixel); \
432 type *pixel; \
433 if (x1 <= x2) { \
434 pixel = (type *)dst->pixels + y1 * pitch + x1; \
435 length = draw_end ? (x2 - x1 + 1) : (x2 - x1); \
436 } else { \
437 pixel = (type *)dst->pixels + y1 * pitch + x2; \
438 if (!draw_end) { \
439 ++pixel; \
440 } \
441 length = draw_end ? (x1 - x2 + 1) : (x1 - x2); \
442 } \
443 while (length--) { \
444 op; \
445 ++pixel; \
446 } \
447 }
448
449// Vertical line
450#define VLINE(type, op, draw_end) \
451 { \
452 int length; \
453 int pitch = (dst->pitch / dst->fmt->bytes_per_pixel); \
454 type *pixel; \
455 if (y1 <= y2) { \
456 pixel = (type *)dst->pixels + y1 * pitch + x1; \
457 length = draw_end ? (y2 - y1 + 1) : (y2 - y1); \
458 } else { \
459 pixel = (type *)dst->pixels + y2 * pitch + x1; \
460 if (!draw_end) { \
461 pixel += pitch; \
462 } \
463 length = draw_end ? (y1 - y2 + 1) : (y1 - y2); \
464 } \
465 while (length--) { \
466 op; \
467 pixel += pitch; \
468 } \
469 }
470
471// Diagonal line
472#define DLINE(type, op, draw_end) \
473 { \
474 int length; \
475 int pitch = (dst->pitch / dst->fmt->bytes_per_pixel); \
476 type *pixel; \
477 if (y1 <= y2) { \
478 pixel = (type *)dst->pixels + y1 * pitch + x1; \
479 if (x1 <= x2) { \
480 ++pitch; \
481 } else { \
482 --pitch; \
483 } \
484 length = (y2 - y1); \
485 } else { \
486 pixel = (type *)dst->pixels + y2 * pitch + x2; \
487 if (x2 <= x1) { \
488 ++pitch; \
489 } else { \
490 --pitch; \
491 } \
492 if (!draw_end) { \
493 pixel += pitch; \
494 } \
495 length = (y1 - y2); \
496 } \
497 if (draw_end) { \
498 ++length; \
499 } \
500 while (length--) { \
501 op; \
502 pixel += pitch; \
503 } \
504 }
505
506// Bresenham's line algorithm
507#define BLINE(x1, y1, x2, y2, op, draw_end) \
508 { \
509 int i, deltax, deltay, numpixels; \
510 int d, dinc1, dinc2; \
511 int x, xinc1, xinc2; \
512 int y, yinc1, yinc2; \
513 \
514 deltax = ABS(x2 - x1); \
515 deltay = ABS(y2 - y1); \
516 \
517 if (deltax >= deltay) { \
518 numpixels = deltax + 1; \
519 d = (2 * deltay) - deltax; \
520 dinc1 = deltay * 2; \
521 dinc2 = (deltay - deltax) * 2; \
522 xinc1 = 1; \
523 xinc2 = 1; \
524 yinc1 = 0; \
525 yinc2 = 1; \
526 } else { \
527 numpixels = deltay + 1; \
528 d = (2 * deltax) - deltay; \
529 dinc1 = deltax * 2; \
530 dinc2 = (deltax - deltay) * 2; \
531 xinc1 = 0; \
532 xinc2 = 1; \
533 yinc1 = 1; \
534 yinc2 = 1; \
535 } \
536 \
537 if (x1 > x2) { \
538 xinc1 = -xinc1; \
539 xinc2 = -xinc2; \
540 } \
541 if (y1 > y2) { \
542 yinc1 = -yinc1; \
543 yinc2 = -yinc2; \
544 } \
545 \
546 x = x1; \
547 y = y1; \
548 \
549 if (!draw_end) { \
550 --numpixels; \
551 } \
552 for (i = 0; i < numpixels; ++i) { \
553 op(x, y); \
554 if (d < 0) { \
555 d += dinc1; \
556 x += xinc1; \
557 y += yinc1; \
558 } else { \
559 d += dinc2; \
560 x += xinc2; \
561 y += yinc2; \
562 } \
563 } \
564 }
565
566// Xiaolin Wu's line algorithm, based on Michael Abrash's implementation
567#define WULINE(x1, y1, x2, y2, opaque_op, blend_op, draw_end) \
568 { \
569 Uint16 ErrorAdj, ErrorAcc; \
570 Uint16 ErrorAccTemp, Weighting; \
571 int DeltaX, DeltaY, Temp, XDir; \
572 unsigned r, g, b, a, inva; \
573 \
574 /* Draw the initial pixel, which is always exactly intersected by \
575 the line and so needs no weighting */ \
576 opaque_op(x1, y1); \
577 \
578 /* Draw the final pixel, which is always exactly intersected by the line \
579 and so needs no weighting */ \
580 if (draw_end) { \
581 opaque_op(x2, y2); \
582 } \
583 \
584 /* Make sure the line runs top to bottom */ \
585 if (y1 > y2) { \
586 Temp = y1; \
587 y1 = y2; \
588 y2 = Temp; \
589 Temp = x1; \
590 x1 = x2; \
591 x2 = Temp; \
592 } \
593 DeltaY = y2 - y1; \
594 \
595 if ((DeltaX = x2 - x1) >= 0) { \
596 XDir = 1; \
597 } else { \
598 XDir = -1; \
599 DeltaX = -DeltaX; /* make DeltaX positive */ \
600 } \
601 \
602 /* line is not horizontal, diagonal, or vertical */ \
603 ErrorAcc = 0; /* initialize the line error accumulator to 0 */ \
604 \
605 /* Is this an X-major or Y-major line? */ \
606 if (DeltaY > DeltaX) { \
607 /* Y-major line; calculate 16-bit fixed-point fractional part of a \
608 pixel that X advances each time Y advances 1 pixel, truncating the \
609 result so that we won't overrun the endpoint along the X axis */ \
610 ErrorAdj = ((unsigned long)DeltaX << 16) / (unsigned long)DeltaY; \
611 /* Draw all pixels other than the first and last */ \
612 while (--DeltaY) { \
613 ErrorAccTemp = ErrorAcc; /* remember current accumulated error */ \
614 ErrorAcc += ErrorAdj; /* calculate error for next pixel */ \
615 if (ErrorAcc <= ErrorAccTemp) { \
616 /* The error accumulator turned over, so advance the X coord */ \
617 x1 += XDir; \
618 } \
619 y1++; /* Y-major, so always advance Y */ \
620 /* The IntensityBits most significant bits of ErrorAcc give us the \
621 intensity weighting for this pixel, and the complement of the \
622 weighting for the paired pixel */ \
623 Weighting = ErrorAcc >> 8; \
624 { \
625 a = DRAW_MUL(_a, (Weighting ^ 255)); \
626 r = DRAW_MUL(_r, a); \
627 g = DRAW_MUL(_g, a); \
628 b = DRAW_MUL(_b, a); \
629 inva = (a ^ 0xFF); \
630 blend_op(x1, y1); \
631 } \
632 { \
633 a = DRAW_MUL(_a, Weighting); \
634 r = DRAW_MUL(_r, a); \
635 g = DRAW_MUL(_g, a); \
636 b = DRAW_MUL(_b, a); \
637 inva = (a ^ 0xFF); \
638 blend_op(x1 + XDir, y1); \
639 } \
640 } \
641 } else { \
642 /* X-major line; calculate 16-bit fixed-point fractional part of a \
643 pixel that Y advances each time X advances 1 pixel, truncating the \
644 result to avoid overrunning the endpoint along the X axis */ \
645 ErrorAdj = ((unsigned long)DeltaY << 16) / (unsigned long)DeltaX; \
646 /* Draw all pixels other than the first and last */ \
647 while (--DeltaX) { \
648 ErrorAccTemp = ErrorAcc; /* remember current accumulated error */ \
649 ErrorAcc += ErrorAdj; /* calculate error for next pixel */ \
650 if (ErrorAcc <= ErrorAccTemp) { \
651 /* The error accumulator turned over, so advance the Y coord */ \
652 y1++; \
653 } \
654 x1 += XDir; /* X-major, so always advance X */ \
655 /* The IntensityBits most significant bits of ErrorAcc give us the \
656 intensity weighting for this pixel, and the complement of the \
657 weighting for the paired pixel */ \
658 Weighting = ErrorAcc >> 8; \
659 { \
660 a = DRAW_MUL(_a, (Weighting ^ 255)); \
661 r = DRAW_MUL(_r, a); \
662 g = DRAW_MUL(_g, a); \
663 b = DRAW_MUL(_b, a); \
664 inva = (a ^ 0xFF); \
665 blend_op(x1, y1); \
666 } \
667 { \
668 a = DRAW_MUL(_a, Weighting); \
669 r = DRAW_MUL(_r, a); \
670 g = DRAW_MUL(_g, a); \
671 b = DRAW_MUL(_b, a); \
672 inva = (a ^ 0xFF); \
673 blend_op(x1, y1 + 1); \
674 } \
675 } \
676 } \
677 }
678
679#ifdef AA_LINES
680#define AALINE(x1, y1, x2, y2, opaque_op, blend_op, draw_end) \
681 WULINE(x1, y1, x2, y2, opaque_op, blend_op, draw_end)
682#else
683#define AALINE(x1, y1, x2, y2, opaque_op, blend_op, draw_end) \
684 BLINE(x1, y1, x2, y2, opaque_op, draw_end)
685#endif
686
687/*
688 * Define fill rect macro
689 */
690
691#define FILLRECT(type, op) \
692 do { \
693 int width = rect->w; \
694 int height = rect->h; \
695 int pitch = (dst->pitch / dst->fmt->bytes_per_pixel); \
696 int skip = pitch - width; \
697 type *pixel = (type *)dst->pixels + rect->y * pitch + rect->x; \
698 while (height--) { \
699 { \
700 int n = (width + 3) / 4; \
701 switch (width & 3) { \
702 case 0: \
703 do { \
704 op; \
705 pixel++; \
706 SDL_FALLTHROUGH; \
707 case 3: \
708 op; \
709 pixel++; \
710 SDL_FALLTHROUGH; \
711 case 2: \
712 op; \
713 pixel++; \
714 SDL_FALLTHROUGH; \
715 case 1: \
716 op; \
717 pixel++; \
718 } while (--n > 0); \
719 } \
720 } \
721 pixel += skip; \
722 } \
723 } while (0)
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_drawline.c b/contrib/SDL-3.2.8/src/render/software/SDL_drawline.c
new file mode 100644
index 0000000..59ba268
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_drawline.c
@@ -0,0 +1,199 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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#ifdef SDL_VIDEO_RENDER_SW
24
25#include "SDL_draw.h"
26#include "SDL_drawline.h"
27#include "SDL_drawpoint.h"
28
29static void SDL_DrawLine1(SDL_Surface *dst, int x1, int y1, int x2, int y2, Uint32 color,
30 bool draw_end)
31{
32 if (y1 == y2) {
33 int length;
34 int pitch = (dst->pitch / dst->fmt->bytes_per_pixel);
35 Uint8 *pixel;
36 if (x1 <= x2) {
37 pixel = (Uint8 *)dst->pixels + y1 * pitch + x1;
38 length = draw_end ? (x2 - x1 + 1) : (x2 - x1);
39 } else {
40 pixel = (Uint8 *)dst->pixels + y1 * pitch + x2;
41 if (!draw_end) {
42 ++pixel;
43 }
44 length = draw_end ? (x1 - x2 + 1) : (x1 - x2);
45 }
46 SDL_memset(pixel, color, length);
47 } else if (x1 == x2) {
48 VLINE(Uint8, DRAW_FASTSETPIXEL1, draw_end);
49 } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
50 DLINE(Uint8, DRAW_FASTSETPIXEL1, draw_end);
51 } else {
52 BLINE(x1, y1, x2, y2, DRAW_FASTSETPIXELXY1, draw_end);
53 }
54}
55
56static void SDL_DrawLine2(SDL_Surface *dst, int x1, int y1, int x2, int y2, Uint32 color,
57 bool draw_end)
58{
59 if (y1 == y2) {
60 HLINE(Uint16, DRAW_FASTSETPIXEL2, draw_end);
61 } else if (x1 == x2) {
62 VLINE(Uint16, DRAW_FASTSETPIXEL2, draw_end);
63 } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
64 DLINE(Uint16, DRAW_FASTSETPIXEL2, draw_end);
65 } else {
66 Uint8 _r, _g, _b, _a;
67 const SDL_PixelFormatDetails *fmt = dst->fmt;
68 SDL_GetRGBA(color, fmt, dst->palette, &_r, &_g, &_b, &_a);
69 if (fmt->Rmask == 0x7C00) {
70 AALINE(x1, y1, x2, y2,
71 DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY_BLEND_RGB555,
72 draw_end);
73 } else if (fmt->Rmask == 0xF800) {
74 AALINE(x1, y1, x2, y2,
75 DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY_BLEND_RGB565,
76 draw_end);
77 } else {
78 AALINE(x1, y1, x2, y2,
79 DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY2_BLEND_RGB,
80 draw_end);
81 }
82 }
83}
84
85static void SDL_DrawLine4(SDL_Surface *dst, int x1, int y1, int x2, int y2, Uint32 color,
86 bool draw_end)
87{
88 if (y1 == y2) {
89 HLINE(Uint32, DRAW_FASTSETPIXEL4, draw_end);
90 } else if (x1 == x2) {
91 VLINE(Uint32, DRAW_FASTSETPIXEL4, draw_end);
92 } else if (ABS(x1 - x2) == ABS(y1 - y2)) {
93 DLINE(Uint32, DRAW_FASTSETPIXEL4, draw_end);
94 } else {
95 Uint8 _r, _g, _b, _a;
96 const SDL_PixelFormatDetails *fmt = dst->fmt;
97 SDL_GetRGBA(color, fmt, dst->palette, &_r, &_g, &_b, &_a);
98 if (fmt->Rmask == 0x00FF0000) {
99 if (!fmt->Amask) {
100 AALINE(x1, y1, x2, y2,
101 DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY_BLEND_XRGB8888,
102 draw_end);
103 } else {
104 AALINE(x1, y1, x2, y2,
105 DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY_BLEND_ARGB8888,
106 draw_end);
107 }
108 } else {
109 AALINE(x1, y1, x2, y2,
110 DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY4_BLEND_RGB,
111 draw_end);
112 }
113 }
114}
115
116typedef void (*DrawLineFunc)(SDL_Surface *dst,
117 int x1, int y1, int x2, int y2,
118 Uint32 color, bool draw_end);
119
120static DrawLineFunc SDL_CalculateDrawLineFunc(const SDL_PixelFormatDetails *fmt)
121{
122 switch (fmt->bytes_per_pixel) {
123 case 1:
124 if (fmt->bits_per_pixel < 8) {
125 break;
126 }
127 return SDL_DrawLine1;
128 case 2:
129 return SDL_DrawLine2;
130 case 4:
131 return SDL_DrawLine4;
132 }
133 return NULL;
134}
135
136bool SDL_DrawLine(SDL_Surface *dst, int x1, int y1, int x2, int y2, Uint32 color)
137{
138 DrawLineFunc func;
139
140 if (!SDL_SurfaceValid(dst)) {
141 return SDL_InvalidParamError("SDL_DrawLine(): dst");
142 }
143
144 func = SDL_CalculateDrawLineFunc(dst->fmt);
145 if (!func) {
146 return SDL_SetError("SDL_DrawLine(): Unsupported surface format");
147 }
148
149 // Perform clipping
150 // FIXME: We don't actually want to clip, as it may change line slope
151 if (!SDL_GetRectAndLineIntersection(&dst->clip_rect, &x1, &y1, &x2, &y2)) {
152 return true;
153 }
154
155 func(dst, x1, y1, x2, y2, color, true);
156 return true;
157}
158
159bool SDL_DrawLines(SDL_Surface *dst, const SDL_Point *points, int count, Uint32 color)
160{
161 int i;
162 int x1, y1;
163 int x2, y2;
164 bool draw_end;
165 DrawLineFunc func;
166
167 if (!SDL_SurfaceValid(dst)) {
168 return SDL_InvalidParamError("SDL_DrawLines(): dst");
169 }
170
171 func = SDL_CalculateDrawLineFunc(dst->fmt);
172 if (!func) {
173 return SDL_SetError("SDL_DrawLines(): Unsupported surface format");
174 }
175
176 for (i = 1; i < count; ++i) {
177 x1 = points[i - 1].x;
178 y1 = points[i - 1].y;
179 x2 = points[i].x;
180 y2 = points[i].y;
181
182 // Perform clipping
183 // FIXME: We don't actually want to clip, as it may change line slope
184 if (!SDL_GetRectAndLineIntersection(&dst->clip_rect, &x1, &y1, &x2, &y2)) {
185 continue;
186 }
187
188 // Draw the end if the whole line is a single point or it was clipped
189 draw_end = ((x1 == x2) && (y1 == y2)) || (x2 != points[i].x || y2 != points[i].y);
190
191 func(dst, x1, y1, x2, y2, color, draw_end);
192 }
193 if (points[0].x != points[count - 1].x || points[0].y != points[count - 1].y) {
194 SDL_DrawPoint(dst, points[count - 1].x, points[count - 1].y, color);
195 }
196 return true;
197}
198
199#endif // SDL_VIDEO_RENDER_SW
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_drawline.h b/contrib/SDL-3.2.8/src/render/software/SDL_drawline.h
new file mode 100644
index 0000000..e88b2c3
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_drawline.h
@@ -0,0 +1,30 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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
22#ifndef SDL_drawline_h_
23#define SDL_drawline_h_
24
25#include "SDL_internal.h"
26
27extern bool SDL_DrawLine(SDL_Surface *dst, int x1, int y1, int x2, int y2, Uint32 color);
28extern bool SDL_DrawLines(SDL_Surface *dst, const SDL_Point *points, int count, Uint32 color);
29
30#endif // SDL_drawline_h_
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_drawpoint.c b/contrib/SDL-3.2.8/src/render/software/SDL_drawpoint.c
new file mode 100644
index 0000000..5aa28b3
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_drawpoint.c
@@ -0,0 +1,108 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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#ifdef SDL_VIDEO_RENDER_SW
24
25#include "SDL_draw.h"
26#include "SDL_drawpoint.h"
27
28bool SDL_DrawPoint(SDL_Surface *dst, int x, int y, Uint32 color)
29{
30 if (!SDL_SurfaceValid(dst)) {
31 return SDL_InvalidParamError("SDL_DrawPoint(): dst");
32 }
33
34 // This function doesn't work on surfaces < 8 bpp
35 if (dst->fmt->bits_per_pixel < 8) {
36 return SDL_SetError("SDL_DrawPoint(): Unsupported surface format");
37 }
38
39 // Perform clipping
40 if (x < dst->clip_rect.x || y < dst->clip_rect.y ||
41 x >= (dst->clip_rect.x + dst->clip_rect.w) ||
42 y >= (dst->clip_rect.y + dst->clip_rect.h)) {
43 return true;
44 }
45
46 switch (dst->fmt->bytes_per_pixel) {
47 case 1:
48 DRAW_FASTSETPIXELXY1(x, y);
49 break;
50 case 2:
51 DRAW_FASTSETPIXELXY2(x, y);
52 break;
53 case 3:
54 return SDL_Unsupported();
55 case 4:
56 DRAW_FASTSETPIXELXY4(x, y);
57 break;
58 }
59 return true;
60}
61
62bool SDL_DrawPoints(SDL_Surface *dst, const SDL_Point *points, int count, Uint32 color)
63{
64 int minx, miny;
65 int maxx, maxy;
66 int i;
67 int x, y;
68
69 if (!SDL_SurfaceValid(dst)) {
70 return SDL_InvalidParamError("SDL_DrawPoints(): dst");
71 }
72
73 // This function doesn't work on surfaces < 8 bpp
74 if (dst->fmt->bits_per_pixel < 8) {
75 return SDL_SetError("SDL_DrawPoints(): Unsupported surface format");
76 }
77
78 minx = dst->clip_rect.x;
79 maxx = dst->clip_rect.x + dst->clip_rect.w - 1;
80 miny = dst->clip_rect.y;
81 maxy = dst->clip_rect.y + dst->clip_rect.h - 1;
82
83 for (i = 0; i < count; ++i) {
84 x = points[i].x;
85 y = points[i].y;
86
87 if (x < minx || x > maxx || y < miny || y > maxy) {
88 continue;
89 }
90
91 switch (dst->fmt->bytes_per_pixel) {
92 case 1:
93 DRAW_FASTSETPIXELXY1(x, y);
94 break;
95 case 2:
96 DRAW_FASTSETPIXELXY2(x, y);
97 break;
98 case 3:
99 return SDL_Unsupported();
100 case 4:
101 DRAW_FASTSETPIXELXY4(x, y);
102 break;
103 }
104 }
105 return true;
106}
107
108#endif // SDL_VIDEO_RENDER_SW
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_drawpoint.h b/contrib/SDL-3.2.8/src/render/software/SDL_drawpoint.h
new file mode 100644
index 0000000..631e7aa
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_drawpoint.h
@@ -0,0 +1,30 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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
22#ifndef SDL_drawpoint_h_
23#define SDL_drawpoint_h_
24
25#include "SDL_internal.h"
26
27extern bool SDL_DrawPoint(SDL_Surface *dst, int x, int y, Uint32 color);
28extern bool SDL_DrawPoints(SDL_Surface *dst, const SDL_Point *points, int count, Uint32 color);
29
30#endif // SDL_drawpoint_h_
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_render_sw.c b/contrib/SDL-3.2.8/src/render/software/SDL_render_sw.c
new file mode 100644
index 0000000..2231724
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_render_sw.c
@@ -0,0 +1,1202 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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#ifdef SDL_VIDEO_RENDER_SW
24
25#include "../SDL_sysrender.h"
26#include "SDL_render_sw_c.h"
27
28#include "SDL_draw.h"
29#include "SDL_blendfillrect.h"
30#include "SDL_blendline.h"
31#include "SDL_blendpoint.h"
32#include "SDL_drawline.h"
33#include "SDL_drawpoint.h"
34#include "SDL_rotate.h"
35#include "SDL_triangle.h"
36#include "../../video/SDL_pixels_c.h"
37
38// SDL surface based renderer implementation
39
40typedef struct
41{
42 const SDL_Rect *viewport;
43 const SDL_Rect *cliprect;
44 bool surface_cliprect_dirty;
45 SDL_Color color;
46} SW_DrawStateCache;
47
48typedef struct
49{
50 SDL_Surface *surface;
51 SDL_Surface *window;
52} SW_RenderData;
53
54static SDL_Surface *SW_ActivateRenderer(SDL_Renderer *renderer)
55{
56 SW_RenderData *data = (SW_RenderData *)renderer->internal;
57
58 if (!data->surface) {
59 data->surface = data->window;
60 }
61 if (!data->surface) {
62 SDL_Surface *surface = SDL_GetWindowSurface(renderer->window);
63 if (surface) {
64 data->surface = data->window = surface;
65 }
66 }
67 return data->surface;
68}
69
70static void SW_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event)
71{
72 SW_RenderData *data = (SW_RenderData *)renderer->internal;
73
74 if (event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) {
75 data->surface = NULL;
76 data->window = NULL;
77 }
78}
79
80static bool SW_GetOutputSize(SDL_Renderer *renderer, int *w, int *h)
81{
82 SW_RenderData *data = (SW_RenderData *)renderer->internal;
83
84 if (data->surface) {
85 if (w) {
86 *w = data->surface->w;
87 }
88 if (h) {
89 *h = data->surface->h;
90 }
91 return true;
92 }
93
94 if (renderer->window) {
95 SDL_GetWindowSizeInPixels(renderer->window, w, h);
96 return true;
97 }
98
99 return SDL_SetError("Software renderer doesn't have an output surface");
100}
101
102static bool SW_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
103{
104 SDL_Surface *surface = SDL_CreateSurface(texture->w, texture->h, texture->format);
105 Uint8 r, g, b, a;
106
107 if (!SDL_SurfaceValid(surface)) {
108 return SDL_SetError("Cannot create surface");
109 }
110 texture->internal = surface;
111 r = (Uint8)SDL_roundf(SDL_clamp(texture->color.r, 0.0f, 1.0f) * 255.0f);
112 g = (Uint8)SDL_roundf(SDL_clamp(texture->color.g, 0.0f, 1.0f) * 255.0f);
113 b = (Uint8)SDL_roundf(SDL_clamp(texture->color.b, 0.0f, 1.0f) * 255.0f);
114 a = (Uint8)SDL_roundf(SDL_clamp(texture->color.a, 0.0f, 1.0f) * 255.0f);
115 SDL_SetSurfaceColorMod(surface, r, g, b);
116 SDL_SetSurfaceAlphaMod(surface, a);
117 SDL_SetSurfaceBlendMode(surface, texture->blendMode);
118
119 /* Only RLE encode textures without an alpha channel since the RLE coder
120 * discards the color values of pixels with an alpha value of zero.
121 */
122 if (texture->access == SDL_TEXTUREACCESS_STATIC && !SDL_ISPIXELFORMAT_ALPHA(surface->format)) {
123 SDL_SetSurfaceRLE(surface, 1);
124 }
125
126 return true;
127}
128
129static bool SW_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
130 const SDL_Rect *rect, const void *pixels, int pitch)
131{
132 SDL_Surface *surface = (SDL_Surface *)texture->internal;
133 Uint8 *src, *dst;
134 int row;
135 size_t length;
136
137 if (SDL_MUSTLOCK(surface)) {
138 if (!SDL_LockSurface(surface)) {
139 return false;
140 }
141 }
142 src = (Uint8 *)pixels;
143 dst = (Uint8 *)surface->pixels +
144 rect->y * surface->pitch +
145 rect->x * surface->fmt->bytes_per_pixel;
146 length = (size_t)rect->w * surface->fmt->bytes_per_pixel;
147 for (row = 0; row < rect->h; ++row) {
148 SDL_memcpy(dst, src, length);
149 src += pitch;
150 dst += surface->pitch;
151 }
152 if (SDL_MUSTLOCK(surface)) {
153 SDL_UnlockSurface(surface);
154 }
155 return true;
156}
157
158static bool SW_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
159 const SDL_Rect *rect, void **pixels, int *pitch)
160{
161 SDL_Surface *surface = (SDL_Surface *)texture->internal;
162
163 *pixels =
164 (void *)((Uint8 *)surface->pixels + rect->y * surface->pitch +
165 rect->x * surface->fmt->bytes_per_pixel);
166 *pitch = surface->pitch;
167 return true;
168}
169
170static void SW_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
171{
172}
173
174static void SW_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
175{
176}
177
178static bool SW_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
179{
180 SW_RenderData *data = (SW_RenderData *)renderer->internal;
181
182 if (texture) {
183 data->surface = (SDL_Surface *)texture->internal;
184 } else {
185 data->surface = data->window;
186 }
187 return true;
188}
189
190static bool SW_QueueNoOp(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
191{
192 return true; // nothing to do in this backend.
193}
194
195static bool SW_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
196{
197 SDL_Point *verts = (SDL_Point *)SDL_AllocateRenderVertices(renderer, count * sizeof(SDL_Point), 0, &cmd->data.draw.first);
198 int i;
199
200 if (!verts) {
201 return false;
202 }
203
204 cmd->data.draw.count = count;
205
206 for (i = 0; i < count; i++, verts++, points++) {
207 verts->x = (int)points->x;
208 verts->y = (int)points->y;
209 }
210
211 return true;
212}
213
214static bool SW_QueueFillRects(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FRect *rects, int count)
215{
216 SDL_Rect *verts = (SDL_Rect *)SDL_AllocateRenderVertices(renderer, count * sizeof(SDL_Rect), 0, &cmd->data.draw.first);
217 int i;
218
219 if (!verts) {
220 return false;
221 }
222
223 cmd->data.draw.count = count;
224
225 for (i = 0; i < count; i++, verts++, rects++) {
226 verts->x = (int)rects->x;
227 verts->y = (int)rects->y;
228 verts->w = SDL_max((int)rects->w, 1);
229 verts->h = SDL_max((int)rects->h, 1);
230 }
231
232 return true;
233}
234
235static bool SW_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
236 const SDL_FRect *srcrect, const SDL_FRect *dstrect)
237{
238 SDL_Rect *verts = (SDL_Rect *)SDL_AllocateRenderVertices(renderer, 2 * sizeof(SDL_Rect), 0, &cmd->data.draw.first);
239
240 if (!verts) {
241 return false;
242 }
243
244 cmd->data.draw.count = 1;
245
246 verts->x = (int)srcrect->x;
247 verts->y = (int)srcrect->y;
248 verts->w = (int)srcrect->w;
249 verts->h = (int)srcrect->h;
250 verts++;
251
252 verts->x = (int)dstrect->x;
253 verts->y = (int)dstrect->y;
254 verts->w = (int)dstrect->w;
255 verts->h = (int)dstrect->h;
256
257 return true;
258}
259
260typedef struct CopyExData
261{
262 SDL_Rect srcrect;
263 SDL_Rect dstrect;
264 double angle;
265 SDL_FPoint center;
266 SDL_FlipMode flip;
267 float scale_x;
268 float scale_y;
269} CopyExData;
270
271static bool SW_QueueCopyEx(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
272 const SDL_FRect *srcrect, const SDL_FRect *dstrect,
273 const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y)
274{
275 CopyExData *verts = (CopyExData *)SDL_AllocateRenderVertices(renderer, sizeof(CopyExData), 0, &cmd->data.draw.first);
276
277 if (!verts) {
278 return false;
279 }
280
281 cmd->data.draw.count = 1;
282
283 verts->srcrect.x = (int)srcrect->x;
284 verts->srcrect.y = (int)srcrect->y;
285 verts->srcrect.w = (int)srcrect->w;
286 verts->srcrect.h = (int)srcrect->h;
287 verts->dstrect.x = (int)dstrect->x;
288 verts->dstrect.y = (int)dstrect->y;
289 verts->dstrect.w = (int)dstrect->w;
290 verts->dstrect.h = (int)dstrect->h;
291 verts->angle = angle;
292 SDL_copyp(&verts->center, center);
293 verts->flip = flip;
294 verts->scale_x = scale_x;
295 verts->scale_y = scale_y;
296
297 return true;
298}
299
300static bool Blit_to_Screen(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *surface, SDL_Rect *dstrect,
301 float scale_x, float scale_y, SDL_ScaleMode scaleMode)
302{
303 bool result;
304 // Renderer scaling, if needed
305 if (scale_x != 1.0f || scale_y != 1.0f) {
306 SDL_Rect r;
307 r.x = (int)((float)dstrect->x * scale_x);
308 r.y = (int)((float)dstrect->y * scale_y);
309 r.w = (int)((float)dstrect->w * scale_x);
310 r.h = (int)((float)dstrect->h * scale_y);
311 result = SDL_BlitSurfaceScaled(src, srcrect, surface, &r, scaleMode);
312 } else {
313 result = SDL_BlitSurface(src, srcrect, surface, dstrect);
314 }
315 return result;
316}
317
318static bool SW_RenderCopyEx(SDL_Renderer *renderer, SDL_Surface *surface, SDL_Texture *texture,
319 const SDL_Rect *srcrect, const SDL_Rect *final_rect,
320 const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y)
321{
322 SDL_Surface *src = (SDL_Surface *)texture->internal;
323 SDL_Rect tmp_rect;
324 SDL_Surface *src_clone, *src_rotated, *src_scaled;
325 SDL_Surface *mask = NULL, *mask_rotated = NULL;
326 bool result = true;
327 SDL_BlendMode blendmode;
328 Uint8 alphaMod, rMod, gMod, bMod;
329 int applyModulation = false;
330 int blitRequired = false;
331 int isOpaque = false;
332
333 if (!SDL_SurfaceValid(surface)) {
334 return false;
335 }
336
337 tmp_rect.x = 0;
338 tmp_rect.y = 0;
339 tmp_rect.w = final_rect->w;
340 tmp_rect.h = final_rect->h;
341
342 /* It is possible to encounter an RLE encoded surface here and locking it is
343 * necessary because this code is going to access the pixel buffer directly.
344 */
345 if (SDL_MUSTLOCK(src)) {
346 if (!SDL_LockSurface(src)) {
347 return false;
348 }
349 }
350
351 /* Clone the source surface but use its pixel buffer directly.
352 * The original source surface must be treated as read-only.
353 */
354 src_clone = SDL_CreateSurfaceFrom(src->w, src->h, src->format, src->pixels, src->pitch);
355 if (!src_clone) {
356 if (SDL_MUSTLOCK(src)) {
357 SDL_UnlockSurface(src);
358 }
359 return false;
360 }
361
362 SDL_GetSurfaceBlendMode(src, &blendmode);
363 SDL_GetSurfaceAlphaMod(src, &alphaMod);
364 SDL_GetSurfaceColorMod(src, &rMod, &gMod, &bMod);
365
366 // SDLgfx_rotateSurface only accepts 32-bit surfaces with a 8888 layout. Everything else has to be converted.
367 if (src->fmt->bits_per_pixel != 32 || SDL_PIXELLAYOUT(src->format) != SDL_PACKEDLAYOUT_8888 || !SDL_ISPIXELFORMAT_ALPHA(src->format)) {
368 blitRequired = true;
369 }
370
371 // If scaling and cropping is necessary, it has to be taken care of before the rotation.
372 if (!(srcrect->w == final_rect->w && srcrect->h == final_rect->h && srcrect->x == 0 && srcrect->y == 0)) {
373 blitRequired = true;
374 }
375
376 // srcrect is not selecting the whole src surface, so cropping is needed
377 if (!(srcrect->w == src->w && srcrect->h == src->h && srcrect->x == 0 && srcrect->y == 0)) {
378 blitRequired = true;
379 }
380
381 // The color and alpha modulation has to be applied before the rotation when using the NONE, MOD or MUL blend modes.
382 if ((blendmode == SDL_BLENDMODE_NONE || blendmode == SDL_BLENDMODE_MOD || blendmode == SDL_BLENDMODE_MUL) && (alphaMod & rMod & gMod & bMod) != 255) {
383 applyModulation = true;
384 SDL_SetSurfaceAlphaMod(src_clone, alphaMod);
385 SDL_SetSurfaceColorMod(src_clone, rMod, gMod, bMod);
386 }
387
388 // Opaque surfaces are much easier to handle with the NONE blend mode.
389 if (blendmode == SDL_BLENDMODE_NONE && !SDL_ISPIXELFORMAT_ALPHA(src->format) && alphaMod == 255) {
390 isOpaque = true;
391 }
392
393 /* The NONE blend mode requires a mask for non-opaque surfaces. This mask will be used
394 * to clear the pixels in the destination surface. The other steps are explained below.
395 */
396 if (blendmode == SDL_BLENDMODE_NONE && !isOpaque) {
397 mask = SDL_CreateSurface(final_rect->w, final_rect->h, SDL_PIXELFORMAT_ARGB8888);
398 if (!mask) {
399 result = false;
400 } else {
401 SDL_SetSurfaceBlendMode(mask, SDL_BLENDMODE_MOD);
402 }
403 }
404
405 /* Create a new surface should there be a format mismatch or if scaling, cropping,
406 * or modulation is required. It's possible to use the source surface directly otherwise.
407 */
408 if (result && (blitRequired || applyModulation)) {
409 SDL_Rect scale_rect = tmp_rect;
410 src_scaled = SDL_CreateSurface(final_rect->w, final_rect->h, SDL_PIXELFORMAT_ARGB8888);
411 if (!src_scaled) {
412 result = false;
413 } else {
414 SDL_SetSurfaceBlendMode(src_clone, SDL_BLENDMODE_NONE);
415 result = SDL_BlitSurfaceScaled(src_clone, srcrect, src_scaled, &scale_rect, texture->scaleMode);
416 SDL_DestroySurface(src_clone);
417 src_clone = src_scaled;
418 src_scaled = NULL;
419 }
420 }
421
422 // SDLgfx_rotateSurface is going to make decisions depending on the blend mode.
423 SDL_SetSurfaceBlendMode(src_clone, blendmode);
424
425 if (result) {
426 SDL_Rect rect_dest;
427 double cangle, sangle;
428
429 SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, angle, center,
430 &rect_dest, &cangle, &sangle);
431 src_rotated = SDLgfx_rotateSurface(src_clone, angle,
432 (texture->scaleMode == SDL_SCALEMODE_NEAREST) ? 0 : 1, flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL,
433 &rect_dest, cangle, sangle, center);
434 if (!src_rotated) {
435 result = false;
436 }
437 if (result && mask) {
438 // The mask needed for the NONE blend mode gets rotated with the same parameters.
439 mask_rotated = SDLgfx_rotateSurface(mask, angle,
440 false, 0, 0,
441 &rect_dest, cangle, sangle, center);
442 if (!mask_rotated) {
443 result = false;
444 }
445 }
446 if (result) {
447
448 tmp_rect.x = final_rect->x + rect_dest.x;
449 tmp_rect.y = final_rect->y + rect_dest.y;
450 tmp_rect.w = rect_dest.w;
451 tmp_rect.h = rect_dest.h;
452
453 /* The NONE blend mode needs some special care with non-opaque surfaces.
454 * Other blend modes or opaque surfaces can be blitted directly.
455 */
456 if (blendmode != SDL_BLENDMODE_NONE || isOpaque) {
457 if (applyModulation == false) {
458 // If the modulation wasn't already applied, make it happen now.
459 SDL_SetSurfaceAlphaMod(src_rotated, alphaMod);
460 SDL_SetSurfaceColorMod(src_rotated, rMod, gMod, bMod);
461 }
462 // Renderer scaling, if needed
463 result = Blit_to_Screen(src_rotated, NULL, surface, &tmp_rect, scale_x, scale_y, texture->scaleMode);
464 } else {
465 /* The NONE blend mode requires three steps to get the pixels onto the destination surface.
466 * First, the area where the rotated pixels will be blitted to get set to zero.
467 * This is accomplished by simply blitting a mask with the NONE blend mode.
468 * The colorkey set by the rotate function will discard the correct pixels.
469 */
470 SDL_Rect mask_rect = tmp_rect;
471 SDL_SetSurfaceBlendMode(mask_rotated, SDL_BLENDMODE_NONE);
472 // Renderer scaling, if needed
473 result = Blit_to_Screen(mask_rotated, NULL, surface, &mask_rect, scale_x, scale_y, texture->scaleMode);
474 if (result) {
475 /* The next step copies the alpha value. This is done with the BLEND blend mode and
476 * by modulating the source colors with 0. Since the destination is all zeros, this
477 * will effectively set the destination alpha to the source alpha.
478 */
479 SDL_SetSurfaceColorMod(src_rotated, 0, 0, 0);
480 mask_rect = tmp_rect;
481 // Renderer scaling, if needed
482 result = Blit_to_Screen(src_rotated, NULL, surface, &mask_rect, scale_x, scale_y, texture->scaleMode);
483 if (result) {
484 /* The last step gets the color values in place. The ADD blend mode simply adds them to
485 * the destination (where the color values are all zero). However, because the ADD blend
486 * mode modulates the colors with the alpha channel, a surface without an alpha mask needs
487 * to be created. This makes all source pixels opaque and the colors get copied correctly.
488 */
489 SDL_Surface *src_rotated_rgb = SDL_CreateSurfaceFrom(src_rotated->w, src_rotated->h, src_rotated->format, src_rotated->pixels, src_rotated->pitch);
490 if (!src_rotated_rgb) {
491 result = false;
492 } else {
493 SDL_SetSurfaceBlendMode(src_rotated_rgb, SDL_BLENDMODE_ADD);
494 // Renderer scaling, if needed
495 result = Blit_to_Screen(src_rotated_rgb, NULL, surface, &tmp_rect, scale_x, scale_y, texture->scaleMode);
496 SDL_DestroySurface(src_rotated_rgb);
497 }
498 }
499 }
500 SDL_DestroySurface(mask_rotated);
501 }
502 if (src_rotated) {
503 SDL_DestroySurface(src_rotated);
504 }
505 }
506 }
507
508 if (SDL_MUSTLOCK(src)) {
509 SDL_UnlockSurface(src);
510 }
511 if (mask) {
512 SDL_DestroySurface(mask);
513 }
514 if (src_clone) {
515 SDL_DestroySurface(src_clone);
516 }
517 return result;
518}
519
520typedef struct GeometryFillData
521{
522 SDL_Point dst;
523 SDL_Color color;
524} GeometryFillData;
525
526typedef struct GeometryCopyData
527{
528 SDL_Point src;
529 SDL_Point dst;
530 SDL_Color color;
531} GeometryCopyData;
532
533static bool SW_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
534 const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride,
535 int num_vertices, const void *indices, int num_indices, int size_indices,
536 float scale_x, float scale_y)
537{
538 int i;
539 int count = indices ? num_indices : num_vertices;
540 void *verts;
541 size_t sz = texture ? sizeof(GeometryCopyData) : sizeof(GeometryFillData);
542 const float color_scale = cmd->data.draw.color_scale;
543
544 verts = SDL_AllocateRenderVertices(renderer, count * sz, 0, &cmd->data.draw.first);
545 if (!verts) {
546 return false;
547 }
548
549 cmd->data.draw.count = count;
550 size_indices = indices ? size_indices : 0;
551
552 if (texture) {
553 GeometryCopyData *ptr = (GeometryCopyData *)verts;
554 for (i = 0; i < count; i++) {
555 int j;
556 float *xy_;
557 SDL_FColor col_;
558 float *uv_;
559 if (size_indices == 4) {
560 j = ((const Uint32 *)indices)[i];
561 } else if (size_indices == 2) {
562 j = ((const Uint16 *)indices)[i];
563 } else if (size_indices == 1) {
564 j = ((const Uint8 *)indices)[i];
565 } else {
566 j = i;
567 }
568
569 xy_ = (float *)((char *)xy + j * xy_stride);
570 col_ = *(SDL_FColor *)((char *)color + j * color_stride);
571
572 uv_ = (float *)((char *)uv + j * uv_stride);
573
574 ptr->src.x = (int)(uv_[0] * texture->w);
575 ptr->src.y = (int)(uv_[1] * texture->h);
576
577 ptr->dst.x = (int)(xy_[0] * scale_x);
578 ptr->dst.y = (int)(xy_[1] * scale_y);
579 trianglepoint_2_fixedpoint(&ptr->dst);
580
581 ptr->color.r = (Uint8)SDL_roundf(SDL_clamp(col_.r * color_scale, 0.0f, 1.0f) * 255.0f);
582 ptr->color.g = (Uint8)SDL_roundf(SDL_clamp(col_.g * color_scale, 0.0f, 1.0f) * 255.0f);
583 ptr->color.b = (Uint8)SDL_roundf(SDL_clamp(col_.b * color_scale, 0.0f, 1.0f) * 255.0f);
584 ptr->color.a = (Uint8)SDL_roundf(SDL_clamp(col_.a, 0.0f, 1.0f) * 255.0f);
585
586 ptr++;
587 }
588 } else {
589 GeometryFillData *ptr = (GeometryFillData *)verts;
590
591 for (i = 0; i < count; i++) {
592 int j;
593 float *xy_;
594 SDL_FColor col_;
595 if (size_indices == 4) {
596 j = ((const Uint32 *)indices)[i];
597 } else if (size_indices == 2) {
598 j = ((const Uint16 *)indices)[i];
599 } else if (size_indices == 1) {
600 j = ((const Uint8 *)indices)[i];
601 } else {
602 j = i;
603 }
604
605 xy_ = (float *)((char *)xy + j * xy_stride);
606 col_ = *(SDL_FColor *)((char *)color + j * color_stride);
607
608 ptr->dst.x = (int)(xy_[0] * scale_x);
609 ptr->dst.y = (int)(xy_[1] * scale_y);
610 trianglepoint_2_fixedpoint(&ptr->dst);
611
612 ptr->color.r = (Uint8)SDL_roundf(SDL_clamp(col_.r * color_scale, 0.0f, 1.0f) * 255.0f);
613 ptr->color.g = (Uint8)SDL_roundf(SDL_clamp(col_.g * color_scale, 0.0f, 1.0f) * 255.0f);
614 ptr->color.b = (Uint8)SDL_roundf(SDL_clamp(col_.b * color_scale, 0.0f, 1.0f) * 255.0f);
615 ptr->color.a = (Uint8)SDL_roundf(SDL_clamp(col_.a, 0.0f, 1.0f) * 255.0f);
616
617 ptr++;
618 }
619 }
620 return true;
621}
622
623static void PrepTextureForCopy(const SDL_RenderCommand *cmd, SW_DrawStateCache *drawstate)
624{
625 const Uint8 r = drawstate->color.r;
626 const Uint8 g = drawstate->color.g;
627 const Uint8 b = drawstate->color.b;
628 const Uint8 a = drawstate->color.a;
629 const SDL_BlendMode blend = cmd->data.draw.blend;
630 SDL_Texture *texture = cmd->data.draw.texture;
631 SDL_Surface *surface = (SDL_Surface *)texture->internal;
632 const bool colormod = ((r & g & b) != 0xFF);
633 const bool alphamod = (a != 0xFF);
634 const bool blending = ((blend == SDL_BLENDMODE_ADD) || (blend == SDL_BLENDMODE_MOD) || (blend == SDL_BLENDMODE_MUL));
635
636 if (colormod || alphamod || blending) {
637 SDL_SetSurfaceRLE(surface, 0);
638 }
639
640 // !!! FIXME: we can probably avoid some of these calls.
641 SDL_SetSurfaceColorMod(surface, r, g, b);
642 SDL_SetSurfaceAlphaMod(surface, a);
643 SDL_SetSurfaceBlendMode(surface, blend);
644}
645
646static void SetDrawState(SDL_Surface *surface, SW_DrawStateCache *drawstate)
647{
648 if (drawstate->surface_cliprect_dirty) {
649 const SDL_Rect *viewport = drawstate->viewport;
650 const SDL_Rect *cliprect = drawstate->cliprect;
651 SDL_assert_release(viewport != NULL); // the higher level should have forced a SDL_RENDERCMD_SETVIEWPORT
652
653 if (cliprect && viewport) {
654 SDL_Rect clip_rect;
655 clip_rect.x = cliprect->x + viewport->x;
656 clip_rect.y = cliprect->y + viewport->y;
657 clip_rect.w = cliprect->w;
658 clip_rect.h = cliprect->h;
659 SDL_GetRectIntersection(viewport, &clip_rect, &clip_rect);
660 SDL_SetSurfaceClipRect(surface, &clip_rect);
661 } else {
662 SDL_SetSurfaceClipRect(surface, drawstate->viewport);
663 }
664 drawstate->surface_cliprect_dirty = false;
665 }
666}
667
668static void SW_InvalidateCachedState(SDL_Renderer *renderer)
669{
670 // SW_DrawStateCache only lives during SW_RunCommandQueue, so nothing to do here!
671}
672
673
674static bool SW_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
675{
676 SDL_Surface *surface = SW_ActivateRenderer(renderer);
677 SW_DrawStateCache drawstate;
678
679 if (!SDL_SurfaceValid(surface)) {
680 return false;
681 }
682
683 drawstate.viewport = NULL;
684 drawstate.cliprect = NULL;
685 drawstate.surface_cliprect_dirty = true;
686 drawstate.color.r = 0;
687 drawstate.color.g = 0;
688 drawstate.color.b = 0;
689 drawstate.color.a = 0;
690
691 while (cmd) {
692 switch (cmd->command) {
693 case SDL_RENDERCMD_SETDRAWCOLOR:
694 {
695 drawstate.color.r = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.r * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f);
696 drawstate.color.g = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.g * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f);
697 drawstate.color.b = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.b * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f);
698 drawstate.color.a = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.a, 0.0f, 1.0f) * 255.0f);
699 break;
700 }
701
702 case SDL_RENDERCMD_SETVIEWPORT:
703 {
704 drawstate.viewport = &cmd->data.viewport.rect;
705 drawstate.surface_cliprect_dirty = true;
706 break;
707 }
708
709 case SDL_RENDERCMD_SETCLIPRECT:
710 {
711 drawstate.cliprect = cmd->data.cliprect.enabled ? &cmd->data.cliprect.rect : NULL;
712 drawstate.surface_cliprect_dirty = true;
713 break;
714 }
715
716 case SDL_RENDERCMD_CLEAR:
717 {
718 const Uint8 r = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.r * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f);
719 const Uint8 g = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.g * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f);
720 const Uint8 b = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.b * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f);
721 const Uint8 a = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.a, 0.0f, 1.0f) * 255.0f);
722 // By definition the clear ignores the clip rect
723 SDL_SetSurfaceClipRect(surface, NULL);
724 SDL_FillSurfaceRect(surface, NULL, SDL_MapSurfaceRGBA(surface, r, g, b, a));
725 drawstate.surface_cliprect_dirty = true;
726 break;
727 }
728
729 case SDL_RENDERCMD_DRAW_POINTS:
730 {
731 const Uint8 r = drawstate.color.r;
732 const Uint8 g = drawstate.color.g;
733 const Uint8 b = drawstate.color.b;
734 const Uint8 a = drawstate.color.a;
735 const int count = (int)cmd->data.draw.count;
736 SDL_Point *verts = (SDL_Point *)(((Uint8 *)vertices) + cmd->data.draw.first);
737 const SDL_BlendMode blend = cmd->data.draw.blend;
738 SetDrawState(surface, &drawstate);
739
740 // Apply viewport
741 if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) {
742 int i;
743 for (i = 0; i < count; i++) {
744 verts[i].x += drawstate.viewport->x;
745 verts[i].y += drawstate.viewport->y;
746 }
747 }
748
749 if (blend == SDL_BLENDMODE_NONE) {
750 SDL_DrawPoints(surface, verts, count, SDL_MapSurfaceRGBA(surface, r, g, b, a));
751 } else {
752 SDL_BlendPoints(surface, verts, count, blend, r, g, b, a);
753 }
754 break;
755 }
756
757 case SDL_RENDERCMD_DRAW_LINES:
758 {
759 const Uint8 r = drawstate.color.r;
760 const Uint8 g = drawstate.color.g;
761 const Uint8 b = drawstate.color.b;
762 const Uint8 a = drawstate.color.a;
763 const int count = (int)cmd->data.draw.count;
764 SDL_Point *verts = (SDL_Point *)(((Uint8 *)vertices) + cmd->data.draw.first);
765 const SDL_BlendMode blend = cmd->data.draw.blend;
766 SetDrawState(surface, &drawstate);
767
768 // Apply viewport
769 if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) {
770 int i;
771 for (i = 0; i < count; i++) {
772 verts[i].x += drawstate.viewport->x;
773 verts[i].y += drawstate.viewport->y;
774 }
775 }
776
777 if (blend == SDL_BLENDMODE_NONE) {
778 SDL_DrawLines(surface, verts, count, SDL_MapSurfaceRGBA(surface, r, g, b, a));
779 } else {
780 SDL_BlendLines(surface, verts, count, blend, r, g, b, a);
781 }
782 break;
783 }
784
785 case SDL_RENDERCMD_FILL_RECTS:
786 {
787 const Uint8 r = drawstate.color.r;
788 const Uint8 g = drawstate.color.g;
789 const Uint8 b = drawstate.color.b;
790 const Uint8 a = drawstate.color.a;
791 const int count = (int)cmd->data.draw.count;
792 SDL_Rect *verts = (SDL_Rect *)(((Uint8 *)vertices) + cmd->data.draw.first);
793 const SDL_BlendMode blend = cmd->data.draw.blend;
794 SetDrawState(surface, &drawstate);
795
796 // Apply viewport
797 if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) {
798 int i;
799 for (i = 0; i < count; i++) {
800 verts[i].x += drawstate.viewport->x;
801 verts[i].y += drawstate.viewport->y;
802 }
803 }
804
805 if (blend == SDL_BLENDMODE_NONE) {
806 SDL_FillSurfaceRects(surface, verts, count, SDL_MapSurfaceRGBA(surface, r, g, b, a));
807 } else {
808 SDL_BlendFillRects(surface, verts, count, blend, r, g, b, a);
809 }
810 break;
811 }
812
813 case SDL_RENDERCMD_COPY:
814 {
815 SDL_Rect *verts = (SDL_Rect *)(((Uint8 *)vertices) + cmd->data.draw.first);
816 const SDL_Rect *srcrect = verts;
817 SDL_Rect *dstrect = verts + 1;
818 SDL_Texture *texture = cmd->data.draw.texture;
819 SDL_Surface *src = (SDL_Surface *)texture->internal;
820
821 SetDrawState(surface, &drawstate);
822
823 PrepTextureForCopy(cmd, &drawstate);
824
825 // Apply viewport
826 if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) {
827 dstrect->x += drawstate.viewport->x;
828 dstrect->y += drawstate.viewport->y;
829 }
830
831 if (srcrect->w == dstrect->w && srcrect->h == dstrect->h) {
832 SDL_BlitSurface(src, srcrect, surface, dstrect);
833 } else {
834 /* If scaling is ever done, permanently disable RLE (which doesn't support scaling)
835 * to avoid potentially frequent RLE encoding/decoding.
836 */
837 SDL_SetSurfaceRLE(surface, 0);
838
839 // Prevent to do scaling + clipping on viewport boundaries as it may lose proportion
840 if (dstrect->x < 0 || dstrect->y < 0 || dstrect->x + dstrect->w > surface->w || dstrect->y + dstrect->h > surface->h) {
841 SDL_Surface *tmp = SDL_CreateSurface(dstrect->w, dstrect->h, src->format);
842 // Scale to an intermediate surface, then blit
843 if (tmp) {
844 SDL_Rect r;
845 SDL_BlendMode blendmode;
846 Uint8 alphaMod, rMod, gMod, bMod;
847
848 SDL_GetSurfaceBlendMode(src, &blendmode);
849 SDL_GetSurfaceAlphaMod(src, &alphaMod);
850 SDL_GetSurfaceColorMod(src, &rMod, &gMod, &bMod);
851
852 r.x = 0;
853 r.y = 0;
854 r.w = dstrect->w;
855 r.h = dstrect->h;
856
857 SDL_SetSurfaceBlendMode(src, SDL_BLENDMODE_NONE);
858 SDL_SetSurfaceColorMod(src, 255, 255, 255);
859 SDL_SetSurfaceAlphaMod(src, 255);
860
861 SDL_BlitSurfaceScaled(src, srcrect, tmp, &r, texture->scaleMode);
862
863 SDL_SetSurfaceColorMod(tmp, rMod, gMod, bMod);
864 SDL_SetSurfaceAlphaMod(tmp, alphaMod);
865 SDL_SetSurfaceBlendMode(tmp, blendmode);
866
867 SDL_BlitSurface(tmp, NULL, surface, dstrect);
868 SDL_DestroySurface(tmp);
869 // No need to set back r/g/b/a/blendmode to 'src' since it's done in PrepTextureForCopy()
870 }
871 } else {
872 SDL_BlitSurfaceScaled(src, srcrect, surface, dstrect, texture->scaleMode);
873 }
874 }
875 break;
876 }
877
878 case SDL_RENDERCMD_COPY_EX:
879 {
880 CopyExData *copydata = (CopyExData *)(((Uint8 *)vertices) + cmd->data.draw.first);
881 SetDrawState(surface, &drawstate);
882 PrepTextureForCopy(cmd, &drawstate);
883
884 // Apply viewport
885 if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) {
886 copydata->dstrect.x += drawstate.viewport->x;
887 copydata->dstrect.y += drawstate.viewport->y;
888 }
889
890 SW_RenderCopyEx(renderer, surface, cmd->data.draw.texture, &copydata->srcrect,
891 &copydata->dstrect, copydata->angle, &copydata->center, copydata->flip,
892 copydata->scale_x, copydata->scale_y);
893 break;
894 }
895
896 case SDL_RENDERCMD_GEOMETRY:
897 {
898 int i;
899 SDL_Rect *verts = (SDL_Rect *)(((Uint8 *)vertices) + cmd->data.draw.first);
900 const int count = (int)cmd->data.draw.count;
901 SDL_Texture *texture = cmd->data.draw.texture;
902 const SDL_BlendMode blend = cmd->data.draw.blend;
903
904 SetDrawState(surface, &drawstate);
905
906 if (texture) {
907 SDL_Surface *src = (SDL_Surface *)texture->internal;
908
909 GeometryCopyData *ptr = (GeometryCopyData *)verts;
910
911 PrepTextureForCopy(cmd, &drawstate);
912
913 // Apply viewport
914 if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) {
915 SDL_Point vp;
916 vp.x = drawstate.viewport->x;
917 vp.y = drawstate.viewport->y;
918 trianglepoint_2_fixedpoint(&vp);
919 for (i = 0; i < count; i++) {
920 ptr[i].dst.x += vp.x;
921 ptr[i].dst.y += vp.y;
922 }
923 }
924
925 for (i = 0; i < count; i += 3, ptr += 3) {
926 SDL_SW_BlitTriangle(
927 src,
928 &(ptr[0].src), &(ptr[1].src), &(ptr[2].src),
929 surface,
930 &(ptr[0].dst), &(ptr[1].dst), &(ptr[2].dst),
931 ptr[0].color, ptr[1].color, ptr[2].color,
932 cmd->data.draw.texture_address_mode);
933 }
934 } else {
935 GeometryFillData *ptr = (GeometryFillData *)verts;
936
937 // Apply viewport
938 if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) {
939 SDL_Point vp;
940 vp.x = drawstate.viewport->x;
941 vp.y = drawstate.viewport->y;
942 trianglepoint_2_fixedpoint(&vp);
943 for (i = 0; i < count; i++) {
944 ptr[i].dst.x += vp.x;
945 ptr[i].dst.y += vp.y;
946 }
947 }
948
949 for (i = 0; i < count; i += 3, ptr += 3) {
950 SDL_SW_FillTriangle(surface, &(ptr[0].dst), &(ptr[1].dst), &(ptr[2].dst), blend, ptr[0].color, ptr[1].color, ptr[2].color);
951 }
952 }
953 break;
954 }
955
956 case SDL_RENDERCMD_NO_OP:
957 break;
958 }
959
960 cmd = cmd->next;
961 }
962
963 return true;
964}
965
966static SDL_Surface *SW_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect)
967{
968 SDL_Surface *surface = SW_ActivateRenderer(renderer);
969 void *pixels;
970
971 if (!SDL_SurfaceValid(surface)) {
972 return NULL;
973 }
974
975 /* NOTE: The rect is already adjusted according to the viewport by
976 * SDL_RenderReadPixels.
977 */
978
979 if (rect->x < 0 || rect->x + rect->w > surface->w ||
980 rect->y < 0 || rect->y + rect->h > surface->h) {
981 SDL_SetError("Tried to read outside of surface bounds");
982 return NULL;
983 }
984
985 pixels = (void *)((Uint8 *)surface->pixels +
986 rect->y * surface->pitch +
987 rect->x * surface->fmt->bytes_per_pixel);
988
989 return SDL_DuplicatePixels(rect->w, rect->h, surface->format, SDL_COLORSPACE_SRGB, pixels, surface->pitch);
990}
991
992static bool SW_RenderPresent(SDL_Renderer *renderer)
993{
994 SDL_Window *window = renderer->window;
995
996 if (!window) {
997 return false;
998 }
999 return SDL_UpdateWindowSurface(window);
1000}
1001
1002static void SW_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
1003{
1004 SDL_Surface *surface = (SDL_Surface *)texture->internal;
1005
1006 SDL_DestroySurface(surface);
1007}
1008
1009static void SW_DestroyRenderer(SDL_Renderer *renderer)
1010{
1011 SDL_Window *window = renderer->window;
1012 SW_RenderData *data = (SW_RenderData *)renderer->internal;
1013
1014 if (window) {
1015 SDL_DestroyWindowSurface(window);
1016 }
1017 SDL_free(data);
1018}
1019
1020static void SW_SelectBestFormats(SDL_Renderer *renderer, SDL_PixelFormat format)
1021{
1022 // Prefer the format used by the framebuffer by default.
1023 SDL_AddSupportedTextureFormat(renderer, format);
1024
1025 switch (format) {
1026 case SDL_PIXELFORMAT_XRGB4444:
1027 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB4444);
1028 break;
1029 case SDL_PIXELFORMAT_XBGR4444:
1030 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR4444);
1031 break;
1032 case SDL_PIXELFORMAT_ARGB4444:
1033 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB4444);
1034 break;
1035 case SDL_PIXELFORMAT_ABGR4444:
1036 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR4444);
1037 break;
1038
1039 case SDL_PIXELFORMAT_XRGB1555:
1040 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB1555);
1041 break;
1042 case SDL_PIXELFORMAT_XBGR1555:
1043 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR1555);
1044 break;
1045 case SDL_PIXELFORMAT_ARGB1555:
1046 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB1555);
1047 break;
1048 case SDL_PIXELFORMAT_ABGR1555:
1049 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR1555);
1050 break;
1051
1052 case SDL_PIXELFORMAT_XRGB8888:
1053 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888);
1054 break;
1055 case SDL_PIXELFORMAT_RGBX8888:
1056 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA8888);
1057 break;
1058 case SDL_PIXELFORMAT_XBGR8888:
1059 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888);
1060 break;
1061 case SDL_PIXELFORMAT_BGRX8888:
1062 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA8888);
1063 break;
1064 case SDL_PIXELFORMAT_ARGB8888:
1065 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888);
1066 break;
1067 case SDL_PIXELFORMAT_RGBA8888:
1068 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBX8888);
1069 break;
1070 case SDL_PIXELFORMAT_ABGR8888:
1071 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR8888);
1072 break;
1073 case SDL_PIXELFORMAT_BGRA8888:
1074 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRX8888);
1075 break;
1076 default:
1077 break;
1078 }
1079
1080 /* Ensure that we always have a SDL_PACKEDLAYOUT_8888 format. Having a matching component order increases the
1081 * chances of getting a fast path for blitting.
1082 */
1083 if (SDL_ISPIXELFORMAT_PACKED(format)) {
1084 if (SDL_PIXELLAYOUT(format) != SDL_PACKEDLAYOUT_8888) {
1085 switch (SDL_PIXELORDER(format)) {
1086 case SDL_PACKEDORDER_BGRX:
1087 case SDL_PACKEDORDER_BGRA:
1088 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRX8888);
1089 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA8888);
1090 break;
1091 case SDL_PACKEDORDER_RGBX:
1092 case SDL_PACKEDORDER_RGBA:
1093 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBX8888);
1094 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA8888);
1095 break;
1096 case SDL_PACKEDORDER_XBGR:
1097 case SDL_PACKEDORDER_ABGR:
1098 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR8888);
1099 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888);
1100 break;
1101 case SDL_PACKEDORDER_XRGB:
1102 case SDL_PACKEDORDER_ARGB:
1103 default:
1104 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888);
1105 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888);
1106 break;
1107 }
1108 }
1109 } else {
1110 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888);
1111 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888);
1112 }
1113}
1114
1115bool SW_CreateRendererForSurface(SDL_Renderer *renderer, SDL_Surface *surface, SDL_PropertiesID create_props)
1116{
1117 SW_RenderData *data;
1118
1119 if (!SDL_SurfaceValid(surface)) {
1120 return SDL_InvalidParamError("surface");
1121 }
1122
1123 renderer->software = true;
1124
1125 data = (SW_RenderData *)SDL_calloc(1, sizeof(*data));
1126 if (!data) {
1127 return false;
1128 }
1129 data->surface = surface;
1130 data->window = surface;
1131
1132 renderer->WindowEvent = SW_WindowEvent;
1133 renderer->GetOutputSize = SW_GetOutputSize;
1134 renderer->CreateTexture = SW_CreateTexture;
1135 renderer->UpdateTexture = SW_UpdateTexture;
1136 renderer->LockTexture = SW_LockTexture;
1137 renderer->UnlockTexture = SW_UnlockTexture;
1138 renderer->SetTextureScaleMode = SW_SetTextureScaleMode;
1139 renderer->SetRenderTarget = SW_SetRenderTarget;
1140 renderer->QueueSetViewport = SW_QueueNoOp;
1141 renderer->QueueSetDrawColor = SW_QueueNoOp;
1142 renderer->QueueDrawPoints = SW_QueueDrawPoints;
1143 renderer->QueueDrawLines = SW_QueueDrawPoints; // lines and points queue vertices the same way.
1144 renderer->QueueFillRects = SW_QueueFillRects;
1145 renderer->QueueCopy = SW_QueueCopy;
1146 renderer->QueueCopyEx = SW_QueueCopyEx;
1147 renderer->QueueGeometry = SW_QueueGeometry;
1148 renderer->InvalidateCachedState = SW_InvalidateCachedState;
1149 renderer->RunCommandQueue = SW_RunCommandQueue;
1150 renderer->RenderReadPixels = SW_RenderReadPixels;
1151 renderer->RenderPresent = SW_RenderPresent;
1152 renderer->DestroyTexture = SW_DestroyTexture;
1153 renderer->DestroyRenderer = SW_DestroyRenderer;
1154 renderer->internal = data;
1155 SW_InvalidateCachedState(renderer);
1156
1157 renderer->name = SW_RenderDriver.name;
1158
1159 SW_SelectBestFormats(renderer, surface->format);
1160
1161 SDL_SetupRendererColorspace(renderer, create_props);
1162
1163 if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) {
1164 return SDL_SetError("Unsupported output colorspace");
1165 }
1166
1167 return true;
1168}
1169
1170static bool SW_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
1171{
1172 // Set the vsync hint based on our flags, if it's not already set
1173 const char *hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC);
1174 const bool no_hint_set = (!hint || !*hint);
1175
1176 if (no_hint_set) {
1177 if (SDL_GetBooleanProperty(create_props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0)) {
1178 SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1");
1179 } else {
1180 SDL_SetHint(SDL_HINT_RENDER_VSYNC, "0");
1181 }
1182 }
1183
1184 SDL_Surface *surface = SDL_GetWindowSurface(window);
1185
1186 // Reset the vsync hint if we set it above
1187 if (no_hint_set) {
1188 SDL_SetHint(SDL_HINT_RENDER_VSYNC, "");
1189 }
1190
1191 if (!SDL_SurfaceValid(surface)) {
1192 return false;
1193 }
1194
1195 return SW_CreateRendererForSurface(renderer, surface, create_props);
1196}
1197
1198SDL_RenderDriver SW_RenderDriver = {
1199 SW_CreateRenderer, SDL_SOFTWARE_RENDERER
1200};
1201
1202#endif // SDL_VIDEO_RENDER_SW
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_render_sw_c.h b/contrib/SDL-3.2.8/src/render/software/SDL_render_sw_c.h
new file mode 100644
index 0000000..40d3c3a
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_render_sw_c.h
@@ -0,0 +1,27 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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
22#ifndef SDL_render_sw_c_h_
23#define SDL_render_sw_c_h_
24
25extern bool SW_CreateRendererForSurface(SDL_Renderer *renderer, SDL_Surface *surface, SDL_PropertiesID create_props);
26
27#endif // SDL_render_sw_c_h_
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_rotate.c b/contrib/SDL-3.2.8/src/render/software/SDL_rotate.c
new file mode 100644
index 0000000..516ba8a
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_rotate.c
@@ -0,0 +1,612 @@
1/*
2
3SDL_rotate.c: rotates 32bit or 8bit surfaces
4
5Shamelessly stolen from SDL_gfx by Andreas Schiffler. Original copyright follows:
6
7Copyright (C) 2001-2011 Andreas Schiffler
8
9This software is provided 'as-is', without any express or implied
10warranty. In no event will the authors be held liable for any damages
11arising from the use of this software.
12
13Permission is granted to anyone to use this software for any purpose,
14including commercial applications, and to alter it and redistribute it
15freely, subject to the following restrictions:
16
17 1. The origin of this software must not be misrepresented; you must not
18 claim that you wrote the original software. If you use this software
19 in a product, an acknowledgment in the product documentation would be
20 appreciated but is not required.
21
22 2. Altered source versions must be plainly marked as such, and must not be
23 misrepresented as being the original software.
24
25 3. This notice may not be removed or altered from any source
26 distribution.
27
28Andreas Schiffler -- aschiffler at ferzkopp dot net
29
30*/
31#include "SDL_internal.h"
32
33#ifdef SDL_VIDEO_RENDER_SW
34
35#if defined(SDL_PLATFORM_WINDOWS)
36#include "../../core/windows/SDL_windows.h"
37#endif
38
39#include "SDL_rotate.h"
40
41#include "../../video/SDL_surface_c.h"
42
43// ---- Internally used structures
44
45/**
46A 32 bit RGBA pixel.
47*/
48typedef struct tColorRGBA
49{
50 Uint8 r;
51 Uint8 g;
52 Uint8 b;
53 Uint8 a;
54} tColorRGBA;
55
56/**
57A 8bit Y/palette pixel.
58*/
59typedef struct tColorY
60{
61 Uint8 y;
62} tColorY;
63
64/**
65Number of guard rows added to destination surfaces.
66
67This is a simple but effective workaround for observed issues.
68These rows allocate extra memory and are then hidden from the surface.
69Rows are added to the end of destination surfaces when they are allocated.
70This catches any potential overflows which seem to happen with
71just the right src image dimensions and scale/rotation and can lead
72to a situation where the program can segfault.
73*/
74#define GUARD_ROWS (2)
75
76/**
77Returns colorkey info for a surface
78*/
79static Uint32 get_colorkey(SDL_Surface *src)
80{
81 Uint32 key = 0;
82 if (SDL_SurfaceHasColorKey(src)) {
83 SDL_GetSurfaceColorKey(src, &key);
84 }
85 return key;
86}
87
88// rotate (sx, sy) by (angle, center) into (dx, dy)
89static void rotate(double sx, double sy, double sinangle, double cosangle, const SDL_FPoint *center, double *dx, double *dy)
90{
91 sx -= center->x;
92 sy -= center->y;
93
94 *dx = cosangle * sx - sinangle * sy;
95 *dy = sinangle * sx + cosangle * sy;
96
97 *dx += center->x;
98 *dy += center->y;
99}
100
101/**
102Internal target surface sizing function for rotations with trig result return.
103
104\param width The source surface width.
105\param height The source surface height.
106\param angle The angle to rotate in degrees.
107\param center The center of ratation
108\param rect_dest Bounding box of rotated rectangle
109\param cangle The sine of the angle
110\param sangle The cosine of the angle
111
112*/
113void SDLgfx_rotozoomSurfaceSizeTrig(int width, int height, double angle, const SDL_FPoint *center,
114 SDL_Rect *rect_dest, double *cangle, double *sangle)
115{
116 int minx, maxx, miny, maxy;
117 double radangle;
118 double x0, x1, x2, x3;
119 double y0, y1, y2, y3;
120 double sinangle;
121 double cosangle;
122
123 radangle = angle * (SDL_PI_D / 180.0);
124 sinangle = SDL_sin(radangle);
125 cosangle = SDL_cos(radangle);
126
127 /*
128 * Determine destination width and height by rotating a source box, at pixel center
129 */
130 rotate(0.5, 0.5, sinangle, cosangle, center, &x0, &y0);
131 rotate(width - 0.5, 0.5, sinangle, cosangle, center, &x1, &y1);
132 rotate(0.5, height - 0.5, sinangle, cosangle, center, &x2, &y2);
133 rotate(width - 0.5, height - 0.5, sinangle, cosangle, center, &x3, &y3);
134
135 minx = (int)SDL_floor(SDL_min(SDL_min(x0, x1), SDL_min(x2, x3)));
136 maxx = (int)SDL_ceil(SDL_max(SDL_max(x0, x1), SDL_max(x2, x3)));
137
138 miny = (int)SDL_floor(SDL_min(SDL_min(y0, y1), SDL_min(y2, y3)));
139 maxy = (int)SDL_ceil(SDL_max(SDL_max(y0, y1), SDL_max(y2, y3)));
140
141 rect_dest->w = maxx - minx;
142 rect_dest->h = maxy - miny;
143 rect_dest->x = minx;
144 rect_dest->y = miny;
145
146 // reverse the angle because our rotations are clockwise
147 *sangle = -sinangle;
148 *cangle = cosangle;
149
150 {
151 // The trig code below gets the wrong size (due to FP inaccuracy?) when angle is a multiple of 90 degrees
152 int angle90 = (int)(angle / 90);
153 if (angle90 == angle / 90) { // if the angle is a multiple of 90 degrees
154 angle90 %= 4;
155 if (angle90 < 0) {
156 angle90 += 4; // 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg
157 }
158
159 if (angle90 & 1) {
160 rect_dest->w = height;
161 rect_dest->h = width;
162 *cangle = 0;
163 *sangle = angle90 == 1 ? -1 : 1; // reversed because our rotations are clockwise
164 } else {
165 rect_dest->w = width;
166 rect_dest->h = height;
167 *cangle = angle90 == 0 ? 1 : -1;
168 *sangle = 0;
169 }
170 }
171 }
172}
173
174// Computes source pointer X/Y increments for a rotation that's a multiple of 90 degrees.
175static void computeSourceIncrements90(SDL_Surface *src, int bpp, int angle, int flipx, int flipy,
176 int *sincx, int *sincy, int *signx, int *signy)
177{
178 int pitch = flipy ? -src->pitch : src->pitch;
179 if (flipx) {
180 bpp = -bpp;
181 }
182 switch (angle) { // 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg
183 case 0:
184 *sincx = bpp;
185 *sincy = pitch - src->w * *sincx;
186 *signx = *signy = 1;
187 break;
188 case 1:
189 *sincx = -pitch;
190 *sincy = bpp - *sincx * src->h;
191 *signx = 1;
192 *signy = -1;
193 break;
194 case 2:
195 *sincx = -bpp;
196 *sincy = -src->w * *sincx - pitch;
197 *signx = *signy = -1;
198 break;
199 case 3:
200 default:
201 *sincx = pitch;
202 *sincy = -*sincx * src->h - bpp;
203 *signx = -1;
204 *signy = 1;
205 break;
206 }
207 if (flipx) {
208 *signx = -*signx;
209 }
210 if (flipy) {
211 *signy = -*signy;
212 }
213}
214
215// Performs a relatively fast rotation/flip when the angle is a multiple of 90 degrees.
216#define TRANSFORM_SURFACE_90(pixelType) \
217 int dy, dincy = dst->pitch - dst->w * sizeof(pixelType), sincx, sincy, signx, signy; \
218 Uint8 *sp = (Uint8 *)src->pixels, *dp = (Uint8 *)dst->pixels, *de; \
219 \
220 computeSourceIncrements90(src, sizeof(pixelType), angle, flipx, flipy, &sincx, &sincy, &signx, &signy); \
221 if (signx < 0) \
222 sp += (src->w - 1) * sizeof(pixelType); \
223 if (signy < 0) \
224 sp += (src->h - 1) * src->pitch; \
225 \
226 for (dy = 0; dy < dst->h; sp += sincy, dp += dincy, dy++) { \
227 if (sincx == sizeof(pixelType)) { /* if advancing src and dest equally, use SDL_memcpy */ \
228 SDL_memcpy(dp, sp, dst->w * sizeof(pixelType)); \
229 sp += dst->w * sizeof(pixelType); \
230 dp += dst->w * sizeof(pixelType); \
231 } else { \
232 for (de = dp + dst->w * sizeof(pixelType); dp != de; sp += sincx, dp += sizeof(pixelType)) { \
233 *(pixelType *)dp = *(pixelType *)sp; \
234 } \
235 } \
236 }
237
238static void transformSurfaceRGBA90(SDL_Surface *src, SDL_Surface *dst, int angle, int flipx, int flipy)
239{
240 TRANSFORM_SURFACE_90(tColorRGBA);
241}
242
243static void transformSurfaceY90(SDL_Surface *src, SDL_Surface *dst, int angle, int flipx, int flipy)
244{
245 TRANSFORM_SURFACE_90(tColorY);
246}
247
248#undef TRANSFORM_SURFACE_90
249
250/**
251Internal 32 bit rotozoomer with optional anti-aliasing.
252
253Rotates and zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
254parameters by scanning the destination surface and applying optionally anti-aliasing
255by bilinear interpolation.
256Assumes src and dst surfaces are of 32 bit depth.
257Assumes dst surface was allocated with the correct dimensions.
258
259\param src Source surface.
260\param dst Destination surface.
261\param isin Integer version of sine of angle.
262\param icos Integer version of cosine of angle.
263\param flipx Flag indicating horizontal mirroring should be applied.
264\param flipy Flag indicating vertical mirroring should be applied.
265\param smooth Flag indicating anti-aliasing should be used.
266\param rect_dest destination coordinates
267\param center true center.
268*/
269static void transformSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst, int isin, int icos,
270 int flipx, int flipy, int smooth,
271 const SDL_Rect *rect_dest,
272 const SDL_FPoint *center)
273{
274 int sw, sh;
275 int cx, cy;
276 tColorRGBA c00, c01, c10, c11, cswap;
277 tColorRGBA *pc, *sp;
278 int gap;
279 const int fp_half = (1 << 15);
280
281 /*
282 * Variable setup
283 */
284 sw = src->w - 1;
285 sh = src->h - 1;
286 pc = (tColorRGBA *)dst->pixels;
287 gap = dst->pitch - dst->w * 4;
288 cx = (int)(center->x * 65536.0);
289 cy = (int)(center->y * 65536.0);
290
291 /*
292 * Switch between interpolating and non-interpolating code
293 */
294 if (smooth) {
295 int y;
296 for (y = 0; y < dst->h; y++) {
297 int x;
298 double src_x = ((double)rect_dest->x + 0 + 0.5 - center->x);
299 double src_y = ((double)rect_dest->y + y + 0.5 - center->y);
300 int sdx = (int)((icos * src_x - isin * src_y) + cx - fp_half);
301 int sdy = (int)((isin * src_x + icos * src_y) + cy - fp_half);
302 for (x = 0; x < dst->w; x++) {
303 int dx = (sdx >> 16);
304 int dy = (sdy >> 16);
305 if (flipx) {
306 dx = sw - dx;
307 }
308 if (flipy) {
309 dy = sh - dy;
310 }
311 if ((dx > -1) && (dy > -1) && (dx < (src->w - 1)) && (dy < (src->h - 1))) {
312 int ex, ey;
313 int t1, t2;
314 sp = (tColorRGBA *)((Uint8 *)src->pixels + src->pitch * dy) + dx;
315 c00 = *sp;
316 sp += 1;
317 c01 = *sp;
318 sp += (src->pitch / 4);
319 c11 = *sp;
320 sp -= 1;
321 c10 = *sp;
322 if (flipx) {
323 cswap = c00;
324 c00 = c01;
325 c01 = cswap;
326 cswap = c10;
327 c10 = c11;
328 c11 = cswap;
329 }
330 if (flipy) {
331 cswap = c00;
332 c00 = c10;
333 c10 = cswap;
334 cswap = c01;
335 c01 = c11;
336 c11 = cswap;
337 }
338 /*
339 * Interpolate colors
340 */
341 ex = (sdx & 0xffff);
342 ey = (sdy & 0xffff);
343 t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
344 t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
345 pc->r = (Uint8)((((t2 - t1) * ey) >> 16) + t1);
346 t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
347 t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
348 pc->g = (Uint8)((((t2 - t1) * ey) >> 16) + t1);
349 t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
350 t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
351 pc->b = (Uint8)((((t2 - t1) * ey) >> 16) + t1);
352 t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
353 t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
354 pc->a = (Uint8)((((t2 - t1) * ey) >> 16) + t1);
355 }
356 sdx += icos;
357 sdy += isin;
358 pc++;
359 }
360 pc = (tColorRGBA *)((Uint8 *)pc + gap);
361 }
362 } else {
363 int y;
364 for (y = 0; y < dst->h; y++) {
365 int x;
366 double src_x = ((double)rect_dest->x + 0 + 0.5 - center->x);
367 double src_y = ((double)rect_dest->y + y + 0.5 - center->y);
368 int sdx = (int)((icos * src_x - isin * src_y) + cx - fp_half);
369 int sdy = (int)((isin * src_x + icos * src_y) + cy - fp_half);
370 for (x = 0; x < dst->w; x++) {
371 int dx = (sdx >> 16);
372 int dy = (sdy >> 16);
373 if ((unsigned)dx < (unsigned)src->w && (unsigned)dy < (unsigned)src->h) {
374 if (flipx) {
375 dx = sw - dx;
376 }
377 if (flipy) {
378 dy = sh - dy;
379 }
380 *pc = *((tColorRGBA *)((Uint8 *)src->pixels + src->pitch * dy) + dx);
381 }
382 sdx += icos;
383 sdy += isin;
384 pc++;
385 }
386 pc = (tColorRGBA *)((Uint8 *)pc + gap);
387 }
388 }
389}
390
391/**
392
393Rotates and zooms 8 bit palette/Y 'src' surface to 'dst' surface without smoothing.
394
395Rotates and zooms 8 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
396parameters by scanning the destination surface.
397Assumes src and dst surfaces are of 8 bit depth.
398Assumes dst surface was allocated with the correct dimensions.
399
400\param src Source surface.
401\param dst Destination surface.
402\param isin Integer version of sine of angle.
403\param icos Integer version of cosine of angle.
404\param flipx Flag indicating horizontal mirroring should be applied.
405\param flipy Flag indicating vertical mirroring should be applied.
406\param rect_dest destination coordinates
407\param center true center.
408*/
409static void transformSurfaceY(SDL_Surface *src, SDL_Surface *dst, int isin, int icos, int flipx, int flipy,
410 const SDL_Rect *rect_dest,
411 const SDL_FPoint *center)
412{
413 int sw, sh;
414 int cx, cy;
415 tColorY *pc;
416 int gap;
417 const int fp_half = (1 << 15);
418 int y;
419
420 /*
421 * Variable setup
422 */
423 sw = src->w - 1;
424 sh = src->h - 1;
425 pc = (tColorY *)dst->pixels;
426 gap = dst->pitch - dst->w;
427 cx = (int)(center->x * 65536.0);
428 cy = (int)(center->y * 65536.0);
429
430 /*
431 * Clear surface to colorkey
432 */
433 SDL_memset(pc, (int)(get_colorkey(src) & 0xff), (size_t)dst->pitch * dst->h);
434 /*
435 * Iterate through destination surface
436 */
437 for (y = 0; y < dst->h; y++) {
438 int x;
439 double src_x = ((double)rect_dest->x + 0 + 0.5 - center->x);
440 double src_y = ((double)rect_dest->y + y + 0.5 - center->y);
441 int sdx = (int)((icos * src_x - isin * src_y) + cx - fp_half);
442 int sdy = (int)((isin * src_x + icos * src_y) + cy - fp_half);
443 for (x = 0; x < dst->w; x++) {
444 int dx = (sdx >> 16);
445 int dy = (sdy >> 16);
446 if ((unsigned)dx < (unsigned)src->w && (unsigned)dy < (unsigned)src->h) {
447 if (flipx) {
448 dx = sw - dx;
449 }
450 if (flipy) {
451 dy = sh - dy;
452 }
453 *pc = *((tColorY *)src->pixels + src->pitch * dy + dx);
454 }
455 sdx += icos;
456 sdy += isin;
457 pc++;
458 }
459 pc += gap;
460 }
461}
462
463/**
464Rotates and zooms a surface with different horizontal and vertival scaling factors and optional anti-aliasing.
465
466Rotates a 32-bit or 8-bit 'src' surface to newly created 'dst' surface.
467'angle' is the rotation in degrees, 'center' the rotation center. If 'smooth' is set
468then the destination 32-bit surface is anti-aliased. 8-bit surfaces must have a colorkey. 32-bit
469surfaces must have a 8888 layout with red, green, blue and alpha masks (any ordering goes).
470The blend mode of the 'src' surface has some effects on generation of the 'dst' surface: The NONE
471mode will set the BLEND mode on the 'dst' surface. The MOD mode either generates a white 'dst'
472surface and sets the colorkey or fills the it with the colorkey before copying the pixels.
473When using the NONE and MOD modes, color and alpha modulation must be applied before using this function.
474
475\param src The surface to rotozoom.
476\param angle The angle to rotate in degrees.
477\param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
478\param flipx Set to 1 to flip the image horizontally
479\param flipy Set to 1 to flip the image vertically
480\param rect_dest The destination rect bounding box
481\param cangle The angle cosine
482\param sangle The angle sine
483\param center The true coordinate of the center of rotation
484\return The new rotated surface.
485
486*/
487
488SDL_Surface *SDLgfx_rotateSurface(SDL_Surface *src, double angle, int smooth, int flipx, int flipy,
489 const SDL_Rect *rect_dest, double cangle, double sangle, const SDL_FPoint *center)
490{
491 SDL_Surface *rz_dst;
492 int is8bit, angle90;
493 SDL_BlendMode blendmode;
494 Uint32 colorkey = 0;
495 bool colorKeyAvailable = false;
496 double sangleinv, cangleinv;
497
498 // Sanity check
499 if (!SDL_SurfaceValid(src)) {
500 return NULL;
501 }
502
503 if (SDL_SurfaceHasColorKey(src)) {
504 if (SDL_GetSurfaceColorKey(src, &colorkey)) {
505 colorKeyAvailable = true;
506 }
507 }
508 // This function requires a 32-bit surface or 8-bit surface with a colorkey
509 is8bit = src->fmt->bits_per_pixel == 8 && colorKeyAvailable;
510 if (!(is8bit || (src->fmt->bits_per_pixel == 32 && SDL_ISPIXELFORMAT_ALPHA(src->format)))) {
511 return NULL;
512 }
513
514 // Calculate target factors from sine/cosine and zoom
515 sangleinv = sangle * 65536.0;
516 cangleinv = cangle * 65536.0;
517
518 // Alloc space to completely contain the rotated surface
519 rz_dst = NULL;
520 if (is8bit) {
521 // Target surface is 8 bit
522 rz_dst = SDL_CreateSurface(rect_dest->w, rect_dest->h + GUARD_ROWS, src->format);
523 if (rz_dst) {
524 SDL_SetSurfacePalette(rz_dst, src->palette);
525 }
526 } else {
527 // Target surface is 32 bit with source RGBA ordering
528 rz_dst = SDL_CreateSurface(rect_dest->w, rect_dest->h + GUARD_ROWS, src->format);
529 }
530
531 // Check target
532 if (!rz_dst) {
533 return NULL;
534 }
535
536 // Adjust for guard rows
537 rz_dst->h = rect_dest->h;
538
539 SDL_GetSurfaceBlendMode(src, &blendmode);
540
541 if (colorKeyAvailable) {
542 // If available, the colorkey will be used to discard the pixels that are outside of the rotated area.
543 SDL_SetSurfaceColorKey(rz_dst, true, colorkey);
544 SDL_FillSurfaceRect(rz_dst, NULL, colorkey);
545 } else if (blendmode == SDL_BLENDMODE_NONE) {
546 blendmode = SDL_BLENDMODE_BLEND;
547 } else if (blendmode == SDL_BLENDMODE_MOD || blendmode == SDL_BLENDMODE_MUL) {
548 /* Without a colorkey, the target texture has to be white for the MOD and MUL blend mode so
549 * that the pixels outside the rotated area don't affect the destination surface.
550 */
551 colorkey = SDL_MapSurfaceRGBA(rz_dst, 255, 255, 255, 0);
552 SDL_FillSurfaceRect(rz_dst, NULL, colorkey);
553 /* Setting a white colorkey for the destination surface makes the final blit discard
554 * all pixels outside of the rotated area. This doesn't interfere with anything because
555 * white pixels are already a no-op and the MOD blend mode does not interact with alpha.
556 */
557 SDL_SetSurfaceColorKey(rz_dst, true, colorkey);
558 }
559
560 SDL_SetSurfaceBlendMode(rz_dst, blendmode);
561
562 // Lock source surface
563 if (SDL_MUSTLOCK(src)) {
564 if (!SDL_LockSurface(src)) {
565 SDL_DestroySurface(rz_dst);
566 return NULL;
567 }
568 }
569
570 /* check if the rotation is a multiple of 90 degrees so we can take a fast path and also somewhat reduce
571 * the off-by-one problem in transformSurfaceRGBA that expresses itself when the rotation is near
572 * multiples of 90 degrees.
573 */
574 angle90 = (int)(angle / 90);
575 if (angle90 == angle / 90) {
576 angle90 %= 4;
577 if (angle90 < 0) {
578 angle90 += 4; // 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg
579 }
580
581 } else {
582 angle90 = -1;
583 }
584
585 if (is8bit) {
586 // Call the 8-bit transformation routine to do the rotation
587 if (angle90 >= 0) {
588 transformSurfaceY90(src, rz_dst, angle90, flipx, flipy);
589 } else {
590 transformSurfaceY(src, rz_dst, (int)sangleinv, (int)cangleinv,
591 flipx, flipy, rect_dest, center);
592 }
593 } else {
594 // Call the 32-bit transformation routine to do the rotation
595 if (angle90 >= 0) {
596 transformSurfaceRGBA90(src, rz_dst, angle90, flipx, flipy);
597 } else {
598 transformSurfaceRGBA(src, rz_dst, (int)sangleinv, (int)cangleinv,
599 flipx, flipy, smooth, rect_dest, center);
600 }
601 }
602
603 // Unlock source surface
604 if (SDL_MUSTLOCK(src)) {
605 SDL_UnlockSurface(src);
606 }
607
608 // Return rotated surface
609 return rz_dst;
610}
611
612#endif // SDL_VIDEO_RENDER_SW
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_rotate.h b/contrib/SDL-3.2.8/src/render/software/SDL_rotate.h
new file mode 100644
index 0000000..ecf84f7
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_rotate.h
@@ -0,0 +1,30 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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
22#ifndef SDL_rotate_h_
23#define SDL_rotate_h_
24
25extern SDL_Surface *SDLgfx_rotateSurface(SDL_Surface *src, double angle, int smooth, int flipx, int flipy,
26 const SDL_Rect *rect_dest, double cangle, double sangle, const SDL_FPoint *center);
27extern void SDLgfx_rotozoomSurfaceSizeTrig(int width, int height, double angle, const SDL_FPoint *center,
28 SDL_Rect *rect_dest, double *cangle, double *sangle);
29
30#endif // SDL_rotate_h_
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_triangle.c b/contrib/SDL-3.2.8/src/render/software/SDL_triangle.c
new file mode 100644
index 0000000..c4e16d1
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_triangle.c
@@ -0,0 +1,945 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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#ifdef SDL_VIDEO_RENDER_SW
24
25#include <limits.h>
26
27#include "SDL_triangle.h"
28
29#include "../../video/SDL_surface_c.h"
30
31/* fixed points bits precision
32 * Set to 1, so that it can start rendering with middle of a pixel precision.
33 * It doesn't need to be increased.
34 * But, if increased too much, it overflows (srcx, srcy) coordinates used for filling with texture.
35 * (which could be turned to int64).
36 */
37#define FP_BITS 1
38
39#define COLOR_EQ(c1, c2) ((c1).r == (c2).r && (c1).g == (c2).g && (c1).b == (c2).b && (c1).a == (c2).a)
40
41static void SDL_BlitTriangle_Slow(SDL_BlitInfo *info,
42 SDL_Point s2_x_area, SDL_Rect dstrect, int area, int bias_w0, int bias_w1, int bias_w2,
43 int d2d1_y, int d1d2_x, int d0d2_y, int d2d0_x, int d1d0_y, int d0d1_x,
44 int s2s0_x, int s2s1_x, int s2s0_y, int s2s1_y, int w0_row, int w1_row, int w2_row,
45 SDL_Color c0, SDL_Color c1, SDL_Color c2, bool is_uniform, SDL_TextureAddressMode texture_address_mode);
46
47#if 0
48bool SDL_BlitTriangle(SDL_Surface *src, const SDL_Point srcpoints[3], SDL_Surface *dst, const SDL_Point dstpoints[3])
49{
50 int i;
51 SDL_Point points[6];
52
53 if (src == NULL || dst == NULL) {
54 return false;
55 }
56
57 for (i = 0; i < 3; i++) {
58 if (srcpoints[i].x < 0 || srcpoints[i].y < 0 || srcpoints[i].x >= src->w || srcpoints[i].y >= src->h) {
59 return SDL_SetError("Values of 'srcpoints' out of bounds");
60 }
61 }
62
63 points[0] = srcpoints[0];
64 points[1] = dstpoints[0];
65 points[2] = srcpoints[1];
66 points[3] = dstpoints[1];
67 points[4] = srcpoints[2];
68 points[5] = dstpoints[2];
69 for (i = 0; i < 3; i++) {
70 trianglepoint_2_fixedpoint(&points[2 * i + 1]);
71 }
72 return SDL_SW_BlitTriangle(src, dst, points);
73}
74
75bool SDL_FillTriangle(SDL_Surface *dst, const SDL_Point points[3], Uint32 color)
76{
77 int i;
78 SDL_Point points_tmp[3];
79 if (dst == NULL) {
80 return false;
81 }
82 for (i = 0; i < 3; i++) {
83 points_tmp[i] = points[i];
84 trianglepoint_2_fixedpoint(&points_tmp[i]);
85 }
86 return SDL_SW_FillTriangle(dst, points_tmp, SDL_BLENDMODE_NONE, color);
87}
88#endif
89
90// cross product AB x AC
91static Sint64 cross_product(const SDL_Point *a, const SDL_Point *b, int c_x, int c_y)
92{
93 return ((Sint64)(b->x - a->x)) * ((Sint64)(c_y - a->y)) - ((Sint64)(b->y - a->y)) * ((Sint64)(c_x - a->x));
94}
95
96// check for top left rules
97static bool is_top_left(const SDL_Point *a, const SDL_Point *b, int is_clockwise)
98{
99 if (is_clockwise) {
100 if (a->y == b->y && a->x < b->x) {
101 return true;
102 }
103 if (b->y < a->y) {
104 return true;
105 }
106 } else {
107 if (a->y == b->y && b->x < a->x) {
108 return true;
109 }
110 if (a->y < b->y) {
111 return true;
112 }
113 }
114 return false;
115}
116
117// x = (y << FP_BITS)
118// prevent runtime error: left shift of negative value
119#define PRECOMP(x, y) \
120 val = y; \
121 if (val >= 0) { \
122 x = val << FP_BITS; \
123 } else { \
124 val *= -1; \
125 x = val << FP_BITS; \
126 x *= -1; \
127 }
128
129void trianglepoint_2_fixedpoint(SDL_Point *a)
130{
131 int val;
132 PRECOMP(a->x, a->x);
133 PRECOMP(a->y, a->y);
134}
135
136// bounding rect of three points (in fixed point)
137static void bounding_rect_fixedpoint(const SDL_Point *a, const SDL_Point *b, const SDL_Point *c, SDL_Rect *r)
138{
139 int min_x = SDL_min(a->x, SDL_min(b->x, c->x));
140 int max_x = SDL_max(a->x, SDL_max(b->x, c->x));
141 int min_y = SDL_min(a->y, SDL_min(b->y, c->y));
142 int max_y = SDL_max(a->y, SDL_max(b->y, c->y));
143 // points are in fixed point, shift back
144 r->x = min_x >> FP_BITS;
145 r->y = min_y >> FP_BITS;
146 r->w = (max_x - min_x) >> FP_BITS;
147 r->h = (max_y - min_y) >> FP_BITS;
148}
149
150// bounding rect of three points
151static void bounding_rect(const SDL_Point *a, const SDL_Point *b, const SDL_Point *c, SDL_Rect *r)
152{
153 int min_x = SDL_min(a->x, SDL_min(b->x, c->x));
154 int max_x = SDL_max(a->x, SDL_max(b->x, c->x));
155 int min_y = SDL_min(a->y, SDL_min(b->y, c->y));
156 int max_y = SDL_max(a->y, SDL_max(b->y, c->y));
157 r->x = min_x;
158 r->y = min_y;
159 r->w = (max_x - min_x);
160 r->h = (max_y - min_y);
161}
162
163/* Triangle rendering, using Barycentric coordinates (w0, w1, w2)
164 *
165 * The cross product isn't computed from scratch at each iteration,
166 * but optimized using constant step increments
167 *
168 */
169
170#define TRIANGLE_BEGIN_LOOP \
171 { \
172 int x, y; \
173 for (y = 0; y < dstrect.h; y++) { \
174 /* y start */ \
175 Sint64 w0 = w0_row; \
176 Sint64 w1 = w1_row; \
177 Sint64 w2 = w2_row; \
178 for (x = 0; x < dstrect.w; x++) { \
179 /* In triangle */ \
180 if (w0 + bias_w0 >= 0 && w1 + bias_w1 >= 0 && w2 + bias_w2 >= 0) { \
181 Uint8 *dptr = (Uint8 *)dst_ptr + x * dstbpp;
182
183// Use 64 bits precision to prevent overflow when interpolating color / texture with wide triangles
184#define TRIANGLE_GET_TEXTCOORD \
185 int srcx = (int)(((Sint64)w0 * s2s0_x + (Sint64)w1 * s2s1_x + s2_x_area.x) / area); \
186 int srcy = (int)(((Sint64)w0 * s2s0_y + (Sint64)w1 * s2s1_y + s2_x_area.y) / area); \
187 if (texture_address_mode == SDL_TEXTURE_ADDRESS_WRAP) { \
188 srcx %= src_surface->w; \
189 if (srcx < 0) { \
190 srcx += (src_surface->w - 1); \
191 } \
192 srcy %= src_surface->h; \
193 if (srcy < 0) { \
194 srcy += (src_surface->h - 1); \
195 } \
196 }
197
198#define TRIANGLE_GET_MAPPED_COLOR \
199 Uint8 r = (Uint8)(((Sint64)w0 * c0.r + (Sint64)w1 * c1.r + (Sint64)w2 * c2.r) / area); \
200 Uint8 g = (Uint8)(((Sint64)w0 * c0.g + (Sint64)w1 * c1.g + (Sint64)w2 * c2.g) / area); \
201 Uint8 b = (Uint8)(((Sint64)w0 * c0.b + (Sint64)w1 * c1.b + (Sint64)w2 * c2.b) / area); \
202 Uint8 a = (Uint8)(((Sint64)w0 * c0.a + (Sint64)w1 * c1.a + (Sint64)w2 * c2.a) / area); \
203 Uint32 color = SDL_MapRGBA(format, palette, r, g, b, a);
204
205#define TRIANGLE_GET_COLOR \
206 int r = (int)(((Sint64)w0 * c0.r + (Sint64)w1 * c1.r + (Sint64)w2 * c2.r) / area); \
207 int g = (int)(((Sint64)w0 * c0.g + (Sint64)w1 * c1.g + (Sint64)w2 * c2.g) / area); \
208 int b = (int)(((Sint64)w0 * c0.b + (Sint64)w1 * c1.b + (Sint64)w2 * c2.b) / area); \
209 int a = (int)(((Sint64)w0 * c0.a + (Sint64)w1 * c1.a + (Sint64)w2 * c2.a) / area);
210
211#define TRIANGLE_END_LOOP \
212 } \
213 /* x += 1 */ \
214 w0 += d2d1_y; \
215 w1 += d0d2_y; \
216 w2 += d1d0_y; \
217 } \
218 /* y += 1 */ \
219 w0_row += d1d2_x; \
220 w1_row += d2d0_x; \
221 w2_row += d0d1_x; \
222 dst_ptr += dst_pitch; \
223 } \
224 }
225
226bool SDL_SW_FillTriangle(SDL_Surface *dst, SDL_Point *d0, SDL_Point *d1, SDL_Point *d2, SDL_BlendMode blend, SDL_Color c0, SDL_Color c1, SDL_Color c2)
227{
228 bool result = true;
229 int dst_locked = 0;
230
231 SDL_Rect dstrect;
232
233 int dstbpp;
234 Uint8 *dst_ptr;
235 int dst_pitch;
236
237 Sint64 area;
238 int is_clockwise;
239
240 int d2d1_y, d1d2_x, d0d2_y, d2d0_x, d1d0_y, d0d1_x;
241 Sint64 w0_row, w1_row, w2_row;
242 int bias_w0, bias_w1, bias_w2;
243
244 bool is_uniform;
245
246 SDL_Surface *tmp = NULL;
247
248 if (!SDL_SurfaceValid(dst)) {
249 return false;
250 }
251
252 area = cross_product(d0, d1, d2->x, d2->y);
253
254 is_uniform = COLOR_EQ(c0, c1) && COLOR_EQ(c1, c2);
255
256 // Flat triangle
257 if (area == 0) {
258 return true;
259 }
260
261 // Lock the destination, if needed
262 if (SDL_MUSTLOCK(dst)) {
263 if (!SDL_LockSurface(dst)) {
264 result = false;
265 goto end;
266 } else {
267 dst_locked = 1;
268 }
269 }
270
271 bounding_rect_fixedpoint(d0, d1, d2, &dstrect);
272
273 {
274 // Clip triangle rect with surface rect
275 SDL_Rect rect;
276 rect.x = 0;
277 rect.y = 0;
278 rect.w = dst->w;
279 rect.h = dst->h;
280 SDL_GetRectIntersection(&dstrect, &rect, &dstrect);
281 }
282
283 {
284 // Clip triangle with surface clip rect
285 SDL_Rect rect;
286 SDL_GetSurfaceClipRect(dst, &rect);
287 SDL_GetRectIntersection(&dstrect, &rect, &dstrect);
288 }
289
290 if (blend != SDL_BLENDMODE_NONE) {
291 SDL_PixelFormat format = dst->format;
292
293 // need an alpha format
294 if (!SDL_ISPIXELFORMAT_ALPHA(format)) {
295 format = SDL_PIXELFORMAT_ARGB8888;
296 }
297
298 // Use an intermediate surface
299 tmp = SDL_CreateSurface(dstrect.w, dstrect.h, format);
300 if (!tmp) {
301 result = false;
302 goto end;
303 }
304
305 if (blend == SDL_BLENDMODE_MOD) {
306 Uint32 c = SDL_MapSurfaceRGBA(tmp, 255, 255, 255, 255);
307 SDL_FillSurfaceRect(tmp, NULL, c);
308 }
309
310 SDL_SetSurfaceBlendMode(tmp, blend);
311
312 dstbpp = tmp->fmt->bytes_per_pixel;
313 dst_ptr = (Uint8 *)tmp->pixels;
314 dst_pitch = tmp->pitch;
315
316 } else {
317 // Write directly to destination surface
318 dstbpp = dst->fmt->bytes_per_pixel;
319 dst_ptr = (Uint8 *)dst->pixels + dstrect.x * dstbpp + dstrect.y * dst->pitch;
320 dst_pitch = dst->pitch;
321 }
322
323 is_clockwise = area > 0;
324 if (area < 0) {
325 area = -area;
326 }
327
328 {
329 int val;
330 PRECOMP(d2d1_y, d1->y - d2->y)
331 PRECOMP(d0d2_y, d2->y - d0->y)
332 PRECOMP(d1d0_y, d0->y - d1->y)
333 PRECOMP(d1d2_x, d2->x - d1->x)
334 PRECOMP(d2d0_x, d0->x - d2->x)
335 PRECOMP(d0d1_x, d1->x - d0->x)
336 }
337
338 // Starting point for rendering, at the middle of a pixel
339 {
340 SDL_Point p;
341 p.x = dstrect.x;
342 p.y = dstrect.y;
343 trianglepoint_2_fixedpoint(&p);
344 p.x += (1 << FP_BITS) / 2;
345 p.y += (1 << FP_BITS) / 2;
346 w0_row = cross_product(d1, d2, p.x, p.y);
347 w1_row = cross_product(d2, d0, p.x, p.y);
348 w2_row = cross_product(d0, d1, p.x, p.y);
349 }
350
351 // Handle anti-clockwise triangles
352 if (!is_clockwise) {
353 d2d1_y *= -1;
354 d0d2_y *= -1;
355 d1d0_y *= -1;
356 d1d2_x *= -1;
357 d2d0_x *= -1;
358 d0d1_x *= -1;
359 w0_row *= -1;
360 w1_row *= -1;
361 w2_row *= -1;
362 }
363
364 // Add a bias to respect top-left rasterization rule
365 bias_w0 = (is_top_left(d1, d2, is_clockwise) ? 0 : -1);
366 bias_w1 = (is_top_left(d2, d0, is_clockwise) ? 0 : -1);
367 bias_w2 = (is_top_left(d0, d1, is_clockwise) ? 0 : -1);
368
369 if (is_uniform) {
370 Uint32 color;
371 if (tmp) {
372 color = SDL_MapSurfaceRGBA(tmp, c0.r, c0.g, c0.b, c0.a);
373 } else {
374 color = SDL_MapSurfaceRGBA(dst, c0.r, c0.g, c0.b, c0.a);
375 }
376
377 if (dstbpp == 4) {
378 TRIANGLE_BEGIN_LOOP
379 {
380 *(Uint32 *)dptr = color;
381 }
382 TRIANGLE_END_LOOP
383 } else if (dstbpp == 3) {
384 TRIANGLE_BEGIN_LOOP
385 {
386 Uint8 *s = (Uint8 *)&color;
387 dptr[0] = s[0];
388 dptr[1] = s[1];
389 dptr[2] = s[2];
390 }
391 TRIANGLE_END_LOOP
392 } else if (dstbpp == 2) {
393 TRIANGLE_BEGIN_LOOP
394 {
395 *(Uint16 *)dptr = (Uint16)color;
396 }
397 TRIANGLE_END_LOOP
398 } else if (dstbpp == 1) {
399 TRIANGLE_BEGIN_LOOP
400 {
401 *dptr = (Uint8)color;
402 }
403 TRIANGLE_END_LOOP
404 }
405 } else {
406 const SDL_PixelFormatDetails *format;
407 SDL_Palette *palette;
408 if (tmp) {
409 format = tmp->fmt;
410 palette = tmp->palette;
411 } else {
412 format = dst->fmt;
413 palette = dst->palette;
414 }
415 if (dstbpp == 4) {
416 TRIANGLE_BEGIN_LOOP
417 {
418 TRIANGLE_GET_MAPPED_COLOR
419 *(Uint32 *)dptr = color;
420 }
421 TRIANGLE_END_LOOP
422 } else if (dstbpp == 3) {
423 TRIANGLE_BEGIN_LOOP
424 {
425 TRIANGLE_GET_MAPPED_COLOR
426 Uint8 *s = (Uint8 *)&color;
427 dptr[0] = s[0];
428 dptr[1] = s[1];
429 dptr[2] = s[2];
430 }
431 TRIANGLE_END_LOOP
432 } else if (dstbpp == 2) {
433 TRIANGLE_BEGIN_LOOP
434 {
435 TRIANGLE_GET_MAPPED_COLOR
436 *(Uint16 *)dptr = (Uint16)color;
437 }
438 TRIANGLE_END_LOOP
439 } else if (dstbpp == 1) {
440 TRIANGLE_BEGIN_LOOP
441 {
442 TRIANGLE_GET_MAPPED_COLOR
443 *dptr = (Uint8)color;
444 }
445 TRIANGLE_END_LOOP
446 }
447 }
448
449 if (tmp) {
450 SDL_BlitSurface(tmp, NULL, dst, &dstrect);
451 SDL_DestroySurface(tmp);
452 }
453
454end:
455 if (dst_locked) {
456 SDL_UnlockSurface(dst);
457 }
458
459 return result;
460}
461
462bool SDL_SW_BlitTriangle(
463 SDL_Surface *src,
464 SDL_Point *s0, SDL_Point *s1, SDL_Point *s2,
465 SDL_Surface *dst,
466 SDL_Point *d0, SDL_Point *d1, SDL_Point *d2,
467 SDL_Color c0, SDL_Color c1, SDL_Color c2,
468 SDL_TextureAddressMode texture_address_mode)
469{
470 bool result = true;
471 SDL_Surface *src_surface = src;
472 int src_locked = 0;
473 int dst_locked = 0;
474
475 SDL_BlendMode blend;
476
477 SDL_Rect dstrect;
478
479 SDL_Point s2_x_area;
480
481 int dstbpp;
482 Uint8 *dst_ptr;
483 int dst_pitch;
484
485 const int *src_ptr;
486 int src_pitch;
487
488 Sint64 area, tmp64;
489 int is_clockwise;
490
491 int d2d1_y, d1d2_x, d0d2_y, d2d0_x, d1d0_y, d0d1_x;
492 int s2s0_x, s2s1_x, s2s0_y, s2s1_y;
493
494 Sint64 w0_row, w1_row, w2_row;
495 int bias_w0, bias_w1, bias_w2;
496
497 bool is_uniform;
498
499 bool has_modulation;
500
501 if (!SDL_SurfaceValid(src)) {
502 return SDL_InvalidParamError("src");
503 }
504 if (!SDL_SurfaceValid(dst)) {
505 return SDL_InvalidParamError("dst");
506 }
507
508 area = cross_product(d0, d1, d2->x, d2->y);
509
510 // Flat triangle
511 if (area == 0) {
512 return true;
513 }
514
515 // Lock the destination, if needed
516 if (SDL_MUSTLOCK(dst)) {
517 if (!SDL_LockSurface(dst)) {
518 result = false;
519 goto end;
520 } else {
521 dst_locked = 1;
522 }
523 }
524
525 // Lock the source, if needed
526 if (SDL_MUSTLOCK(src)) {
527 if (!SDL_LockSurface(src)) {
528 result = false;
529 goto end;
530 } else {
531 src_locked = 1;
532 }
533 }
534
535 is_uniform = COLOR_EQ(c0, c1) && COLOR_EQ(c1, c2);
536
537 bounding_rect_fixedpoint(d0, d1, d2, &dstrect);
538
539 SDL_GetSurfaceBlendMode(src, &blend);
540
541 // TRIANGLE_GET_TEXTCOORD interpolates up to the max values included, so reduce by 1
542 if (texture_address_mode == SDL_TEXTURE_ADDRESS_CLAMP) {
543 SDL_Rect srcrect;
544 int maxx, maxy;
545 bounding_rect(s0, s1, s2, &srcrect);
546 maxx = srcrect.x + srcrect.w;
547 maxy = srcrect.y + srcrect.h;
548 if (srcrect.w > 0) {
549 if (s0->x == maxx) {
550 s0->x--;
551 }
552 if (s1->x == maxx) {
553 s1->x--;
554 }
555 if (s2->x == maxx) {
556 s2->x--;
557 }
558 }
559 if (srcrect.h > 0) {
560 if (s0->y == maxy) {
561 s0->y--;
562 }
563 if (s1->y == maxy) {
564 s1->y--;
565 }
566 if (s2->y == maxy) {
567 s2->y--;
568 }
569 }
570 }
571
572 if (is_uniform) {
573 // SDL_GetSurfaceColorMod(src, &r, &g, &b);
574 has_modulation = c0.r != 255 || c0.g != 255 || c0.b != 255 || c0.a != 255;
575 } else {
576 has_modulation = true;
577 }
578
579 {
580 // Clip triangle with surface clip rect
581 SDL_Rect rect;
582 SDL_GetSurfaceClipRect(dst, &rect);
583 SDL_GetRectIntersection(&dstrect, &rect, &dstrect);
584 }
585
586 // Set destination pointer
587 dstbpp = dst->fmt->bytes_per_pixel;
588 dst_ptr = (Uint8 *)dst->pixels + dstrect.x * dstbpp + dstrect.y * dst->pitch;
589 dst_pitch = dst->pitch;
590
591 // Set source pointer
592 src_ptr = (const int *)src->pixels;
593 src_pitch = src->pitch;
594
595 is_clockwise = area > 0;
596 if (area < 0) {
597 area = -area;
598 }
599
600 {
601 int val;
602 PRECOMP(d2d1_y, d1->y - d2->y)
603 PRECOMP(d0d2_y, d2->y - d0->y)
604 PRECOMP(d1d0_y, d0->y - d1->y)
605 PRECOMP(d1d2_x, d2->x - d1->x)
606 PRECOMP(d2d0_x, d0->x - d2->x)
607 PRECOMP(d0d1_x, d1->x - d0->x)
608 }
609
610 s2s0_x = s0->x - s2->x;
611 s2s1_x = s1->x - s2->x;
612 s2s0_y = s0->y - s2->y;
613 s2s1_y = s1->y - s2->y;
614
615 // Starting point for rendering, at the middle of a pixel
616 {
617 SDL_Point p;
618 p.x = dstrect.x;
619 p.y = dstrect.y;
620 trianglepoint_2_fixedpoint(&p);
621 p.x += (1 << FP_BITS) / 2;
622 p.y += (1 << FP_BITS) / 2;
623 w0_row = cross_product(d1, d2, p.x, p.y);
624 w1_row = cross_product(d2, d0, p.x, p.y);
625 w2_row = cross_product(d0, d1, p.x, p.y);
626 }
627
628 // Handle anti-clockwise triangles
629 if (!is_clockwise) {
630 d2d1_y *= -1;
631 d0d2_y *= -1;
632 d1d0_y *= -1;
633 d1d2_x *= -1;
634 d2d0_x *= -1;
635 d0d1_x *= -1;
636 w0_row *= -1;
637 w1_row *= -1;
638 w2_row *= -1;
639 }
640
641 // Add a bias to respect top-left rasterization rule
642 bias_w0 = (is_top_left(d1, d2, is_clockwise) ? 0 : -1);
643 bias_w1 = (is_top_left(d2, d0, is_clockwise) ? 0 : -1);
644 bias_w2 = (is_top_left(d0, d1, is_clockwise) ? 0 : -1);
645
646 /* precompute constant 's2->x * area' used in TRIANGLE_GET_TEXTCOORD */
647 tmp64 = s2->x * area;
648 if (tmp64 >= INT_MIN && tmp64 <= INT_MAX) {
649 s2_x_area.x = (int)tmp64;
650 } else {
651 result = SDL_SetError("triangle area overflow");
652 goto end;
653 }
654 tmp64 = s2->y * area;
655 if (tmp64 >= INT_MIN && tmp64 <= INT_MAX) {
656 s2_x_area.y = (int)tmp64;
657 } else {
658 result = SDL_SetError("triangle area overflow");
659 goto end;
660 }
661
662 if (blend != SDL_BLENDMODE_NONE || src->format != dst->format || has_modulation || !is_uniform) {
663 // Use SDL_BlitTriangle_Slow
664
665 SDL_BlitInfo *info = &src->map.info;
666 SDL_BlitInfo tmp_info;
667
668 SDL_zero(tmp_info);
669
670 tmp_info.src_fmt = src->fmt;
671 tmp_info.dst_fmt = dst->fmt;
672 tmp_info.flags = info->flags;
673 /*
674 tmp_info.r = info->r;
675 tmp_info.g = info->g;
676 tmp_info.b = info->b;
677 tmp_info.a = info->a;
678 */
679 tmp_info.r = c0.r;
680 tmp_info.g = c0.g;
681 tmp_info.b = c0.b;
682 tmp_info.a = c0.a;
683
684 tmp_info.flags &= ~(SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA);
685
686 if (c0.r != 255 || c1.r != 255 || c2.r != 255 ||
687 c0.g != 255 || c1.g != 255 || c2.g != 255 ||
688 c0.b != 255 || c1.b != 255 || c2.b != 255) {
689 tmp_info.flags |= SDL_COPY_MODULATE_COLOR;
690 }
691
692 if (c0.a != 255 || c1.a != 255 || c2.a != 255) {
693 tmp_info.flags |= SDL_COPY_MODULATE_ALPHA;
694 }
695
696 tmp_info.colorkey = info->colorkey;
697
698 // src
699 tmp_info.src_surface = src_surface;
700 tmp_info.src = (Uint8 *)src_ptr;
701 tmp_info.src_pitch = src_pitch;
702
703 // dst
704 tmp_info.dst = dst_ptr;
705 tmp_info.dst_pitch = dst_pitch;
706
707#define CHECK_INT_RANGE(X) \
708 if ((X) < INT_MIN || (X) > INT_MAX) { \
709 result = SDL_SetError("integer overflow (%s = %" SDL_PRIs64 ")", #X, X); \
710 goto end; \
711 }
712 CHECK_INT_RANGE(area);
713 CHECK_INT_RANGE(w0_row);
714 CHECK_INT_RANGE(w1_row);
715 CHECK_INT_RANGE(w2_row);
716 SDL_BlitTriangle_Slow(&tmp_info, s2_x_area, dstrect, (int)area, bias_w0, bias_w1, bias_w2,
717 d2d1_y, d1d2_x, d0d2_y, d2d0_x, d1d0_y, d0d1_x,
718 s2s0_x, s2s1_x, s2s0_y, s2s1_y, (int)w0_row, (int)w1_row, (int)w2_row,
719 c0, c1, c2, is_uniform, texture_address_mode);
720
721 goto end;
722 }
723
724 if (dstbpp == 4) {
725 TRIANGLE_BEGIN_LOOP
726 {
727 TRIANGLE_GET_TEXTCOORD
728 Uint32 *sptr = (Uint32 *)((Uint8 *)src_ptr + srcy * src_pitch);
729 *(Uint32 *)dptr = sptr[srcx];
730 }
731 TRIANGLE_END_LOOP
732 } else if (dstbpp == 3) {
733 TRIANGLE_BEGIN_LOOP
734 {
735 TRIANGLE_GET_TEXTCOORD
736 Uint8 *sptr = (Uint8 *)src_ptr + srcy * src_pitch;
737 dptr[0] = sptr[3 * srcx];
738 dptr[1] = sptr[3 * srcx + 1];
739 dptr[2] = sptr[3 * srcx + 2];
740 }
741 TRIANGLE_END_LOOP
742 } else if (dstbpp == 2) {
743 TRIANGLE_BEGIN_LOOP
744 {
745 TRIANGLE_GET_TEXTCOORD
746 Uint16 *sptr = (Uint16 *)((Uint8 *)src_ptr + srcy * src_pitch);
747 *(Uint16 *)dptr = sptr[srcx];
748 }
749 TRIANGLE_END_LOOP
750 } else if (dstbpp == 1) {
751 TRIANGLE_BEGIN_LOOP
752 {
753 TRIANGLE_GET_TEXTCOORD
754 Uint8 *sptr = (Uint8 *)src_ptr + srcy * src_pitch;
755 *dptr = sptr[srcx];
756 }
757 TRIANGLE_END_LOOP
758 }
759
760end:
761 if (dst_locked) {
762 SDL_UnlockSurface(dst);
763 }
764 if (src_locked) {
765 SDL_UnlockSurface(src);
766 }
767
768 return result;
769}
770
771#define FORMAT_ALPHA 0
772#define FORMAT_NO_ALPHA -1
773#define FORMAT_2101010 1
774#define FORMAT_HAS_ALPHA(format) format == 0
775#define FORMAT_HAS_NO_ALPHA(format) format < 0
776static int detect_format(const SDL_PixelFormatDetails *pf)
777{
778 if (pf->format == SDL_PIXELFORMAT_ARGB2101010) {
779 return FORMAT_2101010;
780 } else if (pf->Amask) {
781 return FORMAT_ALPHA;
782 } else {
783 return FORMAT_NO_ALPHA;
784 }
785}
786
787static void SDL_BlitTriangle_Slow(SDL_BlitInfo *info,
788 SDL_Point s2_x_area, SDL_Rect dstrect, int area, int bias_w0, int bias_w1, int bias_w2,
789 int d2d1_y, int d1d2_x, int d0d2_y, int d2d0_x, int d1d0_y, int d0d1_x,
790 int s2s0_x, int s2s1_x, int s2s0_y, int s2s1_y, int w0_row, int w1_row, int w2_row,
791 SDL_Color c0, SDL_Color c1, SDL_Color c2, bool is_uniform, SDL_TextureAddressMode texture_address_mode)
792{
793 SDL_Surface *src_surface = info->src_surface;
794 const int flags = info->flags;
795 Uint32 modulateR = info->r;
796 Uint32 modulateG = info->g;
797 Uint32 modulateB = info->b;
798 Uint32 modulateA = info->a;
799 Uint32 srcpixel;
800 Uint32 srcR, srcG, srcB, srcA;
801 Uint32 dstpixel;
802 Uint32 dstR, dstG, dstB, dstA;
803 const SDL_PixelFormatDetails *src_fmt = info->src_fmt;
804 const SDL_PixelFormatDetails *dst_fmt = info->dst_fmt;
805 int srcbpp = src_fmt->bytes_per_pixel;
806 int dstbpp = dst_fmt->bytes_per_pixel;
807 int srcfmt_val;
808 int dstfmt_val;
809 Uint32 rgbmask = ~src_fmt->Amask;
810 Uint32 ckey = info->colorkey & rgbmask;
811
812 Uint8 *dst_ptr = info->dst;
813 int dst_pitch = info->dst_pitch;
814
815 srcfmt_val = detect_format(src_fmt);
816 dstfmt_val = detect_format(dst_fmt);
817
818 TRIANGLE_BEGIN_LOOP
819 {
820 Uint8 *src;
821 Uint8 *dst = dptr;
822 TRIANGLE_GET_TEXTCOORD
823 src = (info->src + (srcy * info->src_pitch) + (srcx * srcbpp));
824 if (FORMAT_HAS_ALPHA(srcfmt_val)) {
825 DISEMBLE_RGBA(src, srcbpp, src_fmt, srcpixel, srcR, srcG, srcB, srcA);
826 } else if (FORMAT_HAS_NO_ALPHA(srcfmt_val)) {
827 DISEMBLE_RGB(src, srcbpp, src_fmt, srcpixel, srcR, srcG, srcB);
828 srcA = 0xFF;
829 } else {
830 // SDL_PIXELFORMAT_ARGB2101010
831 srcpixel = *((Uint32 *)(src));
832 RGBA_FROM_ARGB2101010(srcpixel, srcR, srcG, srcB, srcA);
833 }
834 if (flags & SDL_COPY_COLORKEY) {
835 // srcpixel isn't set for 24 bpp
836 if (srcbpp == 3) {
837 srcpixel = (srcR << src_fmt->Rshift) |
838 (srcG << src_fmt->Gshift) | (srcB << src_fmt->Bshift);
839 }
840 if ((srcpixel & rgbmask) == ckey) {
841 continue;
842 }
843 }
844 if ((flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL))) {
845 if (FORMAT_HAS_ALPHA(dstfmt_val)) {
846 DISEMBLE_RGBA(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB, dstA);
847 } else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) {
848 DISEMBLE_RGB(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB);
849 dstA = 0xFF;
850 } else {
851 // SDL_PIXELFORMAT_ARGB2101010
852 dstpixel = *((Uint32 *) (dst));
853 RGBA_FROM_ARGB2101010(dstpixel, dstR, dstG, dstB, dstA);
854 }
855 } else {
856 // don't care
857 dstR = dstG = dstB = dstA = 0;
858 }
859
860 if (!is_uniform) {
861 TRIANGLE_GET_COLOR
862 modulateR = r;
863 modulateG = g;
864 modulateB = b;
865 modulateA = a;
866 }
867
868 if (flags & SDL_COPY_MODULATE_COLOR) {
869 srcR = (srcR * modulateR) / 255;
870 srcG = (srcG * modulateG) / 255;
871 srcB = (srcB * modulateB) / 255;
872 }
873 if (flags & SDL_COPY_MODULATE_ALPHA) {
874 srcA = (srcA * modulateA) / 255;
875 }
876 if (flags & (SDL_COPY_BLEND | SDL_COPY_ADD)) {
877 // This goes away if we ever use premultiplied alpha
878 if (srcA < 255) {
879 srcR = (srcR * srcA) / 255;
880 srcG = (srcG * srcA) / 255;
881 srcB = (srcB * srcA) / 255;
882 }
883 }
884 switch (flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL)) {
885 case 0:
886 dstR = srcR;
887 dstG = srcG;
888 dstB = srcB;
889 dstA = srcA;
890 break;
891 case SDL_COPY_BLEND:
892 dstR = srcR + ((255 - srcA) * dstR) / 255;
893 dstG = srcG + ((255 - srcA) * dstG) / 255;
894 dstB = srcB + ((255 - srcA) * dstB) / 255;
895 dstA = srcA + ((255 - srcA) * dstA) / 255;
896 break;
897 case SDL_COPY_ADD:
898 dstR = srcR + dstR;
899 if (dstR > 255) {
900 dstR = 255;
901 }
902 dstG = srcG + dstG;
903 if (dstG > 255) {
904 dstG = 255;
905 }
906 dstB = srcB + dstB;
907 if (dstB > 255) {
908 dstB = 255;
909 }
910 break;
911 case SDL_COPY_MOD:
912 dstR = (srcR * dstR) / 255;
913 dstG = (srcG * dstG) / 255;
914 dstB = (srcB * dstB) / 255;
915 break;
916 case SDL_COPY_MUL:
917 dstR = ((srcR * dstR) + (dstR * (255 - srcA))) / 255;
918 if (dstR > 255) {
919 dstR = 255;
920 }
921 dstG = ((srcG * dstG) + (dstG * (255 - srcA))) / 255;
922 if (dstG > 255) {
923 dstG = 255;
924 }
925 dstB = ((srcB * dstB) + (dstB * (255 - srcA))) / 255;
926 if (dstB > 255) {
927 dstB = 255;
928 }
929 break;
930 }
931 if (FORMAT_HAS_ALPHA(dstfmt_val)) {
932 ASSEMBLE_RGBA(dst, dstbpp, dst_fmt, dstR, dstG, dstB, dstA);
933 } else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) {
934 ASSEMBLE_RGB(dst, dstbpp, dst_fmt, dstR, dstG, dstB);
935 } else {
936 // SDL_PIXELFORMAT_ARGB2101010
937 Uint32 pixel;
938 ARGB2101010_FROM_RGBA(pixel, dstR, dstG, dstB, dstA);
939 *(Uint32 *)dst = pixel;
940 }
941 }
942 TRIANGLE_END_LOOP
943}
944
945#endif // SDL_VIDEO_RENDER_SW
diff --git a/contrib/SDL-3.2.8/src/render/software/SDL_triangle.h b/contrib/SDL-3.2.8/src/render/software/SDL_triangle.h
new file mode 100644
index 0000000..1c5504c
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/render/software/SDL_triangle.h
@@ -0,0 +1,42 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 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
22#ifndef SDL_triangle_h_
23#define SDL_triangle_h_
24
25#include "SDL_internal.h"
26
27#include "../SDL_sysrender.h" // For SDL_TextureAddressMode
28
29extern bool SDL_SW_FillTriangle(SDL_Surface *dst,
30 SDL_Point *d0, SDL_Point *d1, SDL_Point *d2,
31 SDL_BlendMode blend, SDL_Color c0, SDL_Color c1, SDL_Color c2);
32
33extern bool SDL_SW_BlitTriangle(SDL_Surface *src,
34 SDL_Point *s0, SDL_Point *s1, SDL_Point *s2,
35 SDL_Surface *dst,
36 SDL_Point *d0, SDL_Point *d1, SDL_Point *d2,
37 SDL_Color c0, SDL_Color c1, SDL_Color c2,
38 SDL_TextureAddressMode texture_address_mode);
39
40extern void trianglepoint_2_fixedpoint(SDL_Point *a);
41
42#endif // SDL_triangle_h_