From 5a079a2d114f96d4847d1ee305d5b7c16eeec50e Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 27 Dec 2025 12:03:39 -0800 Subject: Initial commit --- .../src/render/software/SDL_blendfillrect.c | 371 ++++++ .../src/render/software/SDL_blendfillrect.h | 30 + .../SDL-3.2.8/src/render/software/SDL_blendline.c | 986 ++++++++++++++++ .../SDL-3.2.8/src/render/software/SDL_blendline.h | 30 + .../SDL-3.2.8/src/render/software/SDL_blendpoint.c | 376 ++++++ .../SDL-3.2.8/src/render/software/SDL_blendpoint.h | 30 + contrib/SDL-3.2.8/src/render/software/SDL_draw.h | 723 ++++++++++++ .../SDL-3.2.8/src/render/software/SDL_drawline.c | 199 ++++ .../SDL-3.2.8/src/render/software/SDL_drawline.h | 30 + .../SDL-3.2.8/src/render/software/SDL_drawpoint.c | 108 ++ .../SDL-3.2.8/src/render/software/SDL_drawpoint.h | 30 + .../SDL-3.2.8/src/render/software/SDL_render_sw.c | 1202 ++++++++++++++++++++ .../src/render/software/SDL_render_sw_c.h | 27 + contrib/SDL-3.2.8/src/render/software/SDL_rotate.c | 612 ++++++++++ contrib/SDL-3.2.8/src/render/software/SDL_rotate.h | 30 + .../SDL-3.2.8/src/render/software/SDL_triangle.c | 945 +++++++++++++++ .../SDL-3.2.8/src/render/software/SDL_triangle.h | 42 + 17 files changed, 5771 insertions(+) create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_blendfillrect.c create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_blendfillrect.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_blendline.c create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_blendline.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_blendpoint.c create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_blendpoint.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_draw.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_drawline.c create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_drawline.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_drawpoint.c create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_drawpoint.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_render_sw.c create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_render_sw_c.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_rotate.c create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_rotate.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_triangle.c create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_triangle.h (limited to 'contrib/SDL-3.2.8/src/render/software') 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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_RENDER_SW + +#include "SDL_draw.h" +#include "SDL_blendfillrect.h" + +static bool SDL_BlendFillRect_RGB555(SDL_Surface *dst, const SDL_Rect *rect, + SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + unsigned inva = 0xff - a; + + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB555); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB555); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + FILLRECT(Uint16, DRAW_SETPIXEL_ADD_RGB555); + break; + case SDL_BLENDMODE_MOD: + FILLRECT(Uint16, DRAW_SETPIXEL_MOD_RGB555); + break; + case SDL_BLENDMODE_MUL: + FILLRECT(Uint16, DRAW_SETPIXEL_MUL_RGB555); + break; + default: + FILLRECT(Uint16, DRAW_SETPIXEL_RGB555); + break; + } + return true; +} + +static bool SDL_BlendFillRect_RGB565(SDL_Surface *dst, const SDL_Rect *rect, + SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + unsigned inva = 0xff - a; + + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB565); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB565); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + FILLRECT(Uint16, DRAW_SETPIXEL_ADD_RGB565); + break; + case SDL_BLENDMODE_MOD: + FILLRECT(Uint16, DRAW_SETPIXEL_MOD_RGB565); + break; + case SDL_BLENDMODE_MUL: + FILLRECT(Uint16, DRAW_SETPIXEL_MUL_RGB565); + break; + default: + FILLRECT(Uint16, DRAW_SETPIXEL_RGB565); + break; + } + return true; +} + +static bool SDL_BlendFillRect_XRGB8888(SDL_Surface *dst, const SDL_Rect *rect, + SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + unsigned inva = 0xff - a; + + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_XRGB8888); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + FILLRECT(Uint32, DRAW_SETPIXEL_ADD_XRGB8888); + break; + case SDL_BLENDMODE_MOD: + FILLRECT(Uint32, DRAW_SETPIXEL_MOD_XRGB8888); + break; + case SDL_BLENDMODE_MUL: + FILLRECT(Uint32, DRAW_SETPIXEL_MUL_XRGB8888); + break; + default: + FILLRECT(Uint32, DRAW_SETPIXEL_XRGB8888); + break; + } + return true; +} + +static bool SDL_BlendFillRect_ARGB8888(SDL_Surface *dst, const SDL_Rect *rect, + SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + unsigned inva = 0xff - a; + + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + FILLRECT(Uint32, DRAW_SETPIXEL_ADD_ARGB8888); + break; + case SDL_BLENDMODE_MOD: + FILLRECT(Uint32, DRAW_SETPIXEL_MOD_ARGB8888); + break; + case SDL_BLENDMODE_MUL: + FILLRECT(Uint32, DRAW_SETPIXEL_MUL_ARGB8888); + break; + default: + FILLRECT(Uint32, DRAW_SETPIXEL_ARGB8888); + break; + } + return true; +} + +static bool SDL_BlendFillRect_RGB(SDL_Surface *dst, const SDL_Rect *rect, + SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + const SDL_PixelFormatDetails *fmt = dst->fmt; + unsigned inva = 0xff - a; + + switch (fmt->bytes_per_pixel) { + case 2: + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + FILLRECT(Uint16, DRAW_SETPIXEL_ADD_RGB); + break; + case SDL_BLENDMODE_MOD: + FILLRECT(Uint16, DRAW_SETPIXEL_MOD_RGB); + break; + case SDL_BLENDMODE_MUL: + FILLRECT(Uint16, DRAW_SETPIXEL_MUL_RGB); + break; + default: + FILLRECT(Uint16, DRAW_SETPIXEL_RGB); + break; + } + return true; + case 4: + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGB); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGB); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + FILLRECT(Uint32, DRAW_SETPIXEL_ADD_RGB); + break; + case SDL_BLENDMODE_MOD: + FILLRECT(Uint32, DRAW_SETPIXEL_MOD_RGB); + break; + case SDL_BLENDMODE_MUL: + FILLRECT(Uint32, DRAW_SETPIXEL_MUL_RGB); + break; + default: + FILLRECT(Uint32, DRAW_SETPIXEL_RGB); + break; + } + return true; + default: + return SDL_Unsupported(); + } +} + +static bool SDL_BlendFillRect_RGBA(SDL_Surface *dst, const SDL_Rect *rect, + SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + const SDL_PixelFormatDetails *fmt = dst->fmt; + unsigned inva = 0xff - a; + + switch (fmt->bytes_per_pixel) { + case 4: + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGBA); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGBA); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + FILLRECT(Uint32, DRAW_SETPIXEL_ADD_RGBA); + break; + case SDL_BLENDMODE_MOD: + FILLRECT(Uint32, DRAW_SETPIXEL_MOD_RGBA); + break; + case SDL_BLENDMODE_MUL: + FILLRECT(Uint32, DRAW_SETPIXEL_MUL_RGBA); + break; + default: + FILLRECT(Uint32, DRAW_SETPIXEL_RGBA); + break; + } + return true; + default: + return SDL_Unsupported(); + } +} + +bool SDL_BlendFillRect(SDL_Surface *dst, const SDL_Rect *rect, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + SDL_Rect clipped; + + if (!SDL_SurfaceValid(dst)) { + return SDL_InvalidParamError("SDL_BlendFillRect(): dst"); + } + + // This function doesn't work on surfaces < 8 bpp + if (SDL_BITSPERPIXEL(dst->format) < 8) { + return SDL_SetError("SDL_BlendFillRect(): Unsupported surface format"); + } + + // If 'rect' == NULL, then fill the whole surface + if (rect) { + // Perform clipping + if (!SDL_GetRectIntersection(rect, &dst->clip_rect, &clipped)) { + return true; + } + rect = &clipped; + } else { + rect = &dst->clip_rect; + } + + if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) { + r = DRAW_MUL(r, a); + g = DRAW_MUL(g, a); + b = DRAW_MUL(b, a); + } + + switch (dst->fmt->bits_per_pixel) { + case 15: + switch (dst->fmt->Rmask) { + case 0x7C00: + return SDL_BlendFillRect_RGB555(dst, rect, blendMode, r, g, b, a); + } + break; + case 16: + switch (dst->fmt->Rmask) { + case 0xF800: + return SDL_BlendFillRect_RGB565(dst, rect, blendMode, r, g, b, a); + } + break; + case 32: + switch (dst->fmt->Rmask) { + case 0x00FF0000: + if (!dst->fmt->Amask) { + return SDL_BlendFillRect_XRGB8888(dst, rect, blendMode, r, g, b, a); + } else { + return SDL_BlendFillRect_ARGB8888(dst, rect, blendMode, r, g, b, a); + } + // break; -Wunreachable-code-break + } + break; + default: + break; + } + + if (!dst->fmt->Amask) { + return SDL_BlendFillRect_RGB(dst, rect, blendMode, r, g, b, a); + } else { + return SDL_BlendFillRect_RGBA(dst, rect, blendMode, r, g, b, a); + } +} + +bool SDL_BlendFillRects(SDL_Surface *dst, const SDL_Rect *rects, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + SDL_Rect rect; + int i; + bool (*func)(SDL_Surface * dst, const SDL_Rect *rect, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) = NULL; + bool result = true; + + if (!SDL_SurfaceValid(dst)) { + return SDL_InvalidParamError("SDL_BlendFillRects(): dst"); + } + + // This function doesn't work on surfaces < 8 bpp + if (dst->fmt->bits_per_pixel < 8) { + return SDL_SetError("SDL_BlendFillRects(): Unsupported surface format"); + } + + if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) { + r = DRAW_MUL(r, a); + g = DRAW_MUL(g, a); + b = DRAW_MUL(b, a); + } + + // FIXME: Does this function pointer slow things down significantly? + switch (dst->fmt->bits_per_pixel) { + case 15: + switch (dst->fmt->Rmask) { + case 0x7C00: + func = SDL_BlendFillRect_RGB555; + } + break; + case 16: + switch (dst->fmt->Rmask) { + case 0xF800: + func = SDL_BlendFillRect_RGB565; + } + break; + case 32: + switch (dst->fmt->Rmask) { + case 0x00FF0000: + if (!dst->fmt->Amask) { + func = SDL_BlendFillRect_XRGB8888; + } else { + func = SDL_BlendFillRect_ARGB8888; + } + break; + } + break; + default: + break; + } + + if (!func) { + if (!dst->fmt->Amask) { + func = SDL_BlendFillRect_RGB; + } else { + func = SDL_BlendFillRect_RGBA; + } + } + + for (i = 0; i < count; ++i) { + // Perform clipping + if (!SDL_GetRectIntersection(&rects[i], &dst->clip_rect, &rect)) { + continue; + } + result = func(dst, &rect, blendMode, r, g, b, a); + } + return result; +} + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_blendfillrect_h_ +#define SDL_blendfillrect_h_ + +#include "SDL_internal.h" + +extern bool SDL_BlendFillRect(SDL_Surface *dst, const SDL_Rect *rect, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a); +extern bool SDL_BlendFillRects(SDL_Surface *dst, const SDL_Rect *rects, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_RENDER_SW + +#include "SDL_draw.h" +#include "SDL_blendline.h" +#include "SDL_blendpoint.h" + +static void SDL_BlendLine_RGB2(SDL_Surface *dst, int x1, int y1, int x2, int y2, + SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a, + bool draw_end) +{ + const SDL_PixelFormatDetails *fmt = dst->fmt; + unsigned r, g, b, a, inva; + + if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) { + r = DRAW_MUL(_r, _a); + g = DRAW_MUL(_g, _a); + b = DRAW_MUL(_b, _a); + a = _a; + } else { + r = _r; + g = _g; + b = _b; + a = _a; + } + inva = (a ^ 0xff); + + if (y1 == y2) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + HLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + HLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + HLINE(Uint16, DRAW_SETPIXEL_ADD_RGB, draw_end); + break; + case SDL_BLENDMODE_MOD: + HLINE(Uint16, DRAW_SETPIXEL_MOD_RGB, draw_end); + break; + case SDL_BLENDMODE_MUL: + HLINE(Uint16, DRAW_SETPIXEL_MUL_RGB, draw_end); + break; + default: + HLINE(Uint16, DRAW_SETPIXEL_RGB, draw_end); + break; + } + } else if (x1 == x2) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + VLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + VLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + VLINE(Uint16, DRAW_SETPIXEL_ADD_RGB, draw_end); + break; + case SDL_BLENDMODE_MOD: + VLINE(Uint16, DRAW_SETPIXEL_MOD_RGB, draw_end); + break; + case SDL_BLENDMODE_MUL: + VLINE(Uint16, DRAW_SETPIXEL_MUL_RGB, draw_end); + break; + default: + VLINE(Uint16, DRAW_SETPIXEL_RGB, draw_end); + break; + } + } else if (ABS(x1 - x2) == ABS(y1 - y2)) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + DLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + DLINE(Uint16, DRAW_SETPIXEL_ADD_RGB, draw_end); + break; + case SDL_BLENDMODE_MOD: + DLINE(Uint16, DRAW_SETPIXEL_MOD_RGB, draw_end); + break; + case SDL_BLENDMODE_MUL: + DLINE(Uint16, DRAW_SETPIXEL_MUL_RGB, draw_end); + break; + default: + DLINE(Uint16, DRAW_SETPIXEL_RGB, draw_end); + break; + } + } else { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY2_BLEND_RGB, DRAW_SETPIXELXY2_BLEND_RGB, + draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY2_BLEND_CLAMPED_RGB, DRAW_SETPIXELXY2_BLEND_CLAMPED_RGB, + draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY2_ADD_RGB, DRAW_SETPIXELXY2_ADD_RGB, + draw_end); + break; + case SDL_BLENDMODE_MOD: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY2_MOD_RGB, DRAW_SETPIXELXY2_MOD_RGB, + draw_end); + break; + case SDL_BLENDMODE_MUL: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY2_MUL_RGB, DRAW_SETPIXELXY2_MUL_RGB, + draw_end); + break; + default: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY2_RGB, DRAW_SETPIXELXY2_BLEND_RGB, + draw_end); + break; + } + } +} + +static void SDL_BlendLine_RGB555(SDL_Surface *dst, int x1, int y1, int x2, int y2, + SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a, + bool draw_end) +{ + unsigned r, g, b, a, inva; + + if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) { + r = DRAW_MUL(_r, _a); + g = DRAW_MUL(_g, _a); + b = DRAW_MUL(_b, _a); + a = _a; + } else { + r = _r; + g = _g; + b = _b; + a = _a; + } + inva = (a ^ 0xff); + + if (y1 == y2) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + HLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB555, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + HLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB555, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + HLINE(Uint16, DRAW_SETPIXEL_ADD_RGB555, draw_end); + break; + case SDL_BLENDMODE_MOD: + HLINE(Uint16, DRAW_SETPIXEL_MOD_RGB555, draw_end); + break; + case SDL_BLENDMODE_MUL: + HLINE(Uint16, DRAW_SETPIXEL_MUL_RGB555, draw_end); + break; + default: + HLINE(Uint16, DRAW_SETPIXEL_RGB555, draw_end); + break; + } + } else if (x1 == x2) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + VLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB555, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + VLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB555, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + VLINE(Uint16, DRAW_SETPIXEL_ADD_RGB555, draw_end); + break; + case SDL_BLENDMODE_MOD: + VLINE(Uint16, DRAW_SETPIXEL_MOD_RGB555, draw_end); + break; + case SDL_BLENDMODE_MUL: + VLINE(Uint16, DRAW_SETPIXEL_MUL_RGB555, draw_end); + break; + default: + VLINE(Uint16, DRAW_SETPIXEL_RGB555, draw_end); + break; + } + } else if (ABS(x1 - x2) == ABS(y1 - y2)) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB555, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + DLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB555, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + DLINE(Uint16, DRAW_SETPIXEL_ADD_RGB555, draw_end); + break; + case SDL_BLENDMODE_MOD: + DLINE(Uint16, DRAW_SETPIXEL_MOD_RGB555, draw_end); + break; + case SDL_BLENDMODE_MUL: + DLINE(Uint16, DRAW_SETPIXEL_MUL_RGB555, draw_end); + break; + default: + DLINE(Uint16, DRAW_SETPIXEL_RGB555, draw_end); + break; + } + } else { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_BLEND_RGB555, DRAW_SETPIXELXY_BLEND_RGB555, + draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_BLEND_CLAMPED_RGB555, DRAW_SETPIXELXY_BLEND_CLAMPED_RGB555, + draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_ADD_RGB555, DRAW_SETPIXELXY_ADD_RGB555, + draw_end); + break; + case SDL_BLENDMODE_MOD: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_MOD_RGB555, DRAW_SETPIXELXY_MOD_RGB555, + draw_end); + break; + case SDL_BLENDMODE_MUL: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_MUL_RGB555, DRAW_SETPIXELXY_MUL_RGB555, + draw_end); + break; + default: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_RGB555, DRAW_SETPIXELXY_BLEND_RGB555, + draw_end); + break; + } + } +} + +static void SDL_BlendLine_RGB565(SDL_Surface *dst, int x1, int y1, int x2, int y2, + SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a, + bool draw_end) +{ + unsigned r, g, b, a, inva; + + if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) { + r = DRAW_MUL(_r, _a); + g = DRAW_MUL(_g, _a); + b = DRAW_MUL(_b, _a); + a = _a; + } else { + r = _r; + g = _g; + b = _b; + a = _a; + } + inva = (a ^ 0xff); + + if (y1 == y2) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + HLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB565, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + HLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB565, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + HLINE(Uint16, DRAW_SETPIXEL_ADD_RGB565, draw_end); + break; + case SDL_BLENDMODE_MOD: + HLINE(Uint16, DRAW_SETPIXEL_MOD_RGB565, draw_end); + break; + case SDL_BLENDMODE_MUL: + HLINE(Uint16, DRAW_SETPIXEL_MUL_RGB565, draw_end); + break; + default: + HLINE(Uint16, DRAW_SETPIXEL_RGB565, draw_end); + break; + } + } else if (x1 == x2) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + VLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB565, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + VLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB565, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + VLINE(Uint16, DRAW_SETPIXEL_ADD_RGB565, draw_end); + break; + case SDL_BLENDMODE_MOD: + VLINE(Uint16, DRAW_SETPIXEL_MOD_RGB565, draw_end); + break; + case SDL_BLENDMODE_MUL: + VLINE(Uint16, DRAW_SETPIXEL_MUL_RGB565, draw_end); + break; + default: + VLINE(Uint16, DRAW_SETPIXEL_RGB565, draw_end); + break; + } + } else if (ABS(x1 - x2) == ABS(y1 - y2)) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB565, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + DLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB565, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + DLINE(Uint16, DRAW_SETPIXEL_ADD_RGB565, draw_end); + break; + case SDL_BLENDMODE_MOD: + DLINE(Uint16, DRAW_SETPIXEL_MOD_RGB565, draw_end); + break; + case SDL_BLENDMODE_MUL: + DLINE(Uint16, DRAW_SETPIXEL_MUL_RGB565, draw_end); + break; + default: + DLINE(Uint16, DRAW_SETPIXEL_RGB565, draw_end); + break; + } + } else { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_BLEND_RGB565, DRAW_SETPIXELXY_BLEND_RGB565, + draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_BLEND_CLAMPED_RGB565, DRAW_SETPIXELXY_BLEND_CLAMPED_RGB565, + draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_ADD_RGB565, DRAW_SETPIXELXY_ADD_RGB565, + draw_end); + break; + case SDL_BLENDMODE_MOD: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_MOD_RGB565, DRAW_SETPIXELXY_MOD_RGB565, + draw_end); + break; + case SDL_BLENDMODE_MUL: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_MUL_RGB565, DRAW_SETPIXELXY_MUL_RGB565, + draw_end); + break; + default: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_RGB565, DRAW_SETPIXELXY_BLEND_RGB565, + draw_end); + break; + } + } +} + +static void SDL_BlendLine_RGB4(SDL_Surface *dst, int x1, int y1, int x2, int y2, + SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a, + bool draw_end) +{ + const SDL_PixelFormatDetails *fmt = dst->fmt; + unsigned r, g, b, a, inva; + + if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) { + r = DRAW_MUL(_r, _a); + g = DRAW_MUL(_g, _a); + b = DRAW_MUL(_b, _a); + a = _a; + } else { + r = _r; + g = _g; + b = _b; + a = _a; + } + inva = (a ^ 0xff); + + if (y1 == y2) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + HLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + HLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + HLINE(Uint32, DRAW_SETPIXEL_ADD_RGB, draw_end); + break; + case SDL_BLENDMODE_MOD: + HLINE(Uint32, DRAW_SETPIXEL_MOD_RGB, draw_end); + break; + case SDL_BLENDMODE_MUL: + HLINE(Uint32, DRAW_SETPIXEL_MUL_RGB, draw_end); + break; + default: + HLINE(Uint32, DRAW_SETPIXEL_RGB, draw_end); + break; + } + } else if (x1 == x2) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + VLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + VLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + VLINE(Uint32, DRAW_SETPIXEL_ADD_RGB, draw_end); + break; + case SDL_BLENDMODE_MOD: + VLINE(Uint32, DRAW_SETPIXEL_MOD_RGB, draw_end); + break; + case SDL_BLENDMODE_MUL: + VLINE(Uint32, DRAW_SETPIXEL_MUL_RGB, draw_end); + break; + default: + VLINE(Uint32, DRAW_SETPIXEL_RGB, draw_end); + break; + } + } else if (ABS(x1 - x2) == ABS(y1 - y2)) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + DLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + DLINE(Uint32, DRAW_SETPIXEL_ADD_RGB, draw_end); + break; + case SDL_BLENDMODE_MOD: + DLINE(Uint32, DRAW_SETPIXEL_MOD_RGB, draw_end); + break; + case SDL_BLENDMODE_MUL: + DLINE(Uint32, DRAW_SETPIXEL_MUL_RGB, draw_end); + break; + default: + DLINE(Uint32, DRAW_SETPIXEL_RGB, draw_end); + break; + } + } else { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY4_BLEND_RGB, DRAW_SETPIXELXY4_BLEND_RGB, + draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY4_BLEND_CLAMPED_RGB, DRAW_SETPIXELXY4_BLEND_CLAMPED_RGB, + draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY4_ADD_RGB, DRAW_SETPIXELXY4_ADD_RGB, + draw_end); + break; + case SDL_BLENDMODE_MOD: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY4_MOD_RGB, DRAW_SETPIXELXY4_MOD_RGB, + draw_end); + break; + case SDL_BLENDMODE_MUL: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY4_MUL_RGB, DRAW_SETPIXELXY4_MUL_RGB, + draw_end); + break; + default: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY4_RGB, DRAW_SETPIXELXY4_BLEND_RGB, + draw_end); + break; + } + } +} + +static void SDL_BlendLine_RGBA4(SDL_Surface *dst, int x1, int y1, int x2, int y2, + SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a, + bool draw_end) +{ + const SDL_PixelFormatDetails *fmt = dst->fmt; + unsigned r, g, b, a, inva; + + if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) { + r = DRAW_MUL(_r, _a); + g = DRAW_MUL(_g, _a); + b = DRAW_MUL(_b, _a); + a = _a; + } else { + r = _r; + g = _g; + b = _b; + a = _a; + } + inva = (a ^ 0xff); + + if (y1 == y2) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + HLINE(Uint32, DRAW_SETPIXEL_BLEND_RGBA, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + HLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGBA, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + HLINE(Uint32, DRAW_SETPIXEL_ADD_RGBA, draw_end); + break; + case SDL_BLENDMODE_MOD: + HLINE(Uint32, DRAW_SETPIXEL_MOD_RGBA, draw_end); + break; + case SDL_BLENDMODE_MUL: + HLINE(Uint32, DRAW_SETPIXEL_MUL_RGBA, draw_end); + break; + default: + HLINE(Uint32, DRAW_SETPIXEL_RGBA, draw_end); + break; + } + } else if (x1 == x2) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + VLINE(Uint32, DRAW_SETPIXEL_BLEND_RGBA, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + VLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGBA, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + VLINE(Uint32, DRAW_SETPIXEL_ADD_RGBA, draw_end); + break; + case SDL_BLENDMODE_MOD: + VLINE(Uint32, DRAW_SETPIXEL_MOD_RGBA, draw_end); + break; + case SDL_BLENDMODE_MUL: + VLINE(Uint32, DRAW_SETPIXEL_MUL_RGBA, draw_end); + break; + default: + VLINE(Uint32, DRAW_SETPIXEL_RGBA, draw_end); + break; + } + } else if (ABS(x1 - x2) == ABS(y1 - y2)) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DLINE(Uint32, DRAW_SETPIXEL_BLEND_RGBA, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + DLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGBA, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + DLINE(Uint32, DRAW_SETPIXEL_ADD_RGBA, draw_end); + break; + case SDL_BLENDMODE_MOD: + DLINE(Uint32, DRAW_SETPIXEL_MOD_RGBA, draw_end); + break; + case SDL_BLENDMODE_MUL: + DLINE(Uint32, DRAW_SETPIXEL_MUL_RGBA, draw_end); + break; + default: + DLINE(Uint32, DRAW_SETPIXEL_RGBA, draw_end); + break; + } + } else { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY4_BLEND_RGBA, DRAW_SETPIXELXY4_BLEND_RGBA, + draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY4_BLEND_CLAMPED_RGBA, DRAW_SETPIXELXY4_BLEND_CLAMPED_RGBA, + draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY4_ADD_RGBA, DRAW_SETPIXELXY4_ADD_RGBA, + draw_end); + break; + case SDL_BLENDMODE_MOD: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY4_MOD_RGBA, DRAW_SETPIXELXY4_MOD_RGBA, + draw_end); + break; + case SDL_BLENDMODE_MUL: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY4_MUL_RGBA, DRAW_SETPIXELXY4_MUL_RGBA, + draw_end); + break; + default: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY4_RGBA, DRAW_SETPIXELXY4_BLEND_RGBA, + draw_end); + break; + } + } +} + +static void SDL_BlendLine_XRGB8888(SDL_Surface *dst, int x1, int y1, int x2, int y2, + SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a, + bool draw_end) +{ + unsigned r, g, b, a, inva; + + if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) { + r = DRAW_MUL(_r, _a); + g = DRAW_MUL(_g, _a); + b = DRAW_MUL(_b, _a); + a = _a; + } else { + r = _r; + g = _g; + b = _b; + a = _a; + } + inva = (a ^ 0xff); + + if (y1 == y2) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + HLINE(Uint32, DRAW_SETPIXEL_BLEND_XRGB8888, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + HLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + HLINE(Uint32, DRAW_SETPIXEL_ADD_XRGB8888, draw_end); + break; + case SDL_BLENDMODE_MOD: + HLINE(Uint32, DRAW_SETPIXEL_MOD_XRGB8888, draw_end); + break; + case SDL_BLENDMODE_MUL: + HLINE(Uint32, DRAW_SETPIXEL_MUL_XRGB8888, draw_end); + break; + default: + HLINE(Uint32, DRAW_SETPIXEL_XRGB8888, draw_end); + break; + } + } else if (x1 == x2) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + VLINE(Uint32, DRAW_SETPIXEL_BLEND_XRGB8888, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + VLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + VLINE(Uint32, DRAW_SETPIXEL_ADD_XRGB8888, draw_end); + break; + case SDL_BLENDMODE_MOD: + VLINE(Uint32, DRAW_SETPIXEL_MOD_XRGB8888, draw_end); + break; + case SDL_BLENDMODE_MUL: + VLINE(Uint32, DRAW_SETPIXEL_MUL_XRGB8888, draw_end); + break; + default: + VLINE(Uint32, DRAW_SETPIXEL_XRGB8888, draw_end); + break; + } + } else if (ABS(x1 - x2) == ABS(y1 - y2)) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DLINE(Uint32, DRAW_SETPIXEL_BLEND_XRGB8888, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + DLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + DLINE(Uint32, DRAW_SETPIXEL_ADD_XRGB8888, draw_end); + break; + case SDL_BLENDMODE_MOD: + DLINE(Uint32, DRAW_SETPIXEL_MOD_XRGB8888, draw_end); + break; + case SDL_BLENDMODE_MUL: + DLINE(Uint32, DRAW_SETPIXEL_MUL_XRGB8888, draw_end); + break; + default: + DLINE(Uint32, DRAW_SETPIXEL_XRGB8888, draw_end); + break; + } + } else { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_BLEND_XRGB8888, DRAW_SETPIXELXY_BLEND_XRGB8888, + draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_BLEND_CLAMPED_XRGB8888, DRAW_SETPIXELXY_BLEND_CLAMPED_XRGB8888, + draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_ADD_XRGB8888, DRAW_SETPIXELXY_ADD_XRGB8888, + draw_end); + break; + case SDL_BLENDMODE_MOD: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_MOD_XRGB8888, DRAW_SETPIXELXY_MOD_XRGB8888, + draw_end); + break; + case SDL_BLENDMODE_MUL: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_MUL_XRGB8888, DRAW_SETPIXELXY_MUL_XRGB8888, + draw_end); + break; + default: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_XRGB8888, DRAW_SETPIXELXY_BLEND_XRGB8888, + draw_end); + break; + } + } +} + +static void SDL_BlendLine_ARGB8888(SDL_Surface *dst, int x1, int y1, int x2, int y2, + SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a, + bool draw_end) +{ + unsigned r, g, b, a, inva; + + if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) { + r = DRAW_MUL(_r, _a); + g = DRAW_MUL(_g, _a); + b = DRAW_MUL(_b, _a); + a = _a; + } else { + r = _r; + g = _g; + b = _b; + a = _a; + } + inva = (a ^ 0xff); + + if (y1 == y2) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + HLINE(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + HLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + HLINE(Uint32, DRAW_SETPIXEL_ADD_ARGB8888, draw_end); + break; + case SDL_BLENDMODE_MOD: + HLINE(Uint32, DRAW_SETPIXEL_MOD_ARGB8888, draw_end); + break; + case SDL_BLENDMODE_MUL: + HLINE(Uint32, DRAW_SETPIXEL_MUL_ARGB8888, draw_end); + break; + default: + HLINE(Uint32, DRAW_SETPIXEL_ARGB8888, draw_end); + break; + } + } else if (x1 == x2) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + VLINE(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + VLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + VLINE(Uint32, DRAW_SETPIXEL_ADD_ARGB8888, draw_end); + break; + case SDL_BLENDMODE_MOD: + VLINE(Uint32, DRAW_SETPIXEL_MOD_ARGB8888, draw_end); + break; + case SDL_BLENDMODE_MUL: + VLINE(Uint32, DRAW_SETPIXEL_MUL_ARGB8888, draw_end); + break; + default: + VLINE(Uint32, DRAW_SETPIXEL_ARGB8888, draw_end); + break; + } + } else if (ABS(x1 - x2) == ABS(y1 - y2)) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DLINE(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888, draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + DLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888, draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + DLINE(Uint32, DRAW_SETPIXEL_ADD_ARGB8888, draw_end); + break; + case SDL_BLENDMODE_MOD: + DLINE(Uint32, DRAW_SETPIXEL_MOD_ARGB8888, draw_end); + break; + case SDL_BLENDMODE_MUL: + DLINE(Uint32, DRAW_SETPIXEL_MUL_ARGB8888, draw_end); + break; + default: + DLINE(Uint32, DRAW_SETPIXEL_ARGB8888, draw_end); + break; + } + } else { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_BLEND_ARGB8888, DRAW_SETPIXELXY_BLEND_ARGB8888, + draw_end); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_BLEND_CLAMPED_ARGB8888, DRAW_SETPIXELXY_BLEND_CLAMPED_ARGB8888, + draw_end); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_ADD_ARGB8888, DRAW_SETPIXELXY_ADD_ARGB8888, + draw_end); + break; + case SDL_BLENDMODE_MOD: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_MOD_ARGB8888, DRAW_SETPIXELXY_MOD_ARGB8888, + draw_end); + break; + case SDL_BLENDMODE_MUL: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_MUL_ARGB8888, DRAW_SETPIXELXY_MUL_ARGB8888, + draw_end); + break; + default: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_ARGB8888, DRAW_SETPIXELXY_BLEND_ARGB8888, + draw_end); + break; + } + } +} + +typedef void (*BlendLineFunc)(SDL_Surface *dst, + int x1, int y1, int x2, int y2, + SDL_BlendMode blendMode, + Uint8 r, Uint8 g, Uint8 b, Uint8 a, + bool draw_end); + +static BlendLineFunc SDL_CalculateBlendLineFunc(const SDL_PixelFormatDetails *fmt) +{ + switch (fmt->bytes_per_pixel) { + case 2: + if (fmt->Rmask == 0x7C00) { + return SDL_BlendLine_RGB555; + } else if (fmt->Rmask == 0xF800) { + return SDL_BlendLine_RGB565; + } else { + return SDL_BlendLine_RGB2; + } + // break; -Wunreachable-code-break + case 4: + if (fmt->Rmask == 0x00FF0000) { + if (fmt->Amask) { + return SDL_BlendLine_ARGB8888; + } else { + return SDL_BlendLine_XRGB8888; + } + } else { + if (fmt->Amask) { + return SDL_BlendLine_RGBA4; + } else { + return SDL_BlendLine_RGB4; + } + } + } + return NULL; +} + +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) +{ + BlendLineFunc func; + + if (!SDL_SurfaceValid(dst)) { + return SDL_InvalidParamError("SDL_BlendLine(): dst"); + } + + func = SDL_CalculateBlendLineFunc(dst->fmt); + if (!func) { + return SDL_SetError("SDL_BlendLine(): Unsupported surface format"); + } + + // Perform clipping + // FIXME: We don't actually want to clip, as it may change line slope + if (!SDL_GetRectAndLineIntersection(&dst->clip_rect, &x1, &y1, &x2, &y2)) { + return true; + } + + func(dst, x1, y1, x2, y2, blendMode, r, g, b, a, true); + return true; +} + +bool SDL_BlendLines(SDL_Surface *dst, const SDL_Point *points, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + int i; + int x1, y1; + int x2, y2; + bool draw_end; + BlendLineFunc func; + + if (!SDL_SurfaceValid(dst)) { + return SDL_SetError("SDL_BlendLines(): Passed NULL destination surface"); + } + + func = SDL_CalculateBlendLineFunc(dst->fmt); + if (!func) { + return SDL_SetError("SDL_BlendLines(): Unsupported surface format"); + } + + for (i = 1; i < count; ++i) { + x1 = points[i - 1].x; + y1 = points[i - 1].y; + x2 = points[i].x; + y2 = points[i].y; + + // Perform clipping + // FIXME: We don't actually want to clip, as it may change line slope + if (!SDL_GetRectAndLineIntersection(&dst->clip_rect, &x1, &y1, &x2, &y2)) { + continue; + } + + // Draw the end if it was clipped + draw_end = (x2 != points[i].x || y2 != points[i].y); + + func(dst, x1, y1, x2, y2, blendMode, r, g, b, a, draw_end); + } + if (points[0].x != points[count - 1].x || points[0].y != points[count - 1].y) { + SDL_BlendPoint(dst, points[count - 1].x, points[count - 1].y, + blendMode, r, g, b, a); + } + return true; +} + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_blendline_h_ +#define SDL_blendline_h_ + +#include "SDL_internal.h" + +extern 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); +extern bool SDL_BlendLines(SDL_Surface *dst, const SDL_Point *points, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_RENDER_SW + +#include "SDL_draw.h" +#include "SDL_blendpoint.h" + +static bool SDL_BlendPoint_RGB555(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, + Uint8 g, Uint8 b, Uint8 a) +{ + unsigned inva = 0xff - a; + + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DRAW_SETPIXELXY_BLEND_RGB555(x, y); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + DRAW_SETPIXELXY_BLEND_CLAMPED_RGB555(x, y); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + DRAW_SETPIXELXY_ADD_RGB555(x, y); + break; + case SDL_BLENDMODE_MOD: + DRAW_SETPIXELXY_MOD_RGB555(x, y); + break; + case SDL_BLENDMODE_MUL: + DRAW_SETPIXELXY_MUL_RGB555(x, y); + break; + default: + DRAW_SETPIXELXY_RGB555(x, y); + break; + } + return true; +} + +static bool SDL_BlendPoint_RGB565(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, + Uint8 g, Uint8 b, Uint8 a) +{ + unsigned inva = 0xff - a; + + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DRAW_SETPIXELXY_BLEND_RGB565(x, y); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + DRAW_SETPIXELXY_BLEND_CLAMPED_RGB565(x, y); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + DRAW_SETPIXELXY_ADD_RGB565(x, y); + break; + case SDL_BLENDMODE_MOD: + DRAW_SETPIXELXY_MOD_RGB565(x, y); + break; + case SDL_BLENDMODE_MUL: + DRAW_SETPIXELXY_MUL_RGB565(x, y); + break; + default: + DRAW_SETPIXELXY_RGB565(x, y); + break; + } + return true; +} + +static bool SDL_BlendPoint_XRGB8888(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, + Uint8 g, Uint8 b, Uint8 a) +{ + unsigned inva = 0xff - a; + + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DRAW_SETPIXELXY_BLEND_XRGB8888(x, y); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + DRAW_SETPIXELXY_BLEND_CLAMPED_XRGB8888(x, y); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + DRAW_SETPIXELXY_ADD_XRGB8888(x, y); + break; + case SDL_BLENDMODE_MOD: + DRAW_SETPIXELXY_MOD_XRGB8888(x, y); + break; + case SDL_BLENDMODE_MUL: + DRAW_SETPIXELXY_MUL_XRGB8888(x, y); + break; + default: + DRAW_SETPIXELXY_XRGB8888(x, y); + break; + } + return true; +} + +static bool SDL_BlendPoint_ARGB8888(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, + Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + unsigned inva = 0xff - a; + + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DRAW_SETPIXELXY_BLEND_ARGB8888(x, y); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + DRAW_SETPIXELXY_BLEND_CLAMPED_ARGB8888(x, y); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + DRAW_SETPIXELXY_ADD_ARGB8888(x, y); + break; + case SDL_BLENDMODE_MOD: + DRAW_SETPIXELXY_MOD_ARGB8888(x, y); + break; + case SDL_BLENDMODE_MUL: + DRAW_SETPIXELXY_MUL_ARGB8888(x, y); + break; + default: + DRAW_SETPIXELXY_ARGB8888(x, y); + break; + } + return true; +} + +static bool SDL_BlendPoint_RGB(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, + Uint8 g, Uint8 b, Uint8 a) +{ + const SDL_PixelFormatDetails *fmt = dst->fmt; + unsigned inva = 0xff - a; + + switch (fmt->bytes_per_pixel) { + case 2: + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DRAW_SETPIXELXY2_BLEND_RGB(x, y); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + DRAW_SETPIXELXY2_BLEND_CLAMPED_RGB(x, y); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + DRAW_SETPIXELXY2_ADD_RGB(x, y); + break; + case SDL_BLENDMODE_MOD: + DRAW_SETPIXELXY2_MOD_RGB(x, y); + break; + case SDL_BLENDMODE_MUL: + DRAW_SETPIXELXY2_MUL_RGB(x, y); + break; + default: + DRAW_SETPIXELXY2_RGB(x, y); + break; + } + return true; + case 4: + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DRAW_SETPIXELXY4_BLEND_RGB(x, y); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + DRAW_SETPIXELXY4_BLEND_CLAMPED_RGB(x, y); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + DRAW_SETPIXELXY4_ADD_RGB(x, y); + break; + case SDL_BLENDMODE_MOD: + DRAW_SETPIXELXY4_MOD_RGB(x, y); + break; + case SDL_BLENDMODE_MUL: + DRAW_SETPIXELXY4_MUL_RGB(x, y); + break; + default: + DRAW_SETPIXELXY4_RGB(x, y); + break; + } + return true; + default: + return SDL_Unsupported(); + } +} + +static bool SDL_BlendPoint_RGBA(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, + Uint8 g, Uint8 b, Uint8 a) +{ + const SDL_PixelFormatDetails *fmt = dst->fmt; + unsigned inva = 0xff - a; + + switch (fmt->bytes_per_pixel) { + case 4: + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DRAW_SETPIXELXY4_BLEND_RGBA(x, y); + break; + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + DRAW_SETPIXELXY4_BLEND_CLAMPED_RGBA(x, y); + break; + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + DRAW_SETPIXELXY4_ADD_RGBA(x, y); + break; + case SDL_BLENDMODE_MOD: + DRAW_SETPIXELXY4_MOD_RGBA(x, y); + break; + case SDL_BLENDMODE_MUL: + DRAW_SETPIXELXY4_MUL_RGBA(x, y); + break; + default: + DRAW_SETPIXELXY4_RGBA(x, y); + break; + } + return true; + default: + return SDL_Unsupported(); + } +} + +bool SDL_BlendPoint(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + if (!SDL_SurfaceValid(dst)) { + return SDL_InvalidParamError("SDL_BlendPoint(): dst"); + } + + // This function doesn't work on surfaces < 8 bpp + if (SDL_BITSPERPIXEL(dst->format) < 8) { + return SDL_SetError("SDL_BlendPoint(): Unsupported surface format"); + } + + // Perform clipping + if (x < dst->clip_rect.x || y < dst->clip_rect.y || + x >= (dst->clip_rect.x + dst->clip_rect.w) || + y >= (dst->clip_rect.y + dst->clip_rect.h)) { + return true; + } + + if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) { + r = DRAW_MUL(r, a); + g = DRAW_MUL(g, a); + b = DRAW_MUL(b, a); + } + + switch (dst->fmt->bits_per_pixel) { + case 15: + switch (dst->fmt->Rmask) { + case 0x7C00: + return SDL_BlendPoint_RGB555(dst, x, y, blendMode, r, g, b, a); + } + break; + case 16: + switch (dst->fmt->Rmask) { + case 0xF800: + return SDL_BlendPoint_RGB565(dst, x, y, blendMode, r, g, b, a); + } + break; + case 32: + switch (dst->fmt->Rmask) { + case 0x00FF0000: + if (!dst->fmt->Amask) { + return SDL_BlendPoint_XRGB8888(dst, x, y, blendMode, r, g, b, a); + } else { + return SDL_BlendPoint_ARGB8888(dst, x, y, blendMode, r, g, b, a); + } + // break; -Wunreachable-code-break + } + break; + default: + break; + } + + if (!dst->fmt->Amask) { + return SDL_BlendPoint_RGB(dst, x, y, blendMode, r, g, b, a); + } else { + return SDL_BlendPoint_RGBA(dst, x, y, blendMode, r, g, b, a); + } +} + +bool SDL_BlendPoints(SDL_Surface *dst, const SDL_Point *points, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + int minx, miny; + int maxx, maxy; + int i; + int x, y; + bool (*func)(SDL_Surface * dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) = NULL; + bool result = true; + + if (!SDL_SurfaceValid(dst)) { + return SDL_InvalidParamError("SDL_BlendPoints(): dst"); + } + + // This function doesn't work on surfaces < 8 bpp + if (dst->fmt->bits_per_pixel < 8) { + return SDL_SetError("SDL_BlendPoints(): Unsupported surface format"); + } + + if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) { + r = DRAW_MUL(r, a); + g = DRAW_MUL(g, a); + b = DRAW_MUL(b, a); + } + + // FIXME: Does this function pointer slow things down significantly? + switch (dst->fmt->bits_per_pixel) { + case 15: + switch (dst->fmt->Rmask) { + case 0x7C00: + func = SDL_BlendPoint_RGB555; + break; + } + break; + case 16: + switch (dst->fmt->Rmask) { + case 0xF800: + func = SDL_BlendPoint_RGB565; + break; + } + break; + case 32: + switch (dst->fmt->Rmask) { + case 0x00FF0000: + if (!dst->fmt->Amask) { + func = SDL_BlendPoint_XRGB8888; + } else { + func = SDL_BlendPoint_ARGB8888; + } + break; + } + break; + default: + break; + } + + if (!func) { + if (!dst->fmt->Amask) { + func = SDL_BlendPoint_RGB; + } else { + func = SDL_BlendPoint_RGBA; + } + } + + minx = dst->clip_rect.x; + maxx = dst->clip_rect.x + dst->clip_rect.w - 1; + miny = dst->clip_rect.y; + maxy = dst->clip_rect.y + dst->clip_rect.h - 1; + + for (i = 0; i < count; ++i) { + x = points[i].x; + y = points[i].y; + + if (x < minx || x > maxx || y < miny || y > maxy) { + continue; + } + result = func(dst, x, y, blendMode, r, g, b, a); + } + return result; +} + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_blendpoint_h_ +#define SDL_blendpoint_h_ + +#include "SDL_internal.h" + +extern bool SDL_BlendPoint(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a); +extern bool SDL_BlendPoints(SDL_Surface *dst, const SDL_Point *points, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#include "../../video/SDL_surface_c.h" + +/* This code assumes that r, g, b, a are the source color, + * and in the blend and add case, the RGB values are premultiplied by a. + */ + +#define DRAW_MUL(_a, _b) (((unsigned)(_a) * (_b)) / 255) + +#define DRAW_FASTSETPIXEL(type) \ + *pixel = (type)color + +#define DRAW_FASTSETPIXEL1 DRAW_FASTSETPIXEL(Uint8) +#define DRAW_FASTSETPIXEL2 DRAW_FASTSETPIXEL(Uint16) +#define DRAW_FASTSETPIXEL4 DRAW_FASTSETPIXEL(Uint32) + +#define DRAW_FASTSETPIXELXY(x, y, type, bpp, color) \ + *(type *)((Uint8 *)dst->pixels + (y)*dst->pitch + (x)*bpp) = (type)color + +#define DRAW_FASTSETPIXELXY1(x, y) DRAW_FASTSETPIXELXY(x, y, Uint8, 1, color) +#define DRAW_FASTSETPIXELXY2(x, y) DRAW_FASTSETPIXELXY(x, y, Uint16, 2, color) +#define DRAW_FASTSETPIXELXY4(x, y) DRAW_FASTSETPIXELXY(x, y, Uint32, 4, color) + +#define DRAW_SETPIXEL(setpixel) \ + do { \ + unsigned sr = r, sg = g, sb = b, sa = a; \ + (void)sa; \ + setpixel; \ + } while (0) + +#define DRAW_SETPIXEL_BLEND(getpixel, setpixel) \ + do { \ + unsigned sr, sg, sb, sa = 0xFF; \ + getpixel; \ + sr = DRAW_MUL(inva, sr) + r; \ + sg = DRAW_MUL(inva, sg) + g; \ + sb = DRAW_MUL(inva, sb) + b; \ + sa = DRAW_MUL(inva, sa) + a; \ + setpixel; \ + } while (0) + +#define DRAW_SETPIXEL_BLEND_CLAMPED(getpixel, setpixel) \ + do { \ + unsigned sr, sg, sb, sa = 0xFF; \ + getpixel; \ + sr = DRAW_MUL(inva, sr) + r; \ + if (sr > 0xff) \ + sr = 0xff; \ + sg = DRAW_MUL(inva, sg) + g; \ + if (sg > 0xff) \ + sg = 0xff; \ + sb = DRAW_MUL(inva, sb) + b; \ + if (sb > 0xff) \ + sb = 0xff; \ + sa = DRAW_MUL(inva, sa) + a; \ + if (sa > 0xff) \ + sa = 0xff; \ + setpixel; \ + } while (0) + +#define DRAW_SETPIXEL_ADD(getpixel, setpixel) \ + do { \ + unsigned sr, sg, sb, sa; \ + (void)sa; \ + getpixel; \ + sr += r; \ + if (sr > 0xff) \ + sr = 0xff; \ + sg += g; \ + if (sg > 0xff) \ + sg = 0xff; \ + sb += b; \ + if (sb > 0xff) \ + sb = 0xff; \ + setpixel; \ + } while (0) + +#define DRAW_SETPIXEL_MOD(getpixel, setpixel) \ + do { \ + unsigned sr, sg, sb, sa; \ + (void)sa; \ + getpixel; \ + sr = DRAW_MUL(sr, r); \ + sg = DRAW_MUL(sg, g); \ + sb = DRAW_MUL(sb, b); \ + setpixel; \ + } while (0) + +#define DRAW_SETPIXEL_MUL(getpixel, setpixel) \ + do { \ + unsigned sr, sg, sb, sa; \ + (void)sa; \ + getpixel; \ + sr = DRAW_MUL(sr, r) + DRAW_MUL(inva, sr); \ + if (sr > 0xff) \ + sr = 0xff; \ + sg = DRAW_MUL(sg, g) + DRAW_MUL(inva, sg); \ + if (sg > 0xff) \ + sg = 0xff; \ + sb = DRAW_MUL(sb, b) + DRAW_MUL(inva, sb); \ + if (sb > 0xff) \ + sb = 0xff; \ + setpixel; \ + } while (0) + +#define DRAW_SETPIXELXY(x, y, type, bpp, op) \ + do { \ + type *pixel = (type *)((Uint8 *)dst->pixels + (y)*dst->pitch + (x)*bpp); \ + op; \ + } while (0) + +/* + * Define draw operators for RGB555 + */ + +#define DRAW_SETPIXEL_RGB555 \ + DRAW_SETPIXEL(RGB555_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_BLEND_RGB555 \ + DRAW_SETPIXEL_BLEND(RGB_FROM_RGB555(*pixel, sr, sg, sb), \ + RGB555_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_BLEND_CLAMPED_RGB555 \ + DRAW_SETPIXEL_BLEND_CLAMPED(RGB_FROM_RGB555(*pixel, sr, sg, sb), \ + RGB555_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_ADD_RGB555 \ + DRAW_SETPIXEL_ADD(RGB_FROM_RGB555(*pixel, sr, sg, sb), \ + RGB555_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_MOD_RGB555 \ + DRAW_SETPIXEL_MOD(RGB_FROM_RGB555(*pixel, sr, sg, sb), \ + RGB555_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_MUL_RGB555 \ + DRAW_SETPIXEL_MUL(RGB_FROM_RGB555(*pixel, sr, sg, sb), \ + RGB555_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXELXY_RGB555(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_RGB555) + +#define DRAW_SETPIXELXY_BLEND_RGB555(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_RGB555) + +#define DRAW_SETPIXELXY_BLEND_CLAMPED_RGB555(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_CLAMPED_RGB555) + +#define DRAW_SETPIXELXY_ADD_RGB555(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_ADD_RGB555) + +#define DRAW_SETPIXELXY_MOD_RGB555(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MOD_RGB555) + +#define DRAW_SETPIXELXY_MUL_RGB555(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MUL_RGB555) + +/* + * Define draw operators for RGB565 + */ + +#define DRAW_SETPIXEL_RGB565 \ + DRAW_SETPIXEL(RGB565_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_BLEND_RGB565 \ + DRAW_SETPIXEL_BLEND(RGB_FROM_RGB565(*pixel, sr, sg, sb), \ + RGB565_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_BLEND_CLAMPED_RGB565 \ + DRAW_SETPIXEL_BLEND_CLAMPED(RGB_FROM_RGB565(*pixel, sr, sg, sb), \ + RGB565_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_ADD_RGB565 \ + DRAW_SETPIXEL_ADD(RGB_FROM_RGB565(*pixel, sr, sg, sb), \ + RGB565_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_MOD_RGB565 \ + DRAW_SETPIXEL_MOD(RGB_FROM_RGB565(*pixel, sr, sg, sb), \ + RGB565_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_MUL_RGB565 \ + DRAW_SETPIXEL_MUL(RGB_FROM_RGB565(*pixel, sr, sg, sb), \ + RGB565_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXELXY_RGB565(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_RGB565) + +#define DRAW_SETPIXELXY_BLEND_RGB565(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_RGB565) + +#define DRAW_SETPIXELXY_BLEND_CLAMPED_RGB565(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_CLAMPED_RGB565) + +#define DRAW_SETPIXELXY_ADD_RGB565(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_ADD_RGB565) + +#define DRAW_SETPIXELXY_MOD_RGB565(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MOD_RGB565) + +#define DRAW_SETPIXELXY_MUL_RGB565(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MUL_RGB565) + +/* + * Define draw operators for RGB888 + */ + +#define DRAW_SETPIXEL_XRGB8888 \ + DRAW_SETPIXEL(XRGB8888_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_BLEND_XRGB8888 \ + DRAW_SETPIXEL_BLEND(RGB_FROM_XRGB8888(*pixel, sr, sg, sb), \ + XRGB8888_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888 \ + DRAW_SETPIXEL_BLEND_CLAMPED(RGB_FROM_XRGB8888(*pixel, sr, sg, sb), \ + XRGB8888_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_ADD_XRGB8888 \ + DRAW_SETPIXEL_ADD(RGB_FROM_XRGB8888(*pixel, sr, sg, sb), \ + XRGB8888_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_MOD_XRGB8888 \ + DRAW_SETPIXEL_MOD(RGB_FROM_XRGB8888(*pixel, sr, sg, sb), \ + XRGB8888_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_MUL_XRGB8888 \ + DRAW_SETPIXEL_MUL(RGB_FROM_XRGB8888(*pixel, sr, sg, sb), \ + XRGB8888_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXELXY_XRGB8888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_XRGB8888) + +#define DRAW_SETPIXELXY_BLEND_XRGB8888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_XRGB8888) + +#define DRAW_SETPIXELXY_BLEND_CLAMPED_XRGB8888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888) + +#define DRAW_SETPIXELXY_ADD_XRGB8888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_ADD_XRGB8888) + +#define DRAW_SETPIXELXY_MOD_XRGB8888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MOD_XRGB8888) + +#define DRAW_SETPIXELXY_MUL_XRGB8888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MUL_XRGB8888) + +/* + * Define draw operators for ARGB8888 + */ + +#define DRAW_SETPIXEL_ARGB8888 \ + DRAW_SETPIXEL(ARGB8888_FROM_RGBA(*pixel, sr, sg, sb, sa)) + +#define DRAW_SETPIXEL_BLEND_ARGB8888 \ + DRAW_SETPIXEL_BLEND(RGBA_FROM_ARGB8888(*pixel, sr, sg, sb, sa), \ + ARGB8888_FROM_RGBA(*pixel, sr, sg, sb, sa)) + +#define DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888 \ + DRAW_SETPIXEL_BLEND_CLAMPED(RGBA_FROM_ARGB8888(*pixel, sr, sg, sb, sa), \ + ARGB8888_FROM_RGBA(*pixel, sr, sg, sb, sa)) + +#define DRAW_SETPIXEL_ADD_ARGB8888 \ + DRAW_SETPIXEL_ADD(RGBA_FROM_ARGB8888(*pixel, sr, sg, sb, sa), \ + ARGB8888_FROM_RGBA(*pixel, sr, sg, sb, sa)) + +#define DRAW_SETPIXEL_MOD_ARGB8888 \ + DRAW_SETPIXEL_MOD(RGBA_FROM_ARGB8888(*pixel, sr, sg, sb, sa), \ + ARGB8888_FROM_RGBA(*pixel, sr, sg, sb, sa)) + +#define DRAW_SETPIXEL_MUL_ARGB8888 \ + DRAW_SETPIXEL_MUL(RGBA_FROM_ARGB8888(*pixel, sr, sg, sb, sa), \ + ARGB8888_FROM_RGBA(*pixel, sr, sg, sb, sa)) + +#define DRAW_SETPIXELXY_ARGB8888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_ARGB8888) + +#define DRAW_SETPIXELXY_BLEND_ARGB8888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_ARGB8888) + +#define DRAW_SETPIXELXY_BLEND_CLAMPED_ARGB8888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888) + +#define DRAW_SETPIXELXY_ADD_ARGB8888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_ADD_ARGB8888) + +#define DRAW_SETPIXELXY_MOD_ARGB8888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MOD_ARGB8888) + +#define DRAW_SETPIXELXY_MUL_ARGB8888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MUL_ARGB8888) + +/* + * Define draw operators for general RGB + */ + +#define DRAW_SETPIXEL_RGB \ + DRAW_SETPIXEL(PIXEL_FROM_RGB(*pixel, fmt, sr, sg, sb)) + +#define DRAW_SETPIXEL_BLEND_RGB \ + DRAW_SETPIXEL_BLEND(RGB_FROM_PIXEL(*pixel, fmt, sr, sg, sb), \ + PIXEL_FROM_RGB(*pixel, fmt, sr, sg, sb)) + +#define DRAW_SETPIXEL_BLEND_CLAMPED_RGB \ + DRAW_SETPIXEL_BLEND_CLAMPED(RGB_FROM_PIXEL(*pixel, fmt, sr, sg, sb), \ + PIXEL_FROM_RGB(*pixel, fmt, sr, sg, sb)) + +#define DRAW_SETPIXEL_ADD_RGB \ + DRAW_SETPIXEL_ADD(RGB_FROM_PIXEL(*pixel, fmt, sr, sg, sb), \ + PIXEL_FROM_RGB(*pixel, fmt, sr, sg, sb)) + +#define DRAW_SETPIXEL_MOD_RGB \ + DRAW_SETPIXEL_MOD(RGB_FROM_PIXEL(*pixel, fmt, sr, sg, sb), \ + PIXEL_FROM_RGB(*pixel, fmt, sr, sg, sb)) + +#define DRAW_SETPIXEL_MUL_RGB \ + DRAW_SETPIXEL_MUL(RGB_FROM_PIXEL(*pixel, fmt, sr, sg, sb), \ + PIXEL_FROM_RGB(*pixel, fmt, sr, sg, sb)) + +#define DRAW_SETPIXELXY2_RGB(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_RGB) + +#define DRAW_SETPIXELXY4_RGB(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_RGB) + +#define DRAW_SETPIXELXY2_BLEND_RGB(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_RGB) + +#define DRAW_SETPIXELXY2_BLEND_CLAMPED_RGB(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_CLAMPED_RGB) + +#define DRAW_SETPIXELXY4_BLEND_RGB(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_RGB) + +#define DRAW_SETPIXELXY4_BLEND_CLAMPED_RGB(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_CLAMPED_RGB) + +#define DRAW_SETPIXELXY2_ADD_RGB(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_ADD_RGB) + +#define DRAW_SETPIXELXY4_ADD_RGB(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_ADD_RGB) + +#define DRAW_SETPIXELXY2_MOD_RGB(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MOD_RGB) + +#define DRAW_SETPIXELXY4_MOD_RGB(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MOD_RGB) + +#define DRAW_SETPIXELXY2_MUL_RGB(x, y) \ + DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MUL_RGB) + +#define DRAW_SETPIXELXY4_MUL_RGB(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MUL_RGB) + +/* + * Define draw operators for general RGBA + */ + +#define DRAW_SETPIXEL_RGBA \ + DRAW_SETPIXEL(PIXEL_FROM_RGBA(*pixel, fmt, sr, sg, sb, sa)) + +#define DRAW_SETPIXEL_BLEND_RGBA \ + DRAW_SETPIXEL_BLEND(RGBA_FROM_PIXEL(*pixel, fmt, sr, sg, sb, sa), \ + PIXEL_FROM_RGBA(*pixel, fmt, sr, sg, sb, sa)) + +#define DRAW_SETPIXEL_BLEND_CLAMPED_RGBA \ + DRAW_SETPIXEL_BLEND_CLAMPED(RGBA_FROM_PIXEL(*pixel, fmt, sr, sg, sb, sa), \ + PIXEL_FROM_RGBA(*pixel, fmt, sr, sg, sb, sa)) + +#define DRAW_SETPIXEL_ADD_RGBA \ + DRAW_SETPIXEL_ADD(RGBA_FROM_PIXEL(*pixel, fmt, sr, sg, sb, sa), \ + PIXEL_FROM_RGBA(*pixel, fmt, sr, sg, sb, sa)) + +#define DRAW_SETPIXEL_MOD_RGBA \ + DRAW_SETPIXEL_MOD(RGBA_FROM_PIXEL(*pixel, fmt, sr, sg, sb, sa), \ + PIXEL_FROM_RGBA(*pixel, fmt, sr, sg, sb, sa)) + +#define DRAW_SETPIXEL_MUL_RGBA \ + DRAW_SETPIXEL_MUL(RGBA_FROM_PIXEL(*pixel, fmt, sr, sg, sb, sa), \ + PIXEL_FROM_RGBA(*pixel, fmt, sr, sg, sb, sa)) + +#define DRAW_SETPIXELXY4_RGBA(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_RGBA) + +#define DRAW_SETPIXELXY4_BLEND_RGBA(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_RGBA) + +#define DRAW_SETPIXELXY4_BLEND_CLAMPED_RGBA(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_CLAMPED_RGBA) + +#define DRAW_SETPIXELXY4_ADD_RGBA(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_ADD_RGBA) + +#define DRAW_SETPIXELXY4_MOD_RGBA(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MOD_RGBA) + +#define DRAW_SETPIXELXY4_MUL_RGBA(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MUL_RGBA) + +/* + * Define line drawing macro + */ + +#define ABS(_x) ((_x) < 0 ? -(_x) : (_x)) + +// Horizontal line +#define HLINE(type, op, draw_end) \ + { \ + int length; \ + int pitch = (dst->pitch / dst->fmt->bytes_per_pixel); \ + type *pixel; \ + if (x1 <= x2) { \ + pixel = (type *)dst->pixels + y1 * pitch + x1; \ + length = draw_end ? (x2 - x1 + 1) : (x2 - x1); \ + } else { \ + pixel = (type *)dst->pixels + y1 * pitch + x2; \ + if (!draw_end) { \ + ++pixel; \ + } \ + length = draw_end ? (x1 - x2 + 1) : (x1 - x2); \ + } \ + while (length--) { \ + op; \ + ++pixel; \ + } \ + } + +// Vertical line +#define VLINE(type, op, draw_end) \ + { \ + int length; \ + int pitch = (dst->pitch / dst->fmt->bytes_per_pixel); \ + type *pixel; \ + if (y1 <= y2) { \ + pixel = (type *)dst->pixels + y1 * pitch + x1; \ + length = draw_end ? (y2 - y1 + 1) : (y2 - y1); \ + } else { \ + pixel = (type *)dst->pixels + y2 * pitch + x1; \ + if (!draw_end) { \ + pixel += pitch; \ + } \ + length = draw_end ? (y1 - y2 + 1) : (y1 - y2); \ + } \ + while (length--) { \ + op; \ + pixel += pitch; \ + } \ + } + +// Diagonal line +#define DLINE(type, op, draw_end) \ + { \ + int length; \ + int pitch = (dst->pitch / dst->fmt->bytes_per_pixel); \ + type *pixel; \ + if (y1 <= y2) { \ + pixel = (type *)dst->pixels + y1 * pitch + x1; \ + if (x1 <= x2) { \ + ++pitch; \ + } else { \ + --pitch; \ + } \ + length = (y2 - y1); \ + } else { \ + pixel = (type *)dst->pixels + y2 * pitch + x2; \ + if (x2 <= x1) { \ + ++pitch; \ + } else { \ + --pitch; \ + } \ + if (!draw_end) { \ + pixel += pitch; \ + } \ + length = (y1 - y2); \ + } \ + if (draw_end) { \ + ++length; \ + } \ + while (length--) { \ + op; \ + pixel += pitch; \ + } \ + } + +// Bresenham's line algorithm +#define BLINE(x1, y1, x2, y2, op, draw_end) \ + { \ + int i, deltax, deltay, numpixels; \ + int d, dinc1, dinc2; \ + int x, xinc1, xinc2; \ + int y, yinc1, yinc2; \ + \ + deltax = ABS(x2 - x1); \ + deltay = ABS(y2 - y1); \ + \ + if (deltax >= deltay) { \ + numpixels = deltax + 1; \ + d = (2 * deltay) - deltax; \ + dinc1 = deltay * 2; \ + dinc2 = (deltay - deltax) * 2; \ + xinc1 = 1; \ + xinc2 = 1; \ + yinc1 = 0; \ + yinc2 = 1; \ + } else { \ + numpixels = deltay + 1; \ + d = (2 * deltax) - deltay; \ + dinc1 = deltax * 2; \ + dinc2 = (deltax - deltay) * 2; \ + xinc1 = 0; \ + xinc2 = 1; \ + yinc1 = 1; \ + yinc2 = 1; \ + } \ + \ + if (x1 > x2) { \ + xinc1 = -xinc1; \ + xinc2 = -xinc2; \ + } \ + if (y1 > y2) { \ + yinc1 = -yinc1; \ + yinc2 = -yinc2; \ + } \ + \ + x = x1; \ + y = y1; \ + \ + if (!draw_end) { \ + --numpixels; \ + } \ + for (i = 0; i < numpixels; ++i) { \ + op(x, y); \ + if (d < 0) { \ + d += dinc1; \ + x += xinc1; \ + y += yinc1; \ + } else { \ + d += dinc2; \ + x += xinc2; \ + y += yinc2; \ + } \ + } \ + } + +// Xiaolin Wu's line algorithm, based on Michael Abrash's implementation +#define WULINE(x1, y1, x2, y2, opaque_op, blend_op, draw_end) \ + { \ + Uint16 ErrorAdj, ErrorAcc; \ + Uint16 ErrorAccTemp, Weighting; \ + int DeltaX, DeltaY, Temp, XDir; \ + unsigned r, g, b, a, inva; \ + \ + /* Draw the initial pixel, which is always exactly intersected by \ + the line and so needs no weighting */ \ + opaque_op(x1, y1); \ + \ + /* Draw the final pixel, which is always exactly intersected by the line \ + and so needs no weighting */ \ + if (draw_end) { \ + opaque_op(x2, y2); \ + } \ + \ + /* Make sure the line runs top to bottom */ \ + if (y1 > y2) { \ + Temp = y1; \ + y1 = y2; \ + y2 = Temp; \ + Temp = x1; \ + x1 = x2; \ + x2 = Temp; \ + } \ + DeltaY = y2 - y1; \ + \ + if ((DeltaX = x2 - x1) >= 0) { \ + XDir = 1; \ + } else { \ + XDir = -1; \ + DeltaX = -DeltaX; /* make DeltaX positive */ \ + } \ + \ + /* line is not horizontal, diagonal, or vertical */ \ + ErrorAcc = 0; /* initialize the line error accumulator to 0 */ \ + \ + /* Is this an X-major or Y-major line? */ \ + if (DeltaY > DeltaX) { \ + /* Y-major line; calculate 16-bit fixed-point fractional part of a \ + pixel that X advances each time Y advances 1 pixel, truncating the \ + result so that we won't overrun the endpoint along the X axis */ \ + ErrorAdj = ((unsigned long)DeltaX << 16) / (unsigned long)DeltaY; \ + /* Draw all pixels other than the first and last */ \ + while (--DeltaY) { \ + ErrorAccTemp = ErrorAcc; /* remember current accumulated error */ \ + ErrorAcc += ErrorAdj; /* calculate error for next pixel */ \ + if (ErrorAcc <= ErrorAccTemp) { \ + /* The error accumulator turned over, so advance the X coord */ \ + x1 += XDir; \ + } \ + y1++; /* Y-major, so always advance Y */ \ + /* The IntensityBits most significant bits of ErrorAcc give us the \ + intensity weighting for this pixel, and the complement of the \ + weighting for the paired pixel */ \ + Weighting = ErrorAcc >> 8; \ + { \ + a = DRAW_MUL(_a, (Weighting ^ 255)); \ + r = DRAW_MUL(_r, a); \ + g = DRAW_MUL(_g, a); \ + b = DRAW_MUL(_b, a); \ + inva = (a ^ 0xFF); \ + blend_op(x1, y1); \ + } \ + { \ + a = DRAW_MUL(_a, Weighting); \ + r = DRAW_MUL(_r, a); \ + g = DRAW_MUL(_g, a); \ + b = DRAW_MUL(_b, a); \ + inva = (a ^ 0xFF); \ + blend_op(x1 + XDir, y1); \ + } \ + } \ + } else { \ + /* X-major line; calculate 16-bit fixed-point fractional part of a \ + pixel that Y advances each time X advances 1 pixel, truncating the \ + result to avoid overrunning the endpoint along the X axis */ \ + ErrorAdj = ((unsigned long)DeltaY << 16) / (unsigned long)DeltaX; \ + /* Draw all pixels other than the first and last */ \ + while (--DeltaX) { \ + ErrorAccTemp = ErrorAcc; /* remember current accumulated error */ \ + ErrorAcc += ErrorAdj; /* calculate error for next pixel */ \ + if (ErrorAcc <= ErrorAccTemp) { \ + /* The error accumulator turned over, so advance the Y coord */ \ + y1++; \ + } \ + x1 += XDir; /* X-major, so always advance X */ \ + /* The IntensityBits most significant bits of ErrorAcc give us the \ + intensity weighting for this pixel, and the complement of the \ + weighting for the paired pixel */ \ + Weighting = ErrorAcc >> 8; \ + { \ + a = DRAW_MUL(_a, (Weighting ^ 255)); \ + r = DRAW_MUL(_r, a); \ + g = DRAW_MUL(_g, a); \ + b = DRAW_MUL(_b, a); \ + inva = (a ^ 0xFF); \ + blend_op(x1, y1); \ + } \ + { \ + a = DRAW_MUL(_a, Weighting); \ + r = DRAW_MUL(_r, a); \ + g = DRAW_MUL(_g, a); \ + b = DRAW_MUL(_b, a); \ + inva = (a ^ 0xFF); \ + blend_op(x1, y1 + 1); \ + } \ + } \ + } \ + } + +#ifdef AA_LINES +#define AALINE(x1, y1, x2, y2, opaque_op, blend_op, draw_end) \ + WULINE(x1, y1, x2, y2, opaque_op, blend_op, draw_end) +#else +#define AALINE(x1, y1, x2, y2, opaque_op, blend_op, draw_end) \ + BLINE(x1, y1, x2, y2, opaque_op, draw_end) +#endif + +/* + * Define fill rect macro + */ + +#define FILLRECT(type, op) \ + do { \ + int width = rect->w; \ + int height = rect->h; \ + int pitch = (dst->pitch / dst->fmt->bytes_per_pixel); \ + int skip = pitch - width; \ + type *pixel = (type *)dst->pixels + rect->y * pitch + rect->x; \ + while (height--) { \ + { \ + int n = (width + 3) / 4; \ + switch (width & 3) { \ + case 0: \ + do { \ + op; \ + pixel++; \ + SDL_FALLTHROUGH; \ + case 3: \ + op; \ + pixel++; \ + SDL_FALLTHROUGH; \ + case 2: \ + op; \ + pixel++; \ + SDL_FALLTHROUGH; \ + case 1: \ + op; \ + pixel++; \ + } while (--n > 0); \ + } \ + } \ + pixel += skip; \ + } \ + } 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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_RENDER_SW + +#include "SDL_draw.h" +#include "SDL_drawline.h" +#include "SDL_drawpoint.h" + +static void SDL_DrawLine1(SDL_Surface *dst, int x1, int y1, int x2, int y2, Uint32 color, + bool draw_end) +{ + if (y1 == y2) { + int length; + int pitch = (dst->pitch / dst->fmt->bytes_per_pixel); + Uint8 *pixel; + if (x1 <= x2) { + pixel = (Uint8 *)dst->pixels + y1 * pitch + x1; + length = draw_end ? (x2 - x1 + 1) : (x2 - x1); + } else { + pixel = (Uint8 *)dst->pixels + y1 * pitch + x2; + if (!draw_end) { + ++pixel; + } + length = draw_end ? (x1 - x2 + 1) : (x1 - x2); + } + SDL_memset(pixel, color, length); + } else if (x1 == x2) { + VLINE(Uint8, DRAW_FASTSETPIXEL1, draw_end); + } else if (ABS(x1 - x2) == ABS(y1 - y2)) { + DLINE(Uint8, DRAW_FASTSETPIXEL1, draw_end); + } else { + BLINE(x1, y1, x2, y2, DRAW_FASTSETPIXELXY1, draw_end); + } +} + +static void SDL_DrawLine2(SDL_Surface *dst, int x1, int y1, int x2, int y2, Uint32 color, + bool draw_end) +{ + if (y1 == y2) { + HLINE(Uint16, DRAW_FASTSETPIXEL2, draw_end); + } else if (x1 == x2) { + VLINE(Uint16, DRAW_FASTSETPIXEL2, draw_end); + } else if (ABS(x1 - x2) == ABS(y1 - y2)) { + DLINE(Uint16, DRAW_FASTSETPIXEL2, draw_end); + } else { + Uint8 _r, _g, _b, _a; + const SDL_PixelFormatDetails *fmt = dst->fmt; + SDL_GetRGBA(color, fmt, dst->palette, &_r, &_g, &_b, &_a); + if (fmt->Rmask == 0x7C00) { + AALINE(x1, y1, x2, y2, + DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY_BLEND_RGB555, + draw_end); + } else if (fmt->Rmask == 0xF800) { + AALINE(x1, y1, x2, y2, + DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY_BLEND_RGB565, + draw_end); + } else { + AALINE(x1, y1, x2, y2, + DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY2_BLEND_RGB, + draw_end); + } + } +} + +static void SDL_DrawLine4(SDL_Surface *dst, int x1, int y1, int x2, int y2, Uint32 color, + bool draw_end) +{ + if (y1 == y2) { + HLINE(Uint32, DRAW_FASTSETPIXEL4, draw_end); + } else if (x1 == x2) { + VLINE(Uint32, DRAW_FASTSETPIXEL4, draw_end); + } else if (ABS(x1 - x2) == ABS(y1 - y2)) { + DLINE(Uint32, DRAW_FASTSETPIXEL4, draw_end); + } else { + Uint8 _r, _g, _b, _a; + const SDL_PixelFormatDetails *fmt = dst->fmt; + SDL_GetRGBA(color, fmt, dst->palette, &_r, &_g, &_b, &_a); + if (fmt->Rmask == 0x00FF0000) { + if (!fmt->Amask) { + AALINE(x1, y1, x2, y2, + DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY_BLEND_XRGB8888, + draw_end); + } else { + AALINE(x1, y1, x2, y2, + DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY_BLEND_ARGB8888, + draw_end); + } + } else { + AALINE(x1, y1, x2, y2, + DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY4_BLEND_RGB, + draw_end); + } + } +} + +typedef void (*DrawLineFunc)(SDL_Surface *dst, + int x1, int y1, int x2, int y2, + Uint32 color, bool draw_end); + +static DrawLineFunc SDL_CalculateDrawLineFunc(const SDL_PixelFormatDetails *fmt) +{ + switch (fmt->bytes_per_pixel) { + case 1: + if (fmt->bits_per_pixel < 8) { + break; + } + return SDL_DrawLine1; + case 2: + return SDL_DrawLine2; + case 4: + return SDL_DrawLine4; + } + return NULL; +} + +bool SDL_DrawLine(SDL_Surface *dst, int x1, int y1, int x2, int y2, Uint32 color) +{ + DrawLineFunc func; + + if (!SDL_SurfaceValid(dst)) { + return SDL_InvalidParamError("SDL_DrawLine(): dst"); + } + + func = SDL_CalculateDrawLineFunc(dst->fmt); + if (!func) { + return SDL_SetError("SDL_DrawLine(): Unsupported surface format"); + } + + // Perform clipping + // FIXME: We don't actually want to clip, as it may change line slope + if (!SDL_GetRectAndLineIntersection(&dst->clip_rect, &x1, &y1, &x2, &y2)) { + return true; + } + + func(dst, x1, y1, x2, y2, color, true); + return true; +} + +bool SDL_DrawLines(SDL_Surface *dst, const SDL_Point *points, int count, Uint32 color) +{ + int i; + int x1, y1; + int x2, y2; + bool draw_end; + DrawLineFunc func; + + if (!SDL_SurfaceValid(dst)) { + return SDL_InvalidParamError("SDL_DrawLines(): dst"); + } + + func = SDL_CalculateDrawLineFunc(dst->fmt); + if (!func) { + return SDL_SetError("SDL_DrawLines(): Unsupported surface format"); + } + + for (i = 1; i < count; ++i) { + x1 = points[i - 1].x; + y1 = points[i - 1].y; + x2 = points[i].x; + y2 = points[i].y; + + // Perform clipping + // FIXME: We don't actually want to clip, as it may change line slope + if (!SDL_GetRectAndLineIntersection(&dst->clip_rect, &x1, &y1, &x2, &y2)) { + continue; + } + + // Draw the end if the whole line is a single point or it was clipped + draw_end = ((x1 == x2) && (y1 == y2)) || (x2 != points[i].x || y2 != points[i].y); + + func(dst, x1, y1, x2, y2, color, draw_end); + } + if (points[0].x != points[count - 1].x || points[0].y != points[count - 1].y) { + SDL_DrawPoint(dst, points[count - 1].x, points[count - 1].y, color); + } + return true; +} + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_drawline_h_ +#define SDL_drawline_h_ + +#include "SDL_internal.h" + +extern bool SDL_DrawLine(SDL_Surface *dst, int x1, int y1, int x2, int y2, Uint32 color); +extern bool SDL_DrawLines(SDL_Surface *dst, const SDL_Point *points, int count, Uint32 color); + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_RENDER_SW + +#include "SDL_draw.h" +#include "SDL_drawpoint.h" + +bool SDL_DrawPoint(SDL_Surface *dst, int x, int y, Uint32 color) +{ + if (!SDL_SurfaceValid(dst)) { + return SDL_InvalidParamError("SDL_DrawPoint(): dst"); + } + + // This function doesn't work on surfaces < 8 bpp + if (dst->fmt->bits_per_pixel < 8) { + return SDL_SetError("SDL_DrawPoint(): Unsupported surface format"); + } + + // Perform clipping + if (x < dst->clip_rect.x || y < dst->clip_rect.y || + x >= (dst->clip_rect.x + dst->clip_rect.w) || + y >= (dst->clip_rect.y + dst->clip_rect.h)) { + return true; + } + + switch (dst->fmt->bytes_per_pixel) { + case 1: + DRAW_FASTSETPIXELXY1(x, y); + break; + case 2: + DRAW_FASTSETPIXELXY2(x, y); + break; + case 3: + return SDL_Unsupported(); + case 4: + DRAW_FASTSETPIXELXY4(x, y); + break; + } + return true; +} + +bool SDL_DrawPoints(SDL_Surface *dst, const SDL_Point *points, int count, Uint32 color) +{ + int minx, miny; + int maxx, maxy; + int i; + int x, y; + + if (!SDL_SurfaceValid(dst)) { + return SDL_InvalidParamError("SDL_DrawPoints(): dst"); + } + + // This function doesn't work on surfaces < 8 bpp + if (dst->fmt->bits_per_pixel < 8) { + return SDL_SetError("SDL_DrawPoints(): Unsupported surface format"); + } + + minx = dst->clip_rect.x; + maxx = dst->clip_rect.x + dst->clip_rect.w - 1; + miny = dst->clip_rect.y; + maxy = dst->clip_rect.y + dst->clip_rect.h - 1; + + for (i = 0; i < count; ++i) { + x = points[i].x; + y = points[i].y; + + if (x < minx || x > maxx || y < miny || y > maxy) { + continue; + } + + switch (dst->fmt->bytes_per_pixel) { + case 1: + DRAW_FASTSETPIXELXY1(x, y); + break; + case 2: + DRAW_FASTSETPIXELXY2(x, y); + break; + case 3: + return SDL_Unsupported(); + case 4: + DRAW_FASTSETPIXELXY4(x, y); + break; + } + } + return true; +} + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_drawpoint_h_ +#define SDL_drawpoint_h_ + +#include "SDL_internal.h" + +extern bool SDL_DrawPoint(SDL_Surface *dst, int x, int y, Uint32 color); +extern bool SDL_DrawPoints(SDL_Surface *dst, const SDL_Point *points, int count, Uint32 color); + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_RENDER_SW + +#include "../SDL_sysrender.h" +#include "SDL_render_sw_c.h" + +#include "SDL_draw.h" +#include "SDL_blendfillrect.h" +#include "SDL_blendline.h" +#include "SDL_blendpoint.h" +#include "SDL_drawline.h" +#include "SDL_drawpoint.h" +#include "SDL_rotate.h" +#include "SDL_triangle.h" +#include "../../video/SDL_pixels_c.h" + +// SDL surface based renderer implementation + +typedef struct +{ + const SDL_Rect *viewport; + const SDL_Rect *cliprect; + bool surface_cliprect_dirty; + SDL_Color color; +} SW_DrawStateCache; + +typedef struct +{ + SDL_Surface *surface; + SDL_Surface *window; +} SW_RenderData; + +static SDL_Surface *SW_ActivateRenderer(SDL_Renderer *renderer) +{ + SW_RenderData *data = (SW_RenderData *)renderer->internal; + + if (!data->surface) { + data->surface = data->window; + } + if (!data->surface) { + SDL_Surface *surface = SDL_GetWindowSurface(renderer->window); + if (surface) { + data->surface = data->window = surface; + } + } + return data->surface; +} + +static void SW_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event) +{ + SW_RenderData *data = (SW_RenderData *)renderer->internal; + + if (event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) { + data->surface = NULL; + data->window = NULL; + } +} + +static bool SW_GetOutputSize(SDL_Renderer *renderer, int *w, int *h) +{ + SW_RenderData *data = (SW_RenderData *)renderer->internal; + + if (data->surface) { + if (w) { + *w = data->surface->w; + } + if (h) { + *h = data->surface->h; + } + return true; + } + + if (renderer->window) { + SDL_GetWindowSizeInPixels(renderer->window, w, h); + return true; + } + + return SDL_SetError("Software renderer doesn't have an output surface"); +} + +static bool SW_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) +{ + SDL_Surface *surface = SDL_CreateSurface(texture->w, texture->h, texture->format); + Uint8 r, g, b, a; + + if (!SDL_SurfaceValid(surface)) { + return SDL_SetError("Cannot create surface"); + } + texture->internal = surface; + r = (Uint8)SDL_roundf(SDL_clamp(texture->color.r, 0.0f, 1.0f) * 255.0f); + g = (Uint8)SDL_roundf(SDL_clamp(texture->color.g, 0.0f, 1.0f) * 255.0f); + b = (Uint8)SDL_roundf(SDL_clamp(texture->color.b, 0.0f, 1.0f) * 255.0f); + a = (Uint8)SDL_roundf(SDL_clamp(texture->color.a, 0.0f, 1.0f) * 255.0f); + SDL_SetSurfaceColorMod(surface, r, g, b); + SDL_SetSurfaceAlphaMod(surface, a); + SDL_SetSurfaceBlendMode(surface, texture->blendMode); + + /* Only RLE encode textures without an alpha channel since the RLE coder + * discards the color values of pixels with an alpha value of zero. + */ + if (texture->access == SDL_TEXTUREACCESS_STATIC && !SDL_ISPIXELFORMAT_ALPHA(surface->format)) { + SDL_SetSurfaceRLE(surface, 1); + } + + return true; +} + +static bool SW_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, const void *pixels, int pitch) +{ + SDL_Surface *surface = (SDL_Surface *)texture->internal; + Uint8 *src, *dst; + int row; + size_t length; + + if (SDL_MUSTLOCK(surface)) { + if (!SDL_LockSurface(surface)) { + return false; + } + } + src = (Uint8 *)pixels; + dst = (Uint8 *)surface->pixels + + rect->y * surface->pitch + + rect->x * surface->fmt->bytes_per_pixel; + length = (size_t)rect->w * surface->fmt->bytes_per_pixel; + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, src, length); + src += pitch; + dst += surface->pitch; + } + if (SDL_MUSTLOCK(surface)) { + SDL_UnlockSurface(surface); + } + return true; +} + +static bool SW_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, void **pixels, int *pitch) +{ + SDL_Surface *surface = (SDL_Surface *)texture->internal; + + *pixels = + (void *)((Uint8 *)surface->pixels + rect->y * surface->pitch + + rect->x * surface->fmt->bytes_per_pixel); + *pitch = surface->pitch; + return true; +} + +static void SW_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) +{ +} + +static void SW_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode) +{ +} + +static bool SW_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) +{ + SW_RenderData *data = (SW_RenderData *)renderer->internal; + + if (texture) { + data->surface = (SDL_Surface *)texture->internal; + } else { + data->surface = data->window; + } + return true; +} + +static bool SW_QueueNoOp(SDL_Renderer *renderer, SDL_RenderCommand *cmd) +{ + return true; // nothing to do in this backend. +} + +static bool SW_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) +{ + SDL_Point *verts = (SDL_Point *)SDL_AllocateRenderVertices(renderer, count * sizeof(SDL_Point), 0, &cmd->data.draw.first); + int i; + + if (!verts) { + return false; + } + + cmd->data.draw.count = count; + + for (i = 0; i < count; i++, verts++, points++) { + verts->x = (int)points->x; + verts->y = (int)points->y; + } + + return true; +} + +static bool SW_QueueFillRects(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FRect *rects, int count) +{ + SDL_Rect *verts = (SDL_Rect *)SDL_AllocateRenderVertices(renderer, count * sizeof(SDL_Rect), 0, &cmd->data.draw.first); + int i; + + if (!verts) { + return false; + } + + cmd->data.draw.count = count; + + for (i = 0; i < count; i++, verts++, rects++) { + verts->x = (int)rects->x; + verts->y = (int)rects->y; + verts->w = SDL_max((int)rects->w, 1); + verts->h = SDL_max((int)rects->h, 1); + } + + return true; +} + +static bool SW_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, + const SDL_FRect *srcrect, const SDL_FRect *dstrect) +{ + SDL_Rect *verts = (SDL_Rect *)SDL_AllocateRenderVertices(renderer, 2 * sizeof(SDL_Rect), 0, &cmd->data.draw.first); + + if (!verts) { + return false; + } + + cmd->data.draw.count = 1; + + verts->x = (int)srcrect->x; + verts->y = (int)srcrect->y; + verts->w = (int)srcrect->w; + verts->h = (int)srcrect->h; + verts++; + + verts->x = (int)dstrect->x; + verts->y = (int)dstrect->y; + verts->w = (int)dstrect->w; + verts->h = (int)dstrect->h; + + return true; +} + +typedef struct CopyExData +{ + SDL_Rect srcrect; + SDL_Rect dstrect; + double angle; + SDL_FPoint center; + SDL_FlipMode flip; + float scale_x; + float scale_y; +} CopyExData; + +static bool SW_QueueCopyEx(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, + const SDL_FRect *srcrect, const SDL_FRect *dstrect, + const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y) +{ + CopyExData *verts = (CopyExData *)SDL_AllocateRenderVertices(renderer, sizeof(CopyExData), 0, &cmd->data.draw.first); + + if (!verts) { + return false; + } + + cmd->data.draw.count = 1; + + verts->srcrect.x = (int)srcrect->x; + verts->srcrect.y = (int)srcrect->y; + verts->srcrect.w = (int)srcrect->w; + verts->srcrect.h = (int)srcrect->h; + verts->dstrect.x = (int)dstrect->x; + verts->dstrect.y = (int)dstrect->y; + verts->dstrect.w = (int)dstrect->w; + verts->dstrect.h = (int)dstrect->h; + verts->angle = angle; + SDL_copyp(&verts->center, center); + verts->flip = flip; + verts->scale_x = scale_x; + verts->scale_y = scale_y; + + return true; +} + +static bool Blit_to_Screen(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *surface, SDL_Rect *dstrect, + float scale_x, float scale_y, SDL_ScaleMode scaleMode) +{ + bool result; + // Renderer scaling, if needed + if (scale_x != 1.0f || scale_y != 1.0f) { + SDL_Rect r; + r.x = (int)((float)dstrect->x * scale_x); + r.y = (int)((float)dstrect->y * scale_y); + r.w = (int)((float)dstrect->w * scale_x); + r.h = (int)((float)dstrect->h * scale_y); + result = SDL_BlitSurfaceScaled(src, srcrect, surface, &r, scaleMode); + } else { + result = SDL_BlitSurface(src, srcrect, surface, dstrect); + } + return result; +} + +static bool SW_RenderCopyEx(SDL_Renderer *renderer, SDL_Surface *surface, SDL_Texture *texture, + const SDL_Rect *srcrect, const SDL_Rect *final_rect, + const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y) +{ + SDL_Surface *src = (SDL_Surface *)texture->internal; + SDL_Rect tmp_rect; + SDL_Surface *src_clone, *src_rotated, *src_scaled; + SDL_Surface *mask = NULL, *mask_rotated = NULL; + bool result = true; + SDL_BlendMode blendmode; + Uint8 alphaMod, rMod, gMod, bMod; + int applyModulation = false; + int blitRequired = false; + int isOpaque = false; + + if (!SDL_SurfaceValid(surface)) { + return false; + } + + tmp_rect.x = 0; + tmp_rect.y = 0; + tmp_rect.w = final_rect->w; + tmp_rect.h = final_rect->h; + + /* It is possible to encounter an RLE encoded surface here and locking it is + * necessary because this code is going to access the pixel buffer directly. + */ + if (SDL_MUSTLOCK(src)) { + if (!SDL_LockSurface(src)) { + return false; + } + } + + /* Clone the source surface but use its pixel buffer directly. + * The original source surface must be treated as read-only. + */ + src_clone = SDL_CreateSurfaceFrom(src->w, src->h, src->format, src->pixels, src->pitch); + if (!src_clone) { + if (SDL_MUSTLOCK(src)) { + SDL_UnlockSurface(src); + } + return false; + } + + SDL_GetSurfaceBlendMode(src, &blendmode); + SDL_GetSurfaceAlphaMod(src, &alphaMod); + SDL_GetSurfaceColorMod(src, &rMod, &gMod, &bMod); + + // SDLgfx_rotateSurface only accepts 32-bit surfaces with a 8888 layout. Everything else has to be converted. + if (src->fmt->bits_per_pixel != 32 || SDL_PIXELLAYOUT(src->format) != SDL_PACKEDLAYOUT_8888 || !SDL_ISPIXELFORMAT_ALPHA(src->format)) { + blitRequired = true; + } + + // If scaling and cropping is necessary, it has to be taken care of before the rotation. + if (!(srcrect->w == final_rect->w && srcrect->h == final_rect->h && srcrect->x == 0 && srcrect->y == 0)) { + blitRequired = true; + } + + // srcrect is not selecting the whole src surface, so cropping is needed + if (!(srcrect->w == src->w && srcrect->h == src->h && srcrect->x == 0 && srcrect->y == 0)) { + blitRequired = true; + } + + // The color and alpha modulation has to be applied before the rotation when using the NONE, MOD or MUL blend modes. + if ((blendmode == SDL_BLENDMODE_NONE || blendmode == SDL_BLENDMODE_MOD || blendmode == SDL_BLENDMODE_MUL) && (alphaMod & rMod & gMod & bMod) != 255) { + applyModulation = true; + SDL_SetSurfaceAlphaMod(src_clone, alphaMod); + SDL_SetSurfaceColorMod(src_clone, rMod, gMod, bMod); + } + + // Opaque surfaces are much easier to handle with the NONE blend mode. + if (blendmode == SDL_BLENDMODE_NONE && !SDL_ISPIXELFORMAT_ALPHA(src->format) && alphaMod == 255) { + isOpaque = true; + } + + /* The NONE blend mode requires a mask for non-opaque surfaces. This mask will be used + * to clear the pixels in the destination surface. The other steps are explained below. + */ + if (blendmode == SDL_BLENDMODE_NONE && !isOpaque) { + mask = SDL_CreateSurface(final_rect->w, final_rect->h, SDL_PIXELFORMAT_ARGB8888); + if (!mask) { + result = false; + } else { + SDL_SetSurfaceBlendMode(mask, SDL_BLENDMODE_MOD); + } + } + + /* Create a new surface should there be a format mismatch or if scaling, cropping, + * or modulation is required. It's possible to use the source surface directly otherwise. + */ + if (result && (blitRequired || applyModulation)) { + SDL_Rect scale_rect = tmp_rect; + src_scaled = SDL_CreateSurface(final_rect->w, final_rect->h, SDL_PIXELFORMAT_ARGB8888); + if (!src_scaled) { + result = false; + } else { + SDL_SetSurfaceBlendMode(src_clone, SDL_BLENDMODE_NONE); + result = SDL_BlitSurfaceScaled(src_clone, srcrect, src_scaled, &scale_rect, texture->scaleMode); + SDL_DestroySurface(src_clone); + src_clone = src_scaled; + src_scaled = NULL; + } + } + + // SDLgfx_rotateSurface is going to make decisions depending on the blend mode. + SDL_SetSurfaceBlendMode(src_clone, blendmode); + + if (result) { + SDL_Rect rect_dest; + double cangle, sangle; + + SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, angle, center, + &rect_dest, &cangle, &sangle); + src_rotated = SDLgfx_rotateSurface(src_clone, angle, + (texture->scaleMode == SDL_SCALEMODE_NEAREST) ? 0 : 1, flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, + &rect_dest, cangle, sangle, center); + if (!src_rotated) { + result = false; + } + if (result && mask) { + // The mask needed for the NONE blend mode gets rotated with the same parameters. + mask_rotated = SDLgfx_rotateSurface(mask, angle, + false, 0, 0, + &rect_dest, cangle, sangle, center); + if (!mask_rotated) { + result = false; + } + } + if (result) { + + tmp_rect.x = final_rect->x + rect_dest.x; + tmp_rect.y = final_rect->y + rect_dest.y; + tmp_rect.w = rect_dest.w; + tmp_rect.h = rect_dest.h; + + /* The NONE blend mode needs some special care with non-opaque surfaces. + * Other blend modes or opaque surfaces can be blitted directly. + */ + if (blendmode != SDL_BLENDMODE_NONE || isOpaque) { + if (applyModulation == false) { + // If the modulation wasn't already applied, make it happen now. + SDL_SetSurfaceAlphaMod(src_rotated, alphaMod); + SDL_SetSurfaceColorMod(src_rotated, rMod, gMod, bMod); + } + // Renderer scaling, if needed + result = Blit_to_Screen(src_rotated, NULL, surface, &tmp_rect, scale_x, scale_y, texture->scaleMode); + } else { + /* The NONE blend mode requires three steps to get the pixels onto the destination surface. + * First, the area where the rotated pixels will be blitted to get set to zero. + * This is accomplished by simply blitting a mask with the NONE blend mode. + * The colorkey set by the rotate function will discard the correct pixels. + */ + SDL_Rect mask_rect = tmp_rect; + SDL_SetSurfaceBlendMode(mask_rotated, SDL_BLENDMODE_NONE); + // Renderer scaling, if needed + result = Blit_to_Screen(mask_rotated, NULL, surface, &mask_rect, scale_x, scale_y, texture->scaleMode); + if (result) { + /* The next step copies the alpha value. This is done with the BLEND blend mode and + * by modulating the source colors with 0. Since the destination is all zeros, this + * will effectively set the destination alpha to the source alpha. + */ + SDL_SetSurfaceColorMod(src_rotated, 0, 0, 0); + mask_rect = tmp_rect; + // Renderer scaling, if needed + result = Blit_to_Screen(src_rotated, NULL, surface, &mask_rect, scale_x, scale_y, texture->scaleMode); + if (result) { + /* The last step gets the color values in place. The ADD blend mode simply adds them to + * the destination (where the color values are all zero). However, because the ADD blend + * mode modulates the colors with the alpha channel, a surface without an alpha mask needs + * to be created. This makes all source pixels opaque and the colors get copied correctly. + */ + SDL_Surface *src_rotated_rgb = SDL_CreateSurfaceFrom(src_rotated->w, src_rotated->h, src_rotated->format, src_rotated->pixels, src_rotated->pitch); + if (!src_rotated_rgb) { + result = false; + } else { + SDL_SetSurfaceBlendMode(src_rotated_rgb, SDL_BLENDMODE_ADD); + // Renderer scaling, if needed + result = Blit_to_Screen(src_rotated_rgb, NULL, surface, &tmp_rect, scale_x, scale_y, texture->scaleMode); + SDL_DestroySurface(src_rotated_rgb); + } + } + } + SDL_DestroySurface(mask_rotated); + } + if (src_rotated) { + SDL_DestroySurface(src_rotated); + } + } + } + + if (SDL_MUSTLOCK(src)) { + SDL_UnlockSurface(src); + } + if (mask) { + SDL_DestroySurface(mask); + } + if (src_clone) { + SDL_DestroySurface(src_clone); + } + return result; +} + +typedef struct GeometryFillData +{ + SDL_Point dst; + SDL_Color color; +} GeometryFillData; + +typedef struct GeometryCopyData +{ + SDL_Point src; + SDL_Point dst; + SDL_Color color; +} GeometryCopyData; + +static bool SW_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, + const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, + int num_vertices, const void *indices, int num_indices, int size_indices, + float scale_x, float scale_y) +{ + int i; + int count = indices ? num_indices : num_vertices; + void *verts; + size_t sz = texture ? sizeof(GeometryCopyData) : sizeof(GeometryFillData); + const float color_scale = cmd->data.draw.color_scale; + + verts = SDL_AllocateRenderVertices(renderer, count * sz, 0, &cmd->data.draw.first); + if (!verts) { + return false; + } + + cmd->data.draw.count = count; + size_indices = indices ? size_indices : 0; + + if (texture) { + GeometryCopyData *ptr = (GeometryCopyData *)verts; + for (i = 0; i < count; i++) { + int j; + float *xy_; + SDL_FColor col_; + float *uv_; + if (size_indices == 4) { + j = ((const Uint32 *)indices)[i]; + } else if (size_indices == 2) { + j = ((const Uint16 *)indices)[i]; + } else if (size_indices == 1) { + j = ((const Uint8 *)indices)[i]; + } else { + j = i; + } + + xy_ = (float *)((char *)xy + j * xy_stride); + col_ = *(SDL_FColor *)((char *)color + j * color_stride); + + uv_ = (float *)((char *)uv + j * uv_stride); + + ptr->src.x = (int)(uv_[0] * texture->w); + ptr->src.y = (int)(uv_[1] * texture->h); + + ptr->dst.x = (int)(xy_[0] * scale_x); + ptr->dst.y = (int)(xy_[1] * scale_y); + trianglepoint_2_fixedpoint(&ptr->dst); + + ptr->color.r = (Uint8)SDL_roundf(SDL_clamp(col_.r * color_scale, 0.0f, 1.0f) * 255.0f); + ptr->color.g = (Uint8)SDL_roundf(SDL_clamp(col_.g * color_scale, 0.0f, 1.0f) * 255.0f); + ptr->color.b = (Uint8)SDL_roundf(SDL_clamp(col_.b * color_scale, 0.0f, 1.0f) * 255.0f); + ptr->color.a = (Uint8)SDL_roundf(SDL_clamp(col_.a, 0.0f, 1.0f) * 255.0f); + + ptr++; + } + } else { + GeometryFillData *ptr = (GeometryFillData *)verts; + + for (i = 0; i < count; i++) { + int j; + float *xy_; + SDL_FColor col_; + if (size_indices == 4) { + j = ((const Uint32 *)indices)[i]; + } else if (size_indices == 2) { + j = ((const Uint16 *)indices)[i]; + } else if (size_indices == 1) { + j = ((const Uint8 *)indices)[i]; + } else { + j = i; + } + + xy_ = (float *)((char *)xy + j * xy_stride); + col_ = *(SDL_FColor *)((char *)color + j * color_stride); + + ptr->dst.x = (int)(xy_[0] * scale_x); + ptr->dst.y = (int)(xy_[1] * scale_y); + trianglepoint_2_fixedpoint(&ptr->dst); + + ptr->color.r = (Uint8)SDL_roundf(SDL_clamp(col_.r * color_scale, 0.0f, 1.0f) * 255.0f); + ptr->color.g = (Uint8)SDL_roundf(SDL_clamp(col_.g * color_scale, 0.0f, 1.0f) * 255.0f); + ptr->color.b = (Uint8)SDL_roundf(SDL_clamp(col_.b * color_scale, 0.0f, 1.0f) * 255.0f); + ptr->color.a = (Uint8)SDL_roundf(SDL_clamp(col_.a, 0.0f, 1.0f) * 255.0f); + + ptr++; + } + } + return true; +} + +static void PrepTextureForCopy(const SDL_RenderCommand *cmd, SW_DrawStateCache *drawstate) +{ + const Uint8 r = drawstate->color.r; + const Uint8 g = drawstate->color.g; + const Uint8 b = drawstate->color.b; + const Uint8 a = drawstate->color.a; + const SDL_BlendMode blend = cmd->data.draw.blend; + SDL_Texture *texture = cmd->data.draw.texture; + SDL_Surface *surface = (SDL_Surface *)texture->internal; + const bool colormod = ((r & g & b) != 0xFF); + const bool alphamod = (a != 0xFF); + const bool blending = ((blend == SDL_BLENDMODE_ADD) || (blend == SDL_BLENDMODE_MOD) || (blend == SDL_BLENDMODE_MUL)); + + if (colormod || alphamod || blending) { + SDL_SetSurfaceRLE(surface, 0); + } + + // !!! FIXME: we can probably avoid some of these calls. + SDL_SetSurfaceColorMod(surface, r, g, b); + SDL_SetSurfaceAlphaMod(surface, a); + SDL_SetSurfaceBlendMode(surface, blend); +} + +static void SetDrawState(SDL_Surface *surface, SW_DrawStateCache *drawstate) +{ + if (drawstate->surface_cliprect_dirty) { + const SDL_Rect *viewport = drawstate->viewport; + const SDL_Rect *cliprect = drawstate->cliprect; + SDL_assert_release(viewport != NULL); // the higher level should have forced a SDL_RENDERCMD_SETVIEWPORT + + if (cliprect && viewport) { + SDL_Rect clip_rect; + clip_rect.x = cliprect->x + viewport->x; + clip_rect.y = cliprect->y + viewport->y; + clip_rect.w = cliprect->w; + clip_rect.h = cliprect->h; + SDL_GetRectIntersection(viewport, &clip_rect, &clip_rect); + SDL_SetSurfaceClipRect(surface, &clip_rect); + } else { + SDL_SetSurfaceClipRect(surface, drawstate->viewport); + } + drawstate->surface_cliprect_dirty = false; + } +} + +static void SW_InvalidateCachedState(SDL_Renderer *renderer) +{ + // SW_DrawStateCache only lives during SW_RunCommandQueue, so nothing to do here! +} + + +static bool SW_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) +{ + SDL_Surface *surface = SW_ActivateRenderer(renderer); + SW_DrawStateCache drawstate; + + if (!SDL_SurfaceValid(surface)) { + return false; + } + + drawstate.viewport = NULL; + drawstate.cliprect = NULL; + drawstate.surface_cliprect_dirty = true; + drawstate.color.r = 0; + drawstate.color.g = 0; + drawstate.color.b = 0; + drawstate.color.a = 0; + + while (cmd) { + switch (cmd->command) { + case SDL_RENDERCMD_SETDRAWCOLOR: + { + drawstate.color.r = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.r * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); + drawstate.color.g = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.g * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); + drawstate.color.b = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.b * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); + drawstate.color.a = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.a, 0.0f, 1.0f) * 255.0f); + break; + } + + case SDL_RENDERCMD_SETVIEWPORT: + { + drawstate.viewport = &cmd->data.viewport.rect; + drawstate.surface_cliprect_dirty = true; + break; + } + + case SDL_RENDERCMD_SETCLIPRECT: + { + drawstate.cliprect = cmd->data.cliprect.enabled ? &cmd->data.cliprect.rect : NULL; + drawstate.surface_cliprect_dirty = true; + break; + } + + case SDL_RENDERCMD_CLEAR: + { + const Uint8 r = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.r * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); + const Uint8 g = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.g * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); + const Uint8 b = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.b * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); + const Uint8 a = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.a, 0.0f, 1.0f) * 255.0f); + // By definition the clear ignores the clip rect + SDL_SetSurfaceClipRect(surface, NULL); + SDL_FillSurfaceRect(surface, NULL, SDL_MapSurfaceRGBA(surface, r, g, b, a)); + drawstate.surface_cliprect_dirty = true; + break; + } + + case SDL_RENDERCMD_DRAW_POINTS: + { + const Uint8 r = drawstate.color.r; + const Uint8 g = drawstate.color.g; + const Uint8 b = drawstate.color.b; + const Uint8 a = drawstate.color.a; + const int count = (int)cmd->data.draw.count; + SDL_Point *verts = (SDL_Point *)(((Uint8 *)vertices) + cmd->data.draw.first); + const SDL_BlendMode blend = cmd->data.draw.blend; + SetDrawState(surface, &drawstate); + + // Apply viewport + if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) { + int i; + for (i = 0; i < count; i++) { + verts[i].x += drawstate.viewport->x; + verts[i].y += drawstate.viewport->y; + } + } + + if (blend == SDL_BLENDMODE_NONE) { + SDL_DrawPoints(surface, verts, count, SDL_MapSurfaceRGBA(surface, r, g, b, a)); + } else { + SDL_BlendPoints(surface, verts, count, blend, r, g, b, a); + } + break; + } + + case SDL_RENDERCMD_DRAW_LINES: + { + const Uint8 r = drawstate.color.r; + const Uint8 g = drawstate.color.g; + const Uint8 b = drawstate.color.b; + const Uint8 a = drawstate.color.a; + const int count = (int)cmd->data.draw.count; + SDL_Point *verts = (SDL_Point *)(((Uint8 *)vertices) + cmd->data.draw.first); + const SDL_BlendMode blend = cmd->data.draw.blend; + SetDrawState(surface, &drawstate); + + // Apply viewport + if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) { + int i; + for (i = 0; i < count; i++) { + verts[i].x += drawstate.viewport->x; + verts[i].y += drawstate.viewport->y; + } + } + + if (blend == SDL_BLENDMODE_NONE) { + SDL_DrawLines(surface, verts, count, SDL_MapSurfaceRGBA(surface, r, g, b, a)); + } else { + SDL_BlendLines(surface, verts, count, blend, r, g, b, a); + } + break; + } + + case SDL_RENDERCMD_FILL_RECTS: + { + const Uint8 r = drawstate.color.r; + const Uint8 g = drawstate.color.g; + const Uint8 b = drawstate.color.b; + const Uint8 a = drawstate.color.a; + const int count = (int)cmd->data.draw.count; + SDL_Rect *verts = (SDL_Rect *)(((Uint8 *)vertices) + cmd->data.draw.first); + const SDL_BlendMode blend = cmd->data.draw.blend; + SetDrawState(surface, &drawstate); + + // Apply viewport + if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) { + int i; + for (i = 0; i < count; i++) { + verts[i].x += drawstate.viewport->x; + verts[i].y += drawstate.viewport->y; + } + } + + if (blend == SDL_BLENDMODE_NONE) { + SDL_FillSurfaceRects(surface, verts, count, SDL_MapSurfaceRGBA(surface, r, g, b, a)); + } else { + SDL_BlendFillRects(surface, verts, count, blend, r, g, b, a); + } + break; + } + + case SDL_RENDERCMD_COPY: + { + SDL_Rect *verts = (SDL_Rect *)(((Uint8 *)vertices) + cmd->data.draw.first); + const SDL_Rect *srcrect = verts; + SDL_Rect *dstrect = verts + 1; + SDL_Texture *texture = cmd->data.draw.texture; + SDL_Surface *src = (SDL_Surface *)texture->internal; + + SetDrawState(surface, &drawstate); + + PrepTextureForCopy(cmd, &drawstate); + + // Apply viewport + if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) { + dstrect->x += drawstate.viewport->x; + dstrect->y += drawstate.viewport->y; + } + + if (srcrect->w == dstrect->w && srcrect->h == dstrect->h) { + SDL_BlitSurface(src, srcrect, surface, dstrect); + } else { + /* If scaling is ever done, permanently disable RLE (which doesn't support scaling) + * to avoid potentially frequent RLE encoding/decoding. + */ + SDL_SetSurfaceRLE(surface, 0); + + // Prevent to do scaling + clipping on viewport boundaries as it may lose proportion + if (dstrect->x < 0 || dstrect->y < 0 || dstrect->x + dstrect->w > surface->w || dstrect->y + dstrect->h > surface->h) { + SDL_Surface *tmp = SDL_CreateSurface(dstrect->w, dstrect->h, src->format); + // Scale to an intermediate surface, then blit + if (tmp) { + SDL_Rect r; + SDL_BlendMode blendmode; + Uint8 alphaMod, rMod, gMod, bMod; + + SDL_GetSurfaceBlendMode(src, &blendmode); + SDL_GetSurfaceAlphaMod(src, &alphaMod); + SDL_GetSurfaceColorMod(src, &rMod, &gMod, &bMod); + + r.x = 0; + r.y = 0; + r.w = dstrect->w; + r.h = dstrect->h; + + SDL_SetSurfaceBlendMode(src, SDL_BLENDMODE_NONE); + SDL_SetSurfaceColorMod(src, 255, 255, 255); + SDL_SetSurfaceAlphaMod(src, 255); + + SDL_BlitSurfaceScaled(src, srcrect, tmp, &r, texture->scaleMode); + + SDL_SetSurfaceColorMod(tmp, rMod, gMod, bMod); + SDL_SetSurfaceAlphaMod(tmp, alphaMod); + SDL_SetSurfaceBlendMode(tmp, blendmode); + + SDL_BlitSurface(tmp, NULL, surface, dstrect); + SDL_DestroySurface(tmp); + // No need to set back r/g/b/a/blendmode to 'src' since it's done in PrepTextureForCopy() + } + } else { + SDL_BlitSurfaceScaled(src, srcrect, surface, dstrect, texture->scaleMode); + } + } + break; + } + + case SDL_RENDERCMD_COPY_EX: + { + CopyExData *copydata = (CopyExData *)(((Uint8 *)vertices) + cmd->data.draw.first); + SetDrawState(surface, &drawstate); + PrepTextureForCopy(cmd, &drawstate); + + // Apply viewport + if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) { + copydata->dstrect.x += drawstate.viewport->x; + copydata->dstrect.y += drawstate.viewport->y; + } + + SW_RenderCopyEx(renderer, surface, cmd->data.draw.texture, ©data->srcrect, + ©data->dstrect, copydata->angle, ©data->center, copydata->flip, + copydata->scale_x, copydata->scale_y); + break; + } + + case SDL_RENDERCMD_GEOMETRY: + { + int i; + SDL_Rect *verts = (SDL_Rect *)(((Uint8 *)vertices) + cmd->data.draw.first); + const int count = (int)cmd->data.draw.count; + SDL_Texture *texture = cmd->data.draw.texture; + const SDL_BlendMode blend = cmd->data.draw.blend; + + SetDrawState(surface, &drawstate); + + if (texture) { + SDL_Surface *src = (SDL_Surface *)texture->internal; + + GeometryCopyData *ptr = (GeometryCopyData *)verts; + + PrepTextureForCopy(cmd, &drawstate); + + // Apply viewport + if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) { + SDL_Point vp; + vp.x = drawstate.viewport->x; + vp.y = drawstate.viewport->y; + trianglepoint_2_fixedpoint(&vp); + for (i = 0; i < count; i++) { + ptr[i].dst.x += vp.x; + ptr[i].dst.y += vp.y; + } + } + + for (i = 0; i < count; i += 3, ptr += 3) { + SDL_SW_BlitTriangle( + src, + &(ptr[0].src), &(ptr[1].src), &(ptr[2].src), + surface, + &(ptr[0].dst), &(ptr[1].dst), &(ptr[2].dst), + ptr[0].color, ptr[1].color, ptr[2].color, + cmd->data.draw.texture_address_mode); + } + } else { + GeometryFillData *ptr = (GeometryFillData *)verts; + + // Apply viewport + if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) { + SDL_Point vp; + vp.x = drawstate.viewport->x; + vp.y = drawstate.viewport->y; + trianglepoint_2_fixedpoint(&vp); + for (i = 0; i < count; i++) { + ptr[i].dst.x += vp.x; + ptr[i].dst.y += vp.y; + } + } + + for (i = 0; i < count; i += 3, ptr += 3) { + SDL_SW_FillTriangle(surface, &(ptr[0].dst), &(ptr[1].dst), &(ptr[2].dst), blend, ptr[0].color, ptr[1].color, ptr[2].color); + } + } + break; + } + + case SDL_RENDERCMD_NO_OP: + break; + } + + cmd = cmd->next; + } + + return true; +} + +static SDL_Surface *SW_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect) +{ + SDL_Surface *surface = SW_ActivateRenderer(renderer); + void *pixels; + + if (!SDL_SurfaceValid(surface)) { + return NULL; + } + + /* NOTE: The rect is already adjusted according to the viewport by + * SDL_RenderReadPixels. + */ + + if (rect->x < 0 || rect->x + rect->w > surface->w || + rect->y < 0 || rect->y + rect->h > surface->h) { + SDL_SetError("Tried to read outside of surface bounds"); + return NULL; + } + + pixels = (void *)((Uint8 *)surface->pixels + + rect->y * surface->pitch + + rect->x * surface->fmt->bytes_per_pixel); + + return SDL_DuplicatePixels(rect->w, rect->h, surface->format, SDL_COLORSPACE_SRGB, pixels, surface->pitch); +} + +static bool SW_RenderPresent(SDL_Renderer *renderer) +{ + SDL_Window *window = renderer->window; + + if (!window) { + return false; + } + return SDL_UpdateWindowSurface(window); +} + +static void SW_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) +{ + SDL_Surface *surface = (SDL_Surface *)texture->internal; + + SDL_DestroySurface(surface); +} + +static void SW_DestroyRenderer(SDL_Renderer *renderer) +{ + SDL_Window *window = renderer->window; + SW_RenderData *data = (SW_RenderData *)renderer->internal; + + if (window) { + SDL_DestroyWindowSurface(window); + } + SDL_free(data); +} + +static void SW_SelectBestFormats(SDL_Renderer *renderer, SDL_PixelFormat format) +{ + // Prefer the format used by the framebuffer by default. + SDL_AddSupportedTextureFormat(renderer, format); + + switch (format) { + case SDL_PIXELFORMAT_XRGB4444: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB4444); + break; + case SDL_PIXELFORMAT_XBGR4444: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR4444); + break; + case SDL_PIXELFORMAT_ARGB4444: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB4444); + break; + case SDL_PIXELFORMAT_ABGR4444: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR4444); + break; + + case SDL_PIXELFORMAT_XRGB1555: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB1555); + break; + case SDL_PIXELFORMAT_XBGR1555: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR1555); + break; + case SDL_PIXELFORMAT_ARGB1555: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB1555); + break; + case SDL_PIXELFORMAT_ABGR1555: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR1555); + break; + + case SDL_PIXELFORMAT_XRGB8888: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888); + break; + case SDL_PIXELFORMAT_RGBX8888: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA8888); + break; + case SDL_PIXELFORMAT_XBGR8888: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888); + break; + case SDL_PIXELFORMAT_BGRX8888: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA8888); + break; + case SDL_PIXELFORMAT_ARGB8888: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888); + break; + case SDL_PIXELFORMAT_RGBA8888: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBX8888); + break; + case SDL_PIXELFORMAT_ABGR8888: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR8888); + break; + case SDL_PIXELFORMAT_BGRA8888: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRX8888); + break; + default: + break; + } + + /* Ensure that we always have a SDL_PACKEDLAYOUT_8888 format. Having a matching component order increases the + * chances of getting a fast path for blitting. + */ + if (SDL_ISPIXELFORMAT_PACKED(format)) { + if (SDL_PIXELLAYOUT(format) != SDL_PACKEDLAYOUT_8888) { + switch (SDL_PIXELORDER(format)) { + case SDL_PACKEDORDER_BGRX: + case SDL_PACKEDORDER_BGRA: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRX8888); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA8888); + break; + case SDL_PACKEDORDER_RGBX: + case SDL_PACKEDORDER_RGBA: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBX8888); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA8888); + break; + case SDL_PACKEDORDER_XBGR: + case SDL_PACKEDORDER_ABGR: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR8888); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888); + break; + case SDL_PACKEDORDER_XRGB: + case SDL_PACKEDORDER_ARGB: + default: + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888); + break; + } + } + } else { + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888); + } +} + +bool SW_CreateRendererForSurface(SDL_Renderer *renderer, SDL_Surface *surface, SDL_PropertiesID create_props) +{ + SW_RenderData *data; + + if (!SDL_SurfaceValid(surface)) { + return SDL_InvalidParamError("surface"); + } + + renderer->software = true; + + data = (SW_RenderData *)SDL_calloc(1, sizeof(*data)); + if (!data) { + return false; + } + data->surface = surface; + data->window = surface; + + renderer->WindowEvent = SW_WindowEvent; + renderer->GetOutputSize = SW_GetOutputSize; + renderer->CreateTexture = SW_CreateTexture; + renderer->UpdateTexture = SW_UpdateTexture; + renderer->LockTexture = SW_LockTexture; + renderer->UnlockTexture = SW_UnlockTexture; + renderer->SetTextureScaleMode = SW_SetTextureScaleMode; + renderer->SetRenderTarget = SW_SetRenderTarget; + renderer->QueueSetViewport = SW_QueueNoOp; + renderer->QueueSetDrawColor = SW_QueueNoOp; + renderer->QueueDrawPoints = SW_QueueDrawPoints; + renderer->QueueDrawLines = SW_QueueDrawPoints; // lines and points queue vertices the same way. + renderer->QueueFillRects = SW_QueueFillRects; + renderer->QueueCopy = SW_QueueCopy; + renderer->QueueCopyEx = SW_QueueCopyEx; + renderer->QueueGeometry = SW_QueueGeometry; + renderer->InvalidateCachedState = SW_InvalidateCachedState; + renderer->RunCommandQueue = SW_RunCommandQueue; + renderer->RenderReadPixels = SW_RenderReadPixels; + renderer->RenderPresent = SW_RenderPresent; + renderer->DestroyTexture = SW_DestroyTexture; + renderer->DestroyRenderer = SW_DestroyRenderer; + renderer->internal = data; + SW_InvalidateCachedState(renderer); + + renderer->name = SW_RenderDriver.name; + + SW_SelectBestFormats(renderer, surface->format); + + SDL_SetupRendererColorspace(renderer, create_props); + + if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) { + return SDL_SetError("Unsupported output colorspace"); + } + + return true; +} + +static bool SW_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props) +{ + // Set the vsync hint based on our flags, if it's not already set + const char *hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC); + const bool no_hint_set = (!hint || !*hint); + + if (no_hint_set) { + if (SDL_GetBooleanProperty(create_props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0)) { + SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1"); + } else { + SDL_SetHint(SDL_HINT_RENDER_VSYNC, "0"); + } + } + + SDL_Surface *surface = SDL_GetWindowSurface(window); + + // Reset the vsync hint if we set it above + if (no_hint_set) { + SDL_SetHint(SDL_HINT_RENDER_VSYNC, ""); + } + + if (!SDL_SurfaceValid(surface)) { + return false; + } + + return SW_CreateRendererForSurface(renderer, surface, create_props); +} + +SDL_RenderDriver SW_RenderDriver = { + SW_CreateRenderer, SDL_SOFTWARE_RENDERER +}; + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_render_sw_c_h_ +#define SDL_render_sw_c_h_ + +extern bool SW_CreateRendererForSurface(SDL_Renderer *renderer, SDL_Surface *surface, SDL_PropertiesID create_props); + +#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 @@ +/* + +SDL_rotate.c: rotates 32bit or 8bit surfaces + +Shamelessly stolen from SDL_gfx by Andreas Schiffler. Original copyright follows: + +Copyright (C) 2001-2011 Andreas Schiffler + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + +Andreas Schiffler -- aschiffler at ferzkopp dot net + +*/ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_RENDER_SW + +#if defined(SDL_PLATFORM_WINDOWS) +#include "../../core/windows/SDL_windows.h" +#endif + +#include "SDL_rotate.h" + +#include "../../video/SDL_surface_c.h" + +// ---- Internally used structures + +/** +A 32 bit RGBA pixel. +*/ +typedef struct tColorRGBA +{ + Uint8 r; + Uint8 g; + Uint8 b; + Uint8 a; +} tColorRGBA; + +/** +A 8bit Y/palette pixel. +*/ +typedef struct tColorY +{ + Uint8 y; +} tColorY; + +/** +Number of guard rows added to destination surfaces. + +This is a simple but effective workaround for observed issues. +These rows allocate extra memory and are then hidden from the surface. +Rows are added to the end of destination surfaces when they are allocated. +This catches any potential overflows which seem to happen with +just the right src image dimensions and scale/rotation and can lead +to a situation where the program can segfault. +*/ +#define GUARD_ROWS (2) + +/** +Returns colorkey info for a surface +*/ +static Uint32 get_colorkey(SDL_Surface *src) +{ + Uint32 key = 0; + if (SDL_SurfaceHasColorKey(src)) { + SDL_GetSurfaceColorKey(src, &key); + } + return key; +} + +// rotate (sx, sy) by (angle, center) into (dx, dy) +static void rotate(double sx, double sy, double sinangle, double cosangle, const SDL_FPoint *center, double *dx, double *dy) +{ + sx -= center->x; + sy -= center->y; + + *dx = cosangle * sx - sinangle * sy; + *dy = sinangle * sx + cosangle * sy; + + *dx += center->x; + *dy += center->y; +} + +/** +Internal target surface sizing function for rotations with trig result return. + +\param width The source surface width. +\param height The source surface height. +\param angle The angle to rotate in degrees. +\param center The center of ratation +\param rect_dest Bounding box of rotated rectangle +\param cangle The sine of the angle +\param sangle The cosine of the angle + +*/ +void SDLgfx_rotozoomSurfaceSizeTrig(int width, int height, double angle, const SDL_FPoint *center, + SDL_Rect *rect_dest, double *cangle, double *sangle) +{ + int minx, maxx, miny, maxy; + double radangle; + double x0, x1, x2, x3; + double y0, y1, y2, y3; + double sinangle; + double cosangle; + + radangle = angle * (SDL_PI_D / 180.0); + sinangle = SDL_sin(radangle); + cosangle = SDL_cos(radangle); + + /* + * Determine destination width and height by rotating a source box, at pixel center + */ + rotate(0.5, 0.5, sinangle, cosangle, center, &x0, &y0); + rotate(width - 0.5, 0.5, sinangle, cosangle, center, &x1, &y1); + rotate(0.5, height - 0.5, sinangle, cosangle, center, &x2, &y2); + rotate(width - 0.5, height - 0.5, sinangle, cosangle, center, &x3, &y3); + + minx = (int)SDL_floor(SDL_min(SDL_min(x0, x1), SDL_min(x2, x3))); + maxx = (int)SDL_ceil(SDL_max(SDL_max(x0, x1), SDL_max(x2, x3))); + + miny = (int)SDL_floor(SDL_min(SDL_min(y0, y1), SDL_min(y2, y3))); + maxy = (int)SDL_ceil(SDL_max(SDL_max(y0, y1), SDL_max(y2, y3))); + + rect_dest->w = maxx - minx; + rect_dest->h = maxy - miny; + rect_dest->x = minx; + rect_dest->y = miny; + + // reverse the angle because our rotations are clockwise + *sangle = -sinangle; + *cangle = cosangle; + + { + // The trig code below gets the wrong size (due to FP inaccuracy?) when angle is a multiple of 90 degrees + int angle90 = (int)(angle / 90); + if (angle90 == angle / 90) { // if the angle is a multiple of 90 degrees + angle90 %= 4; + if (angle90 < 0) { + angle90 += 4; // 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg + } + + if (angle90 & 1) { + rect_dest->w = height; + rect_dest->h = width; + *cangle = 0; + *sangle = angle90 == 1 ? -1 : 1; // reversed because our rotations are clockwise + } else { + rect_dest->w = width; + rect_dest->h = height; + *cangle = angle90 == 0 ? 1 : -1; + *sangle = 0; + } + } + } +} + +// Computes source pointer X/Y increments for a rotation that's a multiple of 90 degrees. +static void computeSourceIncrements90(SDL_Surface *src, int bpp, int angle, int flipx, int flipy, + int *sincx, int *sincy, int *signx, int *signy) +{ + int pitch = flipy ? -src->pitch : src->pitch; + if (flipx) { + bpp = -bpp; + } + switch (angle) { // 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg + case 0: + *sincx = bpp; + *sincy = pitch - src->w * *sincx; + *signx = *signy = 1; + break; + case 1: + *sincx = -pitch; + *sincy = bpp - *sincx * src->h; + *signx = 1; + *signy = -1; + break; + case 2: + *sincx = -bpp; + *sincy = -src->w * *sincx - pitch; + *signx = *signy = -1; + break; + case 3: + default: + *sincx = pitch; + *sincy = -*sincx * src->h - bpp; + *signx = -1; + *signy = 1; + break; + } + if (flipx) { + *signx = -*signx; + } + if (flipy) { + *signy = -*signy; + } +} + +// Performs a relatively fast rotation/flip when the angle is a multiple of 90 degrees. +#define TRANSFORM_SURFACE_90(pixelType) \ + int dy, dincy = dst->pitch - dst->w * sizeof(pixelType), sincx, sincy, signx, signy; \ + Uint8 *sp = (Uint8 *)src->pixels, *dp = (Uint8 *)dst->pixels, *de; \ + \ + computeSourceIncrements90(src, sizeof(pixelType), angle, flipx, flipy, &sincx, &sincy, &signx, &signy); \ + if (signx < 0) \ + sp += (src->w - 1) * sizeof(pixelType); \ + if (signy < 0) \ + sp += (src->h - 1) * src->pitch; \ + \ + for (dy = 0; dy < dst->h; sp += sincy, dp += dincy, dy++) { \ + if (sincx == sizeof(pixelType)) { /* if advancing src and dest equally, use SDL_memcpy */ \ + SDL_memcpy(dp, sp, dst->w * sizeof(pixelType)); \ + sp += dst->w * sizeof(pixelType); \ + dp += dst->w * sizeof(pixelType); \ + } else { \ + for (de = dp + dst->w * sizeof(pixelType); dp != de; sp += sincx, dp += sizeof(pixelType)) { \ + *(pixelType *)dp = *(pixelType *)sp; \ + } \ + } \ + } + +static void transformSurfaceRGBA90(SDL_Surface *src, SDL_Surface *dst, int angle, int flipx, int flipy) +{ + TRANSFORM_SURFACE_90(tColorRGBA); +} + +static void transformSurfaceY90(SDL_Surface *src, SDL_Surface *dst, int angle, int flipx, int flipy) +{ + TRANSFORM_SURFACE_90(tColorY); +} + +#undef TRANSFORM_SURFACE_90 + +/** +Internal 32 bit rotozoomer with optional anti-aliasing. + +Rotates and zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control +parameters by scanning the destination surface and applying optionally anti-aliasing +by bilinear interpolation. +Assumes src and dst surfaces are of 32 bit depth. +Assumes dst surface was allocated with the correct dimensions. + +\param src Source surface. +\param dst Destination surface. +\param isin Integer version of sine of angle. +\param icos Integer version of cosine of angle. +\param flipx Flag indicating horizontal mirroring should be applied. +\param flipy Flag indicating vertical mirroring should be applied. +\param smooth Flag indicating anti-aliasing should be used. +\param rect_dest destination coordinates +\param center true center. +*/ +static void transformSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst, int isin, int icos, + int flipx, int flipy, int smooth, + const SDL_Rect *rect_dest, + const SDL_FPoint *center) +{ + int sw, sh; + int cx, cy; + tColorRGBA c00, c01, c10, c11, cswap; + tColorRGBA *pc, *sp; + int gap; + const int fp_half = (1 << 15); + + /* + * Variable setup + */ + sw = src->w - 1; + sh = src->h - 1; + pc = (tColorRGBA *)dst->pixels; + gap = dst->pitch - dst->w * 4; + cx = (int)(center->x * 65536.0); + cy = (int)(center->y * 65536.0); + + /* + * Switch between interpolating and non-interpolating code + */ + if (smooth) { + int y; + for (y = 0; y < dst->h; y++) { + int x; + double src_x = ((double)rect_dest->x + 0 + 0.5 - center->x); + double src_y = ((double)rect_dest->y + y + 0.5 - center->y); + int sdx = (int)((icos * src_x - isin * src_y) + cx - fp_half); + int sdy = (int)((isin * src_x + icos * src_y) + cy - fp_half); + for (x = 0; x < dst->w; x++) { + int dx = (sdx >> 16); + int dy = (sdy >> 16); + if (flipx) { + dx = sw - dx; + } + if (flipy) { + dy = sh - dy; + } + if ((dx > -1) && (dy > -1) && (dx < (src->w - 1)) && (dy < (src->h - 1))) { + int ex, ey; + int t1, t2; + sp = (tColorRGBA *)((Uint8 *)src->pixels + src->pitch * dy) + dx; + c00 = *sp; + sp += 1; + c01 = *sp; + sp += (src->pitch / 4); + c11 = *sp; + sp -= 1; + c10 = *sp; + if (flipx) { + cswap = c00; + c00 = c01; + c01 = cswap; + cswap = c10; + c10 = c11; + c11 = cswap; + } + if (flipy) { + cswap = c00; + c00 = c10; + c10 = cswap; + cswap = c01; + c01 = c11; + c11 = cswap; + } + /* + * Interpolate colors + */ + ex = (sdx & 0xffff); + ey = (sdy & 0xffff); + t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff; + t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff; + pc->r = (Uint8)((((t2 - t1) * ey) >> 16) + t1); + t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff; + t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff; + pc->g = (Uint8)((((t2 - t1) * ey) >> 16) + t1); + t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff; + t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff; + pc->b = (Uint8)((((t2 - t1) * ey) >> 16) + t1); + t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff; + t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff; + pc->a = (Uint8)((((t2 - t1) * ey) >> 16) + t1); + } + sdx += icos; + sdy += isin; + pc++; + } + pc = (tColorRGBA *)((Uint8 *)pc + gap); + } + } else { + int y; + for (y = 0; y < dst->h; y++) { + int x; + double src_x = ((double)rect_dest->x + 0 + 0.5 - center->x); + double src_y = ((double)rect_dest->y + y + 0.5 - center->y); + int sdx = (int)((icos * src_x - isin * src_y) + cx - fp_half); + int sdy = (int)((isin * src_x + icos * src_y) + cy - fp_half); + for (x = 0; x < dst->w; x++) { + int dx = (sdx >> 16); + int dy = (sdy >> 16); + if ((unsigned)dx < (unsigned)src->w && (unsigned)dy < (unsigned)src->h) { + if (flipx) { + dx = sw - dx; + } + if (flipy) { + dy = sh - dy; + } + *pc = *((tColorRGBA *)((Uint8 *)src->pixels + src->pitch * dy) + dx); + } + sdx += icos; + sdy += isin; + pc++; + } + pc = (tColorRGBA *)((Uint8 *)pc + gap); + } + } +} + +/** + +Rotates and zooms 8 bit palette/Y 'src' surface to 'dst' surface without smoothing. + +Rotates and zooms 8 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control +parameters by scanning the destination surface. +Assumes src and dst surfaces are of 8 bit depth. +Assumes dst surface was allocated with the correct dimensions. + +\param src Source surface. +\param dst Destination surface. +\param isin Integer version of sine of angle. +\param icos Integer version of cosine of angle. +\param flipx Flag indicating horizontal mirroring should be applied. +\param flipy Flag indicating vertical mirroring should be applied. +\param rect_dest destination coordinates +\param center true center. +*/ +static void transformSurfaceY(SDL_Surface *src, SDL_Surface *dst, int isin, int icos, int flipx, int flipy, + const SDL_Rect *rect_dest, + const SDL_FPoint *center) +{ + int sw, sh; + int cx, cy; + tColorY *pc; + int gap; + const int fp_half = (1 << 15); + int y; + + /* + * Variable setup + */ + sw = src->w - 1; + sh = src->h - 1; + pc = (tColorY *)dst->pixels; + gap = dst->pitch - dst->w; + cx = (int)(center->x * 65536.0); + cy = (int)(center->y * 65536.0); + + /* + * Clear surface to colorkey + */ + SDL_memset(pc, (int)(get_colorkey(src) & 0xff), (size_t)dst->pitch * dst->h); + /* + * Iterate through destination surface + */ + for (y = 0; y < dst->h; y++) { + int x; + double src_x = ((double)rect_dest->x + 0 + 0.5 - center->x); + double src_y = ((double)rect_dest->y + y + 0.5 - center->y); + int sdx = (int)((icos * src_x - isin * src_y) + cx - fp_half); + int sdy = (int)((isin * src_x + icos * src_y) + cy - fp_half); + for (x = 0; x < dst->w; x++) { + int dx = (sdx >> 16); + int dy = (sdy >> 16); + if ((unsigned)dx < (unsigned)src->w && (unsigned)dy < (unsigned)src->h) { + if (flipx) { + dx = sw - dx; + } + if (flipy) { + dy = sh - dy; + } + *pc = *((tColorY *)src->pixels + src->pitch * dy + dx); + } + sdx += icos; + sdy += isin; + pc++; + } + pc += gap; + } +} + +/** +Rotates and zooms a surface with different horizontal and vertival scaling factors and optional anti-aliasing. + +Rotates a 32-bit or 8-bit 'src' surface to newly created 'dst' surface. +'angle' is the rotation in degrees, 'center' the rotation center. If 'smooth' is set +then the destination 32-bit surface is anti-aliased. 8-bit surfaces must have a colorkey. 32-bit +surfaces must have a 8888 layout with red, green, blue and alpha masks (any ordering goes). +The blend mode of the 'src' surface has some effects on generation of the 'dst' surface: The NONE +mode will set the BLEND mode on the 'dst' surface. The MOD mode either generates a white 'dst' +surface and sets the colorkey or fills the it with the colorkey before copying the pixels. +When using the NONE and MOD modes, color and alpha modulation must be applied before using this function. + +\param src The surface to rotozoom. +\param angle The angle to rotate in degrees. +\param smooth Antialiasing flag; set to SMOOTHING_ON to enable. +\param flipx Set to 1 to flip the image horizontally +\param flipy Set to 1 to flip the image vertically +\param rect_dest The destination rect bounding box +\param cangle The angle cosine +\param sangle The angle sine +\param center The true coordinate of the center of rotation +\return The new rotated surface. + +*/ + +SDL_Surface *SDLgfx_rotateSurface(SDL_Surface *src, double angle, int smooth, int flipx, int flipy, + const SDL_Rect *rect_dest, double cangle, double sangle, const SDL_FPoint *center) +{ + SDL_Surface *rz_dst; + int is8bit, angle90; + SDL_BlendMode blendmode; + Uint32 colorkey = 0; + bool colorKeyAvailable = false; + double sangleinv, cangleinv; + + // Sanity check + if (!SDL_SurfaceValid(src)) { + return NULL; + } + + if (SDL_SurfaceHasColorKey(src)) { + if (SDL_GetSurfaceColorKey(src, &colorkey)) { + colorKeyAvailable = true; + } + } + // This function requires a 32-bit surface or 8-bit surface with a colorkey + is8bit = src->fmt->bits_per_pixel == 8 && colorKeyAvailable; + if (!(is8bit || (src->fmt->bits_per_pixel == 32 && SDL_ISPIXELFORMAT_ALPHA(src->format)))) { + return NULL; + } + + // Calculate target factors from sine/cosine and zoom + sangleinv = sangle * 65536.0; + cangleinv = cangle * 65536.0; + + // Alloc space to completely contain the rotated surface + rz_dst = NULL; + if (is8bit) { + // Target surface is 8 bit + rz_dst = SDL_CreateSurface(rect_dest->w, rect_dest->h + GUARD_ROWS, src->format); + if (rz_dst) { + SDL_SetSurfacePalette(rz_dst, src->palette); + } + } else { + // Target surface is 32 bit with source RGBA ordering + rz_dst = SDL_CreateSurface(rect_dest->w, rect_dest->h + GUARD_ROWS, src->format); + } + + // Check target + if (!rz_dst) { + return NULL; + } + + // Adjust for guard rows + rz_dst->h = rect_dest->h; + + SDL_GetSurfaceBlendMode(src, &blendmode); + + if (colorKeyAvailable) { + // If available, the colorkey will be used to discard the pixels that are outside of the rotated area. + SDL_SetSurfaceColorKey(rz_dst, true, colorkey); + SDL_FillSurfaceRect(rz_dst, NULL, colorkey); + } else if (blendmode == SDL_BLENDMODE_NONE) { + blendmode = SDL_BLENDMODE_BLEND; + } else if (blendmode == SDL_BLENDMODE_MOD || blendmode == SDL_BLENDMODE_MUL) { + /* Without a colorkey, the target texture has to be white for the MOD and MUL blend mode so + * that the pixels outside the rotated area don't affect the destination surface. + */ + colorkey = SDL_MapSurfaceRGBA(rz_dst, 255, 255, 255, 0); + SDL_FillSurfaceRect(rz_dst, NULL, colorkey); + /* Setting a white colorkey for the destination surface makes the final blit discard + * all pixels outside of the rotated area. This doesn't interfere with anything because + * white pixels are already a no-op and the MOD blend mode does not interact with alpha. + */ + SDL_SetSurfaceColorKey(rz_dst, true, colorkey); + } + + SDL_SetSurfaceBlendMode(rz_dst, blendmode); + + // Lock source surface + if (SDL_MUSTLOCK(src)) { + if (!SDL_LockSurface(src)) { + SDL_DestroySurface(rz_dst); + return NULL; + } + } + + /* check if the rotation is a multiple of 90 degrees so we can take a fast path and also somewhat reduce + * the off-by-one problem in transformSurfaceRGBA that expresses itself when the rotation is near + * multiples of 90 degrees. + */ + angle90 = (int)(angle / 90); + if (angle90 == angle / 90) { + angle90 %= 4; + if (angle90 < 0) { + angle90 += 4; // 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg + } + + } else { + angle90 = -1; + } + + if (is8bit) { + // Call the 8-bit transformation routine to do the rotation + if (angle90 >= 0) { + transformSurfaceY90(src, rz_dst, angle90, flipx, flipy); + } else { + transformSurfaceY(src, rz_dst, (int)sangleinv, (int)cangleinv, + flipx, flipy, rect_dest, center); + } + } else { + // Call the 32-bit transformation routine to do the rotation + if (angle90 >= 0) { + transformSurfaceRGBA90(src, rz_dst, angle90, flipx, flipy); + } else { + transformSurfaceRGBA(src, rz_dst, (int)sangleinv, (int)cangleinv, + flipx, flipy, smooth, rect_dest, center); + } + } + + // Unlock source surface + if (SDL_MUSTLOCK(src)) { + SDL_UnlockSurface(src); + } + + // Return rotated surface + return rz_dst; +} + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_rotate_h_ +#define SDL_rotate_h_ + +extern SDL_Surface *SDLgfx_rotateSurface(SDL_Surface *src, double angle, int smooth, int flipx, int flipy, + const SDL_Rect *rect_dest, double cangle, double sangle, const SDL_FPoint *center); +extern void SDLgfx_rotozoomSurfaceSizeTrig(int width, int height, double angle, const SDL_FPoint *center, + SDL_Rect *rect_dest, double *cangle, double *sangle); + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_RENDER_SW + +#include + +#include "SDL_triangle.h" + +#include "../../video/SDL_surface_c.h" + +/* fixed points bits precision + * Set to 1, so that it can start rendering with middle of a pixel precision. + * It doesn't need to be increased. + * But, if increased too much, it overflows (srcx, srcy) coordinates used for filling with texture. + * (which could be turned to int64). + */ +#define FP_BITS 1 + +#define COLOR_EQ(c1, c2) ((c1).r == (c2).r && (c1).g == (c2).g && (c1).b == (c2).b && (c1).a == (c2).a) + +static void SDL_BlitTriangle_Slow(SDL_BlitInfo *info, + SDL_Point s2_x_area, SDL_Rect dstrect, int area, int bias_w0, int bias_w1, int bias_w2, + int d2d1_y, int d1d2_x, int d0d2_y, int d2d0_x, int d1d0_y, int d0d1_x, + int s2s0_x, int s2s1_x, int s2s0_y, int s2s1_y, int w0_row, int w1_row, int w2_row, + SDL_Color c0, SDL_Color c1, SDL_Color c2, bool is_uniform, SDL_TextureAddressMode texture_address_mode); + +#if 0 +bool SDL_BlitTriangle(SDL_Surface *src, const SDL_Point srcpoints[3], SDL_Surface *dst, const SDL_Point dstpoints[3]) +{ + int i; + SDL_Point points[6]; + + if (src == NULL || dst == NULL) { + return false; + } + + for (i = 0; i < 3; i++) { + if (srcpoints[i].x < 0 || srcpoints[i].y < 0 || srcpoints[i].x >= src->w || srcpoints[i].y >= src->h) { + return SDL_SetError("Values of 'srcpoints' out of bounds"); + } + } + + points[0] = srcpoints[0]; + points[1] = dstpoints[0]; + points[2] = srcpoints[1]; + points[3] = dstpoints[1]; + points[4] = srcpoints[2]; + points[5] = dstpoints[2]; + for (i = 0; i < 3; i++) { + trianglepoint_2_fixedpoint(&points[2 * i + 1]); + } + return SDL_SW_BlitTriangle(src, dst, points); +} + +bool SDL_FillTriangle(SDL_Surface *dst, const SDL_Point points[3], Uint32 color) +{ + int i; + SDL_Point points_tmp[3]; + if (dst == NULL) { + return false; + } + for (i = 0; i < 3; i++) { + points_tmp[i] = points[i]; + trianglepoint_2_fixedpoint(&points_tmp[i]); + } + return SDL_SW_FillTriangle(dst, points_tmp, SDL_BLENDMODE_NONE, color); +} +#endif + +// cross product AB x AC +static Sint64 cross_product(const SDL_Point *a, const SDL_Point *b, int c_x, int c_y) +{ + return ((Sint64)(b->x - a->x)) * ((Sint64)(c_y - a->y)) - ((Sint64)(b->y - a->y)) * ((Sint64)(c_x - a->x)); +} + +// check for top left rules +static bool is_top_left(const SDL_Point *a, const SDL_Point *b, int is_clockwise) +{ + if (is_clockwise) { + if (a->y == b->y && a->x < b->x) { + return true; + } + if (b->y < a->y) { + return true; + } + } else { + if (a->y == b->y && b->x < a->x) { + return true; + } + if (a->y < b->y) { + return true; + } + } + return false; +} + +// x = (y << FP_BITS) +// prevent runtime error: left shift of negative value +#define PRECOMP(x, y) \ + val = y; \ + if (val >= 0) { \ + x = val << FP_BITS; \ + } else { \ + val *= -1; \ + x = val << FP_BITS; \ + x *= -1; \ + } + +void trianglepoint_2_fixedpoint(SDL_Point *a) +{ + int val; + PRECOMP(a->x, a->x); + PRECOMP(a->y, a->y); +} + +// bounding rect of three points (in fixed point) +static void bounding_rect_fixedpoint(const SDL_Point *a, const SDL_Point *b, const SDL_Point *c, SDL_Rect *r) +{ + int min_x = SDL_min(a->x, SDL_min(b->x, c->x)); + int max_x = SDL_max(a->x, SDL_max(b->x, c->x)); + int min_y = SDL_min(a->y, SDL_min(b->y, c->y)); + int max_y = SDL_max(a->y, SDL_max(b->y, c->y)); + // points are in fixed point, shift back + r->x = min_x >> FP_BITS; + r->y = min_y >> FP_BITS; + r->w = (max_x - min_x) >> FP_BITS; + r->h = (max_y - min_y) >> FP_BITS; +} + +// bounding rect of three points +static void bounding_rect(const SDL_Point *a, const SDL_Point *b, const SDL_Point *c, SDL_Rect *r) +{ + int min_x = SDL_min(a->x, SDL_min(b->x, c->x)); + int max_x = SDL_max(a->x, SDL_max(b->x, c->x)); + int min_y = SDL_min(a->y, SDL_min(b->y, c->y)); + int max_y = SDL_max(a->y, SDL_max(b->y, c->y)); + r->x = min_x; + r->y = min_y; + r->w = (max_x - min_x); + r->h = (max_y - min_y); +} + +/* Triangle rendering, using Barycentric coordinates (w0, w1, w2) + * + * The cross product isn't computed from scratch at each iteration, + * but optimized using constant step increments + * + */ + +#define TRIANGLE_BEGIN_LOOP \ + { \ + int x, y; \ + for (y = 0; y < dstrect.h; y++) { \ + /* y start */ \ + Sint64 w0 = w0_row; \ + Sint64 w1 = w1_row; \ + Sint64 w2 = w2_row; \ + for (x = 0; x < dstrect.w; x++) { \ + /* In triangle */ \ + if (w0 + bias_w0 >= 0 && w1 + bias_w1 >= 0 && w2 + bias_w2 >= 0) { \ + Uint8 *dptr = (Uint8 *)dst_ptr + x * dstbpp; + +// Use 64 bits precision to prevent overflow when interpolating color / texture with wide triangles +#define TRIANGLE_GET_TEXTCOORD \ + int srcx = (int)(((Sint64)w0 * s2s0_x + (Sint64)w1 * s2s1_x + s2_x_area.x) / area); \ + int srcy = (int)(((Sint64)w0 * s2s0_y + (Sint64)w1 * s2s1_y + s2_x_area.y) / area); \ + if (texture_address_mode == SDL_TEXTURE_ADDRESS_WRAP) { \ + srcx %= src_surface->w; \ + if (srcx < 0) { \ + srcx += (src_surface->w - 1); \ + } \ + srcy %= src_surface->h; \ + if (srcy < 0) { \ + srcy += (src_surface->h - 1); \ + } \ + } + +#define TRIANGLE_GET_MAPPED_COLOR \ + Uint8 r = (Uint8)(((Sint64)w0 * c0.r + (Sint64)w1 * c1.r + (Sint64)w2 * c2.r) / area); \ + Uint8 g = (Uint8)(((Sint64)w0 * c0.g + (Sint64)w1 * c1.g + (Sint64)w2 * c2.g) / area); \ + Uint8 b = (Uint8)(((Sint64)w0 * c0.b + (Sint64)w1 * c1.b + (Sint64)w2 * c2.b) / area); \ + Uint8 a = (Uint8)(((Sint64)w0 * c0.a + (Sint64)w1 * c1.a + (Sint64)w2 * c2.a) / area); \ + Uint32 color = SDL_MapRGBA(format, palette, r, g, b, a); + +#define TRIANGLE_GET_COLOR \ + int r = (int)(((Sint64)w0 * c0.r + (Sint64)w1 * c1.r + (Sint64)w2 * c2.r) / area); \ + int g = (int)(((Sint64)w0 * c0.g + (Sint64)w1 * c1.g + (Sint64)w2 * c2.g) / area); \ + int b = (int)(((Sint64)w0 * c0.b + (Sint64)w1 * c1.b + (Sint64)w2 * c2.b) / area); \ + int a = (int)(((Sint64)w0 * c0.a + (Sint64)w1 * c1.a + (Sint64)w2 * c2.a) / area); + +#define TRIANGLE_END_LOOP \ + } \ + /* x += 1 */ \ + w0 += d2d1_y; \ + w1 += d0d2_y; \ + w2 += d1d0_y; \ + } \ + /* y += 1 */ \ + w0_row += d1d2_x; \ + w1_row += d2d0_x; \ + w2_row += d0d1_x; \ + dst_ptr += dst_pitch; \ + } \ + } + +bool 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) +{ + bool result = true; + int dst_locked = 0; + + SDL_Rect dstrect; + + int dstbpp; + Uint8 *dst_ptr; + int dst_pitch; + + Sint64 area; + int is_clockwise; + + int d2d1_y, d1d2_x, d0d2_y, d2d0_x, d1d0_y, d0d1_x; + Sint64 w0_row, w1_row, w2_row; + int bias_w0, bias_w1, bias_w2; + + bool is_uniform; + + SDL_Surface *tmp = NULL; + + if (!SDL_SurfaceValid(dst)) { + return false; + } + + area = cross_product(d0, d1, d2->x, d2->y); + + is_uniform = COLOR_EQ(c0, c1) && COLOR_EQ(c1, c2); + + // Flat triangle + if (area == 0) { + return true; + } + + // Lock the destination, if needed + if (SDL_MUSTLOCK(dst)) { + if (!SDL_LockSurface(dst)) { + result = false; + goto end; + } else { + dst_locked = 1; + } + } + + bounding_rect_fixedpoint(d0, d1, d2, &dstrect); + + { + // Clip triangle rect with surface rect + SDL_Rect rect; + rect.x = 0; + rect.y = 0; + rect.w = dst->w; + rect.h = dst->h; + SDL_GetRectIntersection(&dstrect, &rect, &dstrect); + } + + { + // Clip triangle with surface clip rect + SDL_Rect rect; + SDL_GetSurfaceClipRect(dst, &rect); + SDL_GetRectIntersection(&dstrect, &rect, &dstrect); + } + + if (blend != SDL_BLENDMODE_NONE) { + SDL_PixelFormat format = dst->format; + + // need an alpha format + if (!SDL_ISPIXELFORMAT_ALPHA(format)) { + format = SDL_PIXELFORMAT_ARGB8888; + } + + // Use an intermediate surface + tmp = SDL_CreateSurface(dstrect.w, dstrect.h, format); + if (!tmp) { + result = false; + goto end; + } + + if (blend == SDL_BLENDMODE_MOD) { + Uint32 c = SDL_MapSurfaceRGBA(tmp, 255, 255, 255, 255); + SDL_FillSurfaceRect(tmp, NULL, c); + } + + SDL_SetSurfaceBlendMode(tmp, blend); + + dstbpp = tmp->fmt->bytes_per_pixel; + dst_ptr = (Uint8 *)tmp->pixels; + dst_pitch = tmp->pitch; + + } else { + // Write directly to destination surface + dstbpp = dst->fmt->bytes_per_pixel; + dst_ptr = (Uint8 *)dst->pixels + dstrect.x * dstbpp + dstrect.y * dst->pitch; + dst_pitch = dst->pitch; + } + + is_clockwise = area > 0; + if (area < 0) { + area = -area; + } + + { + int val; + PRECOMP(d2d1_y, d1->y - d2->y) + PRECOMP(d0d2_y, d2->y - d0->y) + PRECOMP(d1d0_y, d0->y - d1->y) + PRECOMP(d1d2_x, d2->x - d1->x) + PRECOMP(d2d0_x, d0->x - d2->x) + PRECOMP(d0d1_x, d1->x - d0->x) + } + + // Starting point for rendering, at the middle of a pixel + { + SDL_Point p; + p.x = dstrect.x; + p.y = dstrect.y; + trianglepoint_2_fixedpoint(&p); + p.x += (1 << FP_BITS) / 2; + p.y += (1 << FP_BITS) / 2; + w0_row = cross_product(d1, d2, p.x, p.y); + w1_row = cross_product(d2, d0, p.x, p.y); + w2_row = cross_product(d0, d1, p.x, p.y); + } + + // Handle anti-clockwise triangles + if (!is_clockwise) { + d2d1_y *= -1; + d0d2_y *= -1; + d1d0_y *= -1; + d1d2_x *= -1; + d2d0_x *= -1; + d0d1_x *= -1; + w0_row *= -1; + w1_row *= -1; + w2_row *= -1; + } + + // Add a bias to respect top-left rasterization rule + bias_w0 = (is_top_left(d1, d2, is_clockwise) ? 0 : -1); + bias_w1 = (is_top_left(d2, d0, is_clockwise) ? 0 : -1); + bias_w2 = (is_top_left(d0, d1, is_clockwise) ? 0 : -1); + + if (is_uniform) { + Uint32 color; + if (tmp) { + color = SDL_MapSurfaceRGBA(tmp, c0.r, c0.g, c0.b, c0.a); + } else { + color = SDL_MapSurfaceRGBA(dst, c0.r, c0.g, c0.b, c0.a); + } + + if (dstbpp == 4) { + TRIANGLE_BEGIN_LOOP + { + *(Uint32 *)dptr = color; + } + TRIANGLE_END_LOOP + } else if (dstbpp == 3) { + TRIANGLE_BEGIN_LOOP + { + Uint8 *s = (Uint8 *)&color; + dptr[0] = s[0]; + dptr[1] = s[1]; + dptr[2] = s[2]; + } + TRIANGLE_END_LOOP + } else if (dstbpp == 2) { + TRIANGLE_BEGIN_LOOP + { + *(Uint16 *)dptr = (Uint16)color; + } + TRIANGLE_END_LOOP + } else if (dstbpp == 1) { + TRIANGLE_BEGIN_LOOP + { + *dptr = (Uint8)color; + } + TRIANGLE_END_LOOP + } + } else { + const SDL_PixelFormatDetails *format; + SDL_Palette *palette; + if (tmp) { + format = tmp->fmt; + palette = tmp->palette; + } else { + format = dst->fmt; + palette = dst->palette; + } + if (dstbpp == 4) { + TRIANGLE_BEGIN_LOOP + { + TRIANGLE_GET_MAPPED_COLOR + *(Uint32 *)dptr = color; + } + TRIANGLE_END_LOOP + } else if (dstbpp == 3) { + TRIANGLE_BEGIN_LOOP + { + TRIANGLE_GET_MAPPED_COLOR + Uint8 *s = (Uint8 *)&color; + dptr[0] = s[0]; + dptr[1] = s[1]; + dptr[2] = s[2]; + } + TRIANGLE_END_LOOP + } else if (dstbpp == 2) { + TRIANGLE_BEGIN_LOOP + { + TRIANGLE_GET_MAPPED_COLOR + *(Uint16 *)dptr = (Uint16)color; + } + TRIANGLE_END_LOOP + } else if (dstbpp == 1) { + TRIANGLE_BEGIN_LOOP + { + TRIANGLE_GET_MAPPED_COLOR + *dptr = (Uint8)color; + } + TRIANGLE_END_LOOP + } + } + + if (tmp) { + SDL_BlitSurface(tmp, NULL, dst, &dstrect); + SDL_DestroySurface(tmp); + } + +end: + if (dst_locked) { + SDL_UnlockSurface(dst); + } + + return result; +} + +bool SDL_SW_BlitTriangle( + SDL_Surface *src, + SDL_Point *s0, SDL_Point *s1, SDL_Point *s2, + SDL_Surface *dst, + SDL_Point *d0, SDL_Point *d1, SDL_Point *d2, + SDL_Color c0, SDL_Color c1, SDL_Color c2, + SDL_TextureAddressMode texture_address_mode) +{ + bool result = true; + SDL_Surface *src_surface = src; + int src_locked = 0; + int dst_locked = 0; + + SDL_BlendMode blend; + + SDL_Rect dstrect; + + SDL_Point s2_x_area; + + int dstbpp; + Uint8 *dst_ptr; + int dst_pitch; + + const int *src_ptr; + int src_pitch; + + Sint64 area, tmp64; + int is_clockwise; + + int d2d1_y, d1d2_x, d0d2_y, d2d0_x, d1d0_y, d0d1_x; + int s2s0_x, s2s1_x, s2s0_y, s2s1_y; + + Sint64 w0_row, w1_row, w2_row; + int bias_w0, bias_w1, bias_w2; + + bool is_uniform; + + bool has_modulation; + + if (!SDL_SurfaceValid(src)) { + return SDL_InvalidParamError("src"); + } + if (!SDL_SurfaceValid(dst)) { + return SDL_InvalidParamError("dst"); + } + + area = cross_product(d0, d1, d2->x, d2->y); + + // Flat triangle + if (area == 0) { + return true; + } + + // Lock the destination, if needed + if (SDL_MUSTLOCK(dst)) { + if (!SDL_LockSurface(dst)) { + result = false; + goto end; + } else { + dst_locked = 1; + } + } + + // Lock the source, if needed + if (SDL_MUSTLOCK(src)) { + if (!SDL_LockSurface(src)) { + result = false; + goto end; + } else { + src_locked = 1; + } + } + + is_uniform = COLOR_EQ(c0, c1) && COLOR_EQ(c1, c2); + + bounding_rect_fixedpoint(d0, d1, d2, &dstrect); + + SDL_GetSurfaceBlendMode(src, &blend); + + // TRIANGLE_GET_TEXTCOORD interpolates up to the max values included, so reduce by 1 + if (texture_address_mode == SDL_TEXTURE_ADDRESS_CLAMP) { + SDL_Rect srcrect; + int maxx, maxy; + bounding_rect(s0, s1, s2, &srcrect); + maxx = srcrect.x + srcrect.w; + maxy = srcrect.y + srcrect.h; + if (srcrect.w > 0) { + if (s0->x == maxx) { + s0->x--; + } + if (s1->x == maxx) { + s1->x--; + } + if (s2->x == maxx) { + s2->x--; + } + } + if (srcrect.h > 0) { + if (s0->y == maxy) { + s0->y--; + } + if (s1->y == maxy) { + s1->y--; + } + if (s2->y == maxy) { + s2->y--; + } + } + } + + if (is_uniform) { + // SDL_GetSurfaceColorMod(src, &r, &g, &b); + has_modulation = c0.r != 255 || c0.g != 255 || c0.b != 255 || c0.a != 255; + } else { + has_modulation = true; + } + + { + // Clip triangle with surface clip rect + SDL_Rect rect; + SDL_GetSurfaceClipRect(dst, &rect); + SDL_GetRectIntersection(&dstrect, &rect, &dstrect); + } + + // Set destination pointer + dstbpp = dst->fmt->bytes_per_pixel; + dst_ptr = (Uint8 *)dst->pixels + dstrect.x * dstbpp + dstrect.y * dst->pitch; + dst_pitch = dst->pitch; + + // Set source pointer + src_ptr = (const int *)src->pixels; + src_pitch = src->pitch; + + is_clockwise = area > 0; + if (area < 0) { + area = -area; + } + + { + int val; + PRECOMP(d2d1_y, d1->y - d2->y) + PRECOMP(d0d2_y, d2->y - d0->y) + PRECOMP(d1d0_y, d0->y - d1->y) + PRECOMP(d1d2_x, d2->x - d1->x) + PRECOMP(d2d0_x, d0->x - d2->x) + PRECOMP(d0d1_x, d1->x - d0->x) + } + + s2s0_x = s0->x - s2->x; + s2s1_x = s1->x - s2->x; + s2s0_y = s0->y - s2->y; + s2s1_y = s1->y - s2->y; + + // Starting point for rendering, at the middle of a pixel + { + SDL_Point p; + p.x = dstrect.x; + p.y = dstrect.y; + trianglepoint_2_fixedpoint(&p); + p.x += (1 << FP_BITS) / 2; + p.y += (1 << FP_BITS) / 2; + w0_row = cross_product(d1, d2, p.x, p.y); + w1_row = cross_product(d2, d0, p.x, p.y); + w2_row = cross_product(d0, d1, p.x, p.y); + } + + // Handle anti-clockwise triangles + if (!is_clockwise) { + d2d1_y *= -1; + d0d2_y *= -1; + d1d0_y *= -1; + d1d2_x *= -1; + d2d0_x *= -1; + d0d1_x *= -1; + w0_row *= -1; + w1_row *= -1; + w2_row *= -1; + } + + // Add a bias to respect top-left rasterization rule + bias_w0 = (is_top_left(d1, d2, is_clockwise) ? 0 : -1); + bias_w1 = (is_top_left(d2, d0, is_clockwise) ? 0 : -1); + bias_w2 = (is_top_left(d0, d1, is_clockwise) ? 0 : -1); + + /* precompute constant 's2->x * area' used in TRIANGLE_GET_TEXTCOORD */ + tmp64 = s2->x * area; + if (tmp64 >= INT_MIN && tmp64 <= INT_MAX) { + s2_x_area.x = (int)tmp64; + } else { + result = SDL_SetError("triangle area overflow"); + goto end; + } + tmp64 = s2->y * area; + if (tmp64 >= INT_MIN && tmp64 <= INT_MAX) { + s2_x_area.y = (int)tmp64; + } else { + result = SDL_SetError("triangle area overflow"); + goto end; + } + + if (blend != SDL_BLENDMODE_NONE || src->format != dst->format || has_modulation || !is_uniform) { + // Use SDL_BlitTriangle_Slow + + SDL_BlitInfo *info = &src->map.info; + SDL_BlitInfo tmp_info; + + SDL_zero(tmp_info); + + tmp_info.src_fmt = src->fmt; + tmp_info.dst_fmt = dst->fmt; + tmp_info.flags = info->flags; + /* + tmp_info.r = info->r; + tmp_info.g = info->g; + tmp_info.b = info->b; + tmp_info.a = info->a; + */ + tmp_info.r = c0.r; + tmp_info.g = c0.g; + tmp_info.b = c0.b; + tmp_info.a = c0.a; + + tmp_info.flags &= ~(SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA); + + if (c0.r != 255 || c1.r != 255 || c2.r != 255 || + c0.g != 255 || c1.g != 255 || c2.g != 255 || + c0.b != 255 || c1.b != 255 || c2.b != 255) { + tmp_info.flags |= SDL_COPY_MODULATE_COLOR; + } + + if (c0.a != 255 || c1.a != 255 || c2.a != 255) { + tmp_info.flags |= SDL_COPY_MODULATE_ALPHA; + } + + tmp_info.colorkey = info->colorkey; + + // src + tmp_info.src_surface = src_surface; + tmp_info.src = (Uint8 *)src_ptr; + tmp_info.src_pitch = src_pitch; + + // dst + tmp_info.dst = dst_ptr; + tmp_info.dst_pitch = dst_pitch; + +#define CHECK_INT_RANGE(X) \ + if ((X) < INT_MIN || (X) > INT_MAX) { \ + result = SDL_SetError("integer overflow (%s = %" SDL_PRIs64 ")", #X, X); \ + goto end; \ + } + CHECK_INT_RANGE(area); + CHECK_INT_RANGE(w0_row); + CHECK_INT_RANGE(w1_row); + CHECK_INT_RANGE(w2_row); + SDL_BlitTriangle_Slow(&tmp_info, s2_x_area, dstrect, (int)area, bias_w0, bias_w1, bias_w2, + d2d1_y, d1d2_x, d0d2_y, d2d0_x, d1d0_y, d0d1_x, + s2s0_x, s2s1_x, s2s0_y, s2s1_y, (int)w0_row, (int)w1_row, (int)w2_row, + c0, c1, c2, is_uniform, texture_address_mode); + + goto end; + } + + if (dstbpp == 4) { + TRIANGLE_BEGIN_LOOP + { + TRIANGLE_GET_TEXTCOORD + Uint32 *sptr = (Uint32 *)((Uint8 *)src_ptr + srcy * src_pitch); + *(Uint32 *)dptr = sptr[srcx]; + } + TRIANGLE_END_LOOP + } else if (dstbpp == 3) { + TRIANGLE_BEGIN_LOOP + { + TRIANGLE_GET_TEXTCOORD + Uint8 *sptr = (Uint8 *)src_ptr + srcy * src_pitch; + dptr[0] = sptr[3 * srcx]; + dptr[1] = sptr[3 * srcx + 1]; + dptr[2] = sptr[3 * srcx + 2]; + } + TRIANGLE_END_LOOP + } else if (dstbpp == 2) { + TRIANGLE_BEGIN_LOOP + { + TRIANGLE_GET_TEXTCOORD + Uint16 *sptr = (Uint16 *)((Uint8 *)src_ptr + srcy * src_pitch); + *(Uint16 *)dptr = sptr[srcx]; + } + TRIANGLE_END_LOOP + } else if (dstbpp == 1) { + TRIANGLE_BEGIN_LOOP + { + TRIANGLE_GET_TEXTCOORD + Uint8 *sptr = (Uint8 *)src_ptr + srcy * src_pitch; + *dptr = sptr[srcx]; + } + TRIANGLE_END_LOOP + } + +end: + if (dst_locked) { + SDL_UnlockSurface(dst); + } + if (src_locked) { + SDL_UnlockSurface(src); + } + + return result; +} + +#define FORMAT_ALPHA 0 +#define FORMAT_NO_ALPHA -1 +#define FORMAT_2101010 1 +#define FORMAT_HAS_ALPHA(format) format == 0 +#define FORMAT_HAS_NO_ALPHA(format) format < 0 +static int detect_format(const SDL_PixelFormatDetails *pf) +{ + if (pf->format == SDL_PIXELFORMAT_ARGB2101010) { + return FORMAT_2101010; + } else if (pf->Amask) { + return FORMAT_ALPHA; + } else { + return FORMAT_NO_ALPHA; + } +} + +static void SDL_BlitTriangle_Slow(SDL_BlitInfo *info, + SDL_Point s2_x_area, SDL_Rect dstrect, int area, int bias_w0, int bias_w1, int bias_w2, + int d2d1_y, int d1d2_x, int d0d2_y, int d2d0_x, int d1d0_y, int d0d1_x, + int s2s0_x, int s2s1_x, int s2s0_y, int s2s1_y, int w0_row, int w1_row, int w2_row, + SDL_Color c0, SDL_Color c1, SDL_Color c2, bool is_uniform, SDL_TextureAddressMode texture_address_mode) +{ + SDL_Surface *src_surface = info->src_surface; + const int flags = info->flags; + Uint32 modulateR = info->r; + Uint32 modulateG = info->g; + Uint32 modulateB = info->b; + Uint32 modulateA = info->a; + Uint32 srcpixel; + Uint32 srcR, srcG, srcB, srcA; + Uint32 dstpixel; + Uint32 dstR, dstG, dstB, dstA; + const SDL_PixelFormatDetails *src_fmt = info->src_fmt; + const SDL_PixelFormatDetails *dst_fmt = info->dst_fmt; + int srcbpp = src_fmt->bytes_per_pixel; + int dstbpp = dst_fmt->bytes_per_pixel; + int srcfmt_val; + int dstfmt_val; + Uint32 rgbmask = ~src_fmt->Amask; + Uint32 ckey = info->colorkey & rgbmask; + + Uint8 *dst_ptr = info->dst; + int dst_pitch = info->dst_pitch; + + srcfmt_val = detect_format(src_fmt); + dstfmt_val = detect_format(dst_fmt); + + TRIANGLE_BEGIN_LOOP + { + Uint8 *src; + Uint8 *dst = dptr; + TRIANGLE_GET_TEXTCOORD + src = (info->src + (srcy * info->src_pitch) + (srcx * srcbpp)); + if (FORMAT_HAS_ALPHA(srcfmt_val)) { + DISEMBLE_RGBA(src, srcbpp, src_fmt, srcpixel, srcR, srcG, srcB, srcA); + } else if (FORMAT_HAS_NO_ALPHA(srcfmt_val)) { + DISEMBLE_RGB(src, srcbpp, src_fmt, srcpixel, srcR, srcG, srcB); + srcA = 0xFF; + } else { + // SDL_PIXELFORMAT_ARGB2101010 + srcpixel = *((Uint32 *)(src)); + RGBA_FROM_ARGB2101010(srcpixel, srcR, srcG, srcB, srcA); + } + if (flags & SDL_COPY_COLORKEY) { + // srcpixel isn't set for 24 bpp + if (srcbpp == 3) { + srcpixel = (srcR << src_fmt->Rshift) | + (srcG << src_fmt->Gshift) | (srcB << src_fmt->Bshift); + } + if ((srcpixel & rgbmask) == ckey) { + continue; + } + } + if ((flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL))) { + if (FORMAT_HAS_ALPHA(dstfmt_val)) { + DISEMBLE_RGBA(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB, dstA); + } else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) { + DISEMBLE_RGB(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB); + dstA = 0xFF; + } else { + // SDL_PIXELFORMAT_ARGB2101010 + dstpixel = *((Uint32 *) (dst)); + RGBA_FROM_ARGB2101010(dstpixel, dstR, dstG, dstB, dstA); + } + } else { + // don't care + dstR = dstG = dstB = dstA = 0; + } + + if (!is_uniform) { + TRIANGLE_GET_COLOR + modulateR = r; + modulateG = g; + modulateB = b; + modulateA = a; + } + + if (flags & SDL_COPY_MODULATE_COLOR) { + srcR = (srcR * modulateR) / 255; + srcG = (srcG * modulateG) / 255; + srcB = (srcB * modulateB) / 255; + } + if (flags & SDL_COPY_MODULATE_ALPHA) { + srcA = (srcA * modulateA) / 255; + } + if (flags & (SDL_COPY_BLEND | SDL_COPY_ADD)) { + // This goes away if we ever use premultiplied alpha + if (srcA < 255) { + srcR = (srcR * srcA) / 255; + srcG = (srcG * srcA) / 255; + srcB = (srcB * srcA) / 255; + } + } + switch (flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL)) { + case 0: + dstR = srcR; + dstG = srcG; + dstB = srcB; + dstA = srcA; + break; + case SDL_COPY_BLEND: + dstR = srcR + ((255 - srcA) * dstR) / 255; + dstG = srcG + ((255 - srcA) * dstG) / 255; + dstB = srcB + ((255 - srcA) * dstB) / 255; + dstA = srcA + ((255 - srcA) * dstA) / 255; + break; + case SDL_COPY_ADD: + dstR = srcR + dstR; + if (dstR > 255) { + dstR = 255; + } + dstG = srcG + dstG; + if (dstG > 255) { + dstG = 255; + } + dstB = srcB + dstB; + if (dstB > 255) { + dstB = 255; + } + break; + case SDL_COPY_MOD: + dstR = (srcR * dstR) / 255; + dstG = (srcG * dstG) / 255; + dstB = (srcB * dstB) / 255; + break; + case SDL_COPY_MUL: + dstR = ((srcR * dstR) + (dstR * (255 - srcA))) / 255; + if (dstR > 255) { + dstR = 255; + } + dstG = ((srcG * dstG) + (dstG * (255 - srcA))) / 255; + if (dstG > 255) { + dstG = 255; + } + dstB = ((srcB * dstB) + (dstB * (255 - srcA))) / 255; + if (dstB > 255) { + dstB = 255; + } + break; + } + if (FORMAT_HAS_ALPHA(dstfmt_val)) { + ASSEMBLE_RGBA(dst, dstbpp, dst_fmt, dstR, dstG, dstB, dstA); + } else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) { + ASSEMBLE_RGB(dst, dstbpp, dst_fmt, dstR, dstG, dstB); + } else { + // SDL_PIXELFORMAT_ARGB2101010 + Uint32 pixel; + ARGB2101010_FROM_RGBA(pixel, dstR, dstG, dstB, dstA); + *(Uint32 *)dst = pixel; + } + } + TRIANGLE_END_LOOP +} + +#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 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_triangle_h_ +#define SDL_triangle_h_ + +#include "SDL_internal.h" + +#include "../SDL_sysrender.h" // For SDL_TextureAddressMode + +extern bool 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); + +extern bool SDL_SW_BlitTriangle(SDL_Surface *src, + SDL_Point *s0, SDL_Point *s1, SDL_Point *s2, + SDL_Surface *dst, + SDL_Point *d0, SDL_Point *d1, SDL_Point *d2, + SDL_Color c0, SDL_Color c1, SDL_Color c2, + SDL_TextureAddressMode texture_address_mode); + +extern void trianglepoint_2_fixedpoint(SDL_Point *a); + +#endif // SDL_triangle_h_ -- cgit v1.2.3