From 2660449c6cb33f405d5f3cf4329511a424198550 Mon Sep 17 00:00:00 2001 From: Daniel Santos <47725160+DanielSant0s@users.noreply.github.com> Date: Thu, 30 Jun 2022 11:44:35 -0300 Subject: [PATCH] Add dummy driver --- CMakeLists.txt | 4 +- src/render/SDL_render.c | 3 + src/render/SDL_sysrender.h | 1 + src/render/ps2/SDL_blendfillrect.c | 357 ++++++++ src/render/ps2/SDL_blendfillrect.h | 33 + src/render/ps2/SDL_blendline.c | 875 ++++++++++++++++++++ src/render/ps2/SDL_blendline.h | 33 + src/render/ps2/SDL_blendpoint.c | 362 ++++++++ src/render/ps2/SDL_blendpoint.h | 33 + src/render/ps2/SDL_draw.h | 632 ++++++++++++++ src/render/ps2/SDL_drawline.c | 213 +++++ src/render/ps2/SDL_drawline.h | 33 + src/render/ps2/SDL_drawpoint.c | 114 +++ src/render/ps2/SDL_drawpoint.h | 33 + src/render/ps2/SDL_render_sw.c | 1229 ++++++++++++++++++++++++++++ src/render/ps2/SDL_render_sw_c.h | 37 + src/render/ps2/SDL_rotate.c | 577 +++++++++++++ src/render/ps2/SDL_rotate.h | 30 + src/render/ps2/SDL_triangle.c | 888 ++++++++++++++++++++ src/render/ps2/SDL_triangle.h | 42 + src/video/ps2/SDL_ps2video.c | 77 +- 21 files changed, 5534 insertions(+), 72 deletions(-) create mode 100644 src/render/ps2/SDL_blendfillrect.c create mode 100644 src/render/ps2/SDL_blendfillrect.h create mode 100644 src/render/ps2/SDL_blendline.c create mode 100644 src/render/ps2/SDL_blendline.h create mode 100644 src/render/ps2/SDL_blendpoint.c create mode 100644 src/render/ps2/SDL_blendpoint.h create mode 100644 src/render/ps2/SDL_draw.h create mode 100644 src/render/ps2/SDL_drawline.c create mode 100644 src/render/ps2/SDL_drawline.h create mode 100644 src/render/ps2/SDL_drawpoint.c create mode 100644 src/render/ps2/SDL_drawpoint.h create mode 100644 src/render/ps2/SDL_render_sw.c create mode 100644 src/render/ps2/SDL_render_sw_c.h create mode 100644 src/render/ps2/SDL_rotate.c create mode 100644 src/render/ps2/SDL_rotate.h create mode 100644 src/render/ps2/SDL_triangle.c create mode 100644 src/render/ps2/SDL_triangle.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f430a7cb..2fe57578e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2572,7 +2572,9 @@ elseif(PS2) if(SDL_VIDEO) set(SDL_VIDEO_DRIVER_PS2 1) set(SDL_VIDEO_RENDER_PS2 1) - file(GLOB PS2_VIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/ps2/*.c) + file(GLOB PS2_VIDEO_SOURCES + ${SDL2_SOURCE_DIR}/src/video/ps2/*.c + ${SDL2_SOURCE_DIR}/src/render/ps2/*.c) set(SOURCE_FILES ${SOURCE_FILES} ${PS2_VIDEO_SOURCES}) set(SDL_VIDEO_OPENGL 0) set(HAVE_SDL_VIDEO TRUE) diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index cd33242d9..702cde7ef 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -114,6 +114,9 @@ static const SDL_RenderDriver *render_drivers[] = { #if SDL_VIDEO_RENDER_DIRECTFB &DirectFB_RenderDriver, #endif +#if SDL_VIDEO_RENDER_PS2 + &PS2_RenderDriver, +#endif #if SDL_VIDEO_RENDER_PSP &PSP_RenderDriver, #endif diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index f559a2629..4dcb98ac2 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -293,6 +293,7 @@ extern SDL_RenderDriver GLES2_RenderDriver; extern SDL_RenderDriver GLES_RenderDriver; extern SDL_RenderDriver DirectFB_RenderDriver; extern SDL_RenderDriver METAL_RenderDriver; +extern SDL_RenderDriver PS2_RenderDriver; extern SDL_RenderDriver PSP_RenderDriver; extern SDL_RenderDriver SW_RenderDriver; extern SDL_RenderDriver VITA_GXM_RenderDriver; diff --git a/src/render/ps2/SDL_blendfillrect.c b/src/render/ps2/SDL_blendfillrect.c new file mode 100644 index 000000000..d0e2f836d --- /dev/null +++ b/src/render/ps2/SDL_blendfillrect.c @@ -0,0 +1,357 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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" + +#if SDL_VIDEO_RENDER_PS2 && !SDL_RENDER_DISABLED + +#include "SDL_draw.h" +#include "SDL_blendfillrect.h" + + +static int +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_ADD: + 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 0; +} + +static int +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_ADD: + 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 0; +} + +static int +SDL_BlendFillRect_RGB888(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_RGB888); + break; + case SDL_BLENDMODE_ADD: + FILLRECT(Uint32, DRAW_SETPIXEL_ADD_RGB888); + break; + case SDL_BLENDMODE_MOD: + FILLRECT(Uint32, DRAW_SETPIXEL_MOD_RGB888); + break; + case SDL_BLENDMODE_MUL: + FILLRECT(Uint32, DRAW_SETPIXEL_MUL_RGB888); + break; + default: + FILLRECT(Uint32, DRAW_SETPIXEL_RGB888); + break; + } + return 0; +} + +static int +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_ADD: + 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 0; +} + +static int +SDL_BlendFillRect_RGB(SDL_Surface * dst, const SDL_Rect * rect, + SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + SDL_PixelFormat *fmt = dst->format; + unsigned inva = 0xff - a; + + switch (fmt->BytesPerPixel) { + case 2: + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB); + break; + case SDL_BLENDMODE_ADD: + 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 0; + case 4: + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGB); + break; + case SDL_BLENDMODE_ADD: + 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 0; + default: + return SDL_Unsupported(); + } +} + +static int +SDL_BlendFillRect_RGBA(SDL_Surface * dst, const SDL_Rect * rect, + SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + SDL_PixelFormat *fmt = dst->format; + unsigned inva = 0xff - a; + + switch (fmt->BytesPerPixel) { + case 4: + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGBA); + break; + case SDL_BLENDMODE_ADD: + 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 0; + default: + return SDL_Unsupported(); + } +} + +int +SDL_BlendFillRect(SDL_Surface * dst, const SDL_Rect * rect, + SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + SDL_Rect clipped; + + if (!dst) { + return SDL_InvalidParamError("SDL_BlendFillRect(): dst"); + } + + /* This function doesn't work on surfaces < 8 bpp */ + if (dst->format->BitsPerPixel < 8) { + return SDL_SetError("SDL_BlendFillRect(): Unsupported surface format"); + } + + /* If 'rect' == NULL, then fill the whole surface */ + if (rect) { + /* Perform clipping */ + if (!SDL_IntersectRect(rect, &dst->clip_rect, &clipped)) { + return 0; + } + 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->format->BitsPerPixel) { + case 15: + switch (dst->format->Rmask) { + case 0x7C00: + return SDL_BlendFillRect_RGB555(dst, rect, blendMode, r, g, b, a); + } + break; + case 16: + switch (dst->format->Rmask) { + case 0xF800: + return SDL_BlendFillRect_RGB565(dst, rect, blendMode, r, g, b, a); + } + break; + case 32: + switch (dst->format->Rmask) { + case 0x00FF0000: + if (!dst->format->Amask) { + return SDL_BlendFillRect_RGB888(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->format->Amask) { + return SDL_BlendFillRect_RGB(dst, rect, blendMode, r, g, b, a); + } else { + return SDL_BlendFillRect_RGBA(dst, rect, blendMode, r, g, b, a); + } +} + +int +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; + int (*func)(SDL_Surface * dst, const SDL_Rect * rect, + SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) = NULL; + int status = 0; + + if (!dst) { + return SDL_InvalidParamError("SDL_BlendFillRects(): dst"); + } + + /* This function doesn't work on surfaces < 8 bpp */ + if (dst->format->BitsPerPixel < 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->format->BitsPerPixel) { + case 15: + switch (dst->format->Rmask) { + case 0x7C00: + func = SDL_BlendFillRect_RGB555; + } + break; + case 16: + switch (dst->format->Rmask) { + case 0xF800: + func = SDL_BlendFillRect_RGB565; + } + break; + case 32: + switch (dst->format->Rmask) { + case 0x00FF0000: + if (!dst->format->Amask) { + func = SDL_BlendFillRect_RGB888; + } else { + func = SDL_BlendFillRect_ARGB8888; + } + break; + } + break; + default: + break; + } + + if (!func) { + if (!dst->format->Amask) { + func = SDL_BlendFillRect_RGB; + } else { + func = SDL_BlendFillRect_RGBA; + } + } + + for (i = 0; i < count; ++i) { + /* Perform clipping */ + if (!SDL_IntersectRect(&rects[i], &dst->clip_rect, &rect)) { + continue; + } + status = func(dst, &rect, blendMode, r, g, b, a); + } + return status; +} + +#endif /* SDL_VIDEO_RENDER_SW && !SDL_RENDER_DISABLED */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/ps2/SDL_blendfillrect.h b/src/render/ps2/SDL_blendfillrect.h new file mode 100644 index 000000000..8ee62b198 --- /dev/null +++ b/src/render/ps2/SDL_blendfillrect.h @@ -0,0 +1,33 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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 int SDL_BlendFillRect(SDL_Surface * dst, const SDL_Rect * rect, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a); +extern int 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_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/ps2/SDL_blendline.c b/src/render/ps2/SDL_blendline.c new file mode 100644 index 000000000..363b7a887 --- /dev/null +++ b/src/render/ps2/SDL_blendline.c @@ -0,0 +1,875 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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" + +#if SDL_VIDEO_RENDER_PS2 && !SDL_RENDER_DISABLED + +#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, + SDL_bool draw_end) +{ + const SDL_PixelFormat *fmt = dst->format; + 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_ADD: + 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_ADD: + 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_ADD: + 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_ADD: + 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, + SDL_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_ADD: + 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_ADD: + 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_ADD: + 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_ADD: + 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, + SDL_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_ADD: + 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_ADD: + 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_ADD: + 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_ADD: + 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, + SDL_bool draw_end) +{ + const SDL_PixelFormat *fmt = dst->format; + 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_ADD: + 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_ADD: + 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_ADD: + 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_ADD: + 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, + SDL_bool draw_end) +{ + const SDL_PixelFormat *fmt = dst->format; + 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_ADD: + 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_ADD: + 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_ADD: + 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_ADD: + 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_RGB888(SDL_Surface * dst, int x1, int y1, int x2, int y2, + SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a, + SDL_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_RGB888, draw_end); + break; + case SDL_BLENDMODE_ADD: + HLINE(Uint32, DRAW_SETPIXEL_ADD_RGB888, draw_end); + break; + case SDL_BLENDMODE_MOD: + HLINE(Uint32, DRAW_SETPIXEL_MOD_RGB888, draw_end); + break; + case SDL_BLENDMODE_MUL: + HLINE(Uint32, DRAW_SETPIXEL_MUL_RGB888, draw_end); + break; + default: + HLINE(Uint32, DRAW_SETPIXEL_RGB888, draw_end); + break; + } + } else if (x1 == x2) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + VLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB888, draw_end); + break; + case SDL_BLENDMODE_ADD: + VLINE(Uint32, DRAW_SETPIXEL_ADD_RGB888, draw_end); + break; + case SDL_BLENDMODE_MOD: + VLINE(Uint32, DRAW_SETPIXEL_MOD_RGB888, draw_end); + break; + case SDL_BLENDMODE_MUL: + VLINE(Uint32, DRAW_SETPIXEL_MUL_RGB888, draw_end); + break; + default: + VLINE(Uint32, DRAW_SETPIXEL_RGB888, draw_end); + break; + } + } else if (ABS(x1 - x2) == ABS(y1 - y2)) { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB888, draw_end); + break; + case SDL_BLENDMODE_ADD: + DLINE(Uint32, DRAW_SETPIXEL_ADD_RGB888, draw_end); + break; + case SDL_BLENDMODE_MOD: + DLINE(Uint32, DRAW_SETPIXEL_MOD_RGB888, draw_end); + break; + case SDL_BLENDMODE_MUL: + DLINE(Uint32, DRAW_SETPIXEL_MUL_RGB888, draw_end); + break; + default: + DLINE(Uint32, DRAW_SETPIXEL_RGB888, draw_end); + break; + } + } else { + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_BLEND_RGB888, DRAW_SETPIXELXY_BLEND_RGB888, + draw_end); + break; + case SDL_BLENDMODE_ADD: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_ADD_RGB888, DRAW_SETPIXELXY_ADD_RGB888, + draw_end); + break; + case SDL_BLENDMODE_MOD: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_MOD_RGB888, DRAW_SETPIXELXY_MOD_RGB888, + draw_end); + break; + case SDL_BLENDMODE_MUL: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_MUL_RGB888, DRAW_SETPIXELXY_MUL_RGB888, + draw_end); + break; + default: + AALINE(x1, y1, x2, y2, + DRAW_SETPIXELXY_RGB888, DRAW_SETPIXELXY_BLEND_RGB888, + 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, + SDL_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_ADD: + 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_ADD: + 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_ADD: + 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_ADD: + 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, + SDL_bool draw_end); + +static BlendLineFunc +SDL_CalculateBlendLineFunc(const SDL_PixelFormat * fmt) +{ + switch (fmt->BytesPerPixel) { + 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_RGB888; + } + } else { + if (fmt->Amask) { + return SDL_BlendLine_RGBA4; + } else { + return SDL_BlendLine_RGB4; + } + } + } + return NULL; +} + +int +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 (!dst) { + return SDL_InvalidParamError("SDL_BlendLine(): dst"); + } + + func = SDL_CalculateBlendLineFunc(dst->format); + 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_IntersectRectAndLine(&dst->clip_rect, &x1, &y1, &x2, &y2)) { + return 0; + } + + func(dst, x1, y1, x2, y2, blendMode, r, g, b, a, SDL_TRUE); + return 0; +} + +int +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; + SDL_bool draw_end; + BlendLineFunc func; + + if (!dst) { + return SDL_SetError("SDL_BlendLines(): Passed NULL destination surface"); + } + + func = SDL_CalculateBlendLineFunc(dst->format); + 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_IntersectRectAndLine(&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 0; +} + +#endif /* SDL_VIDEO_RENDER_SW && !SDL_RENDER_DISABLED */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/ps2/SDL_blendline.h b/src/render/ps2/SDL_blendline.h new file mode 100644 index 000000000..a844110c4 --- /dev/null +++ b/src/render/ps2/SDL_blendline.h @@ -0,0 +1,33 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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 int 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 int 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_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/ps2/SDL_blendpoint.c b/src/render/ps2/SDL_blendpoint.c new file mode 100644 index 000000000..ebdb685d1 --- /dev/null +++ b/src/render/ps2/SDL_blendpoint.c @@ -0,0 +1,362 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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" + +#if SDL_VIDEO_RENDER_PS2 && !SDL_RENDER_DISABLED + +#include "SDL_draw.h" +#include "SDL_blendpoint.h" + + +static int +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_ADD: + 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 0; +} + +static int +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_ADD: + 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 0; +} + +static int +SDL_BlendPoint_RGB888(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_RGB888(x, y); + break; + case SDL_BLENDMODE_ADD: + DRAW_SETPIXELXY_ADD_RGB888(x, y); + break; + case SDL_BLENDMODE_MOD: + DRAW_SETPIXELXY_MOD_RGB888(x, y); + break; + case SDL_BLENDMODE_MUL: + DRAW_SETPIXELXY_MUL_RGB888(x, y); + break; + default: + DRAW_SETPIXELXY_RGB888(x, y); + break; + } + return 0; +} + +static int +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_ADD: + 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 0; +} + +static int +SDL_BlendPoint_RGB(SDL_Surface * dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, + Uint8 g, Uint8 b, Uint8 a) +{ + SDL_PixelFormat *fmt = dst->format; + unsigned inva = 0xff - a; + + switch (fmt->BytesPerPixel) { + case 2: + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DRAW_SETPIXELXY2_BLEND_RGB(x, y); + break; + case SDL_BLENDMODE_ADD: + 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 0; + case 4: + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DRAW_SETPIXELXY4_BLEND_RGB(x, y); + break; + case SDL_BLENDMODE_ADD: + 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 0; + default: + return SDL_Unsupported(); + } +} + +static int +SDL_BlendPoint_RGBA(SDL_Surface * dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, + Uint8 g, Uint8 b, Uint8 a) +{ + SDL_PixelFormat *fmt = dst->format; + unsigned inva = 0xff - a; + + switch (fmt->BytesPerPixel) { + case 4: + switch (blendMode) { + case SDL_BLENDMODE_BLEND: + DRAW_SETPIXELXY4_BLEND_RGBA(x, y); + break; + case SDL_BLENDMODE_ADD: + 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 0; + default: + return SDL_Unsupported(); + } +} + +int +SDL_BlendPoint(SDL_Surface * dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, + Uint8 g, Uint8 b, Uint8 a) +{ + if (!dst) { + return SDL_InvalidParamError("SDL_BlendPoint(): dst"); + } + + /* This function doesn't work on surfaces < 8 bpp */ + if (dst->format->BitsPerPixel < 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 0; + } + + 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->format->BitsPerPixel) { + case 15: + switch (dst->format->Rmask) { + case 0x7C00: + return SDL_BlendPoint_RGB555(dst, x, y, blendMode, r, g, b, a); + } + break; + case 16: + switch (dst->format->Rmask) { + case 0xF800: + return SDL_BlendPoint_RGB565(dst, x, y, blendMode, r, g, b, a); + } + break; + case 32: + switch (dst->format->Rmask) { + case 0x00FF0000: + if (!dst->format->Amask) { + return SDL_BlendPoint_RGB888(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->format->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); + } +} + +int +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; + int (*func)(SDL_Surface * dst, int x, int y, + SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) = NULL; + int status = 0; + + if (!dst) { + return SDL_InvalidParamError("SDL_BlendPoints(): dst"); + } + + /* This function doesn't work on surfaces < 8 bpp */ + if (dst->format->BitsPerPixel < 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->format->BitsPerPixel) { + case 15: + switch (dst->format->Rmask) { + case 0x7C00: + func = SDL_BlendPoint_RGB555; + break; + } + break; + case 16: + switch (dst->format->Rmask) { + case 0xF800: + func = SDL_BlendPoint_RGB565; + break; + } + break; + case 32: + switch (dst->format->Rmask) { + case 0x00FF0000: + if (!dst->format->Amask) { + func = SDL_BlendPoint_RGB888; + } else { + func = SDL_BlendPoint_ARGB8888; + } + break; + } + break; + default: + break; + } + + if (!func) { + if (!dst->format->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; + } + status = func(dst, x, y, blendMode, r, g, b, a); + } + return status; +} + +#endif /* SDL_VIDEO_RENDER_SW && !SDL_RENDER_DISABLED */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/ps2/SDL_blendpoint.h b/src/render/ps2/SDL_blendpoint.h new file mode 100644 index 000000000..bf6ddec07 --- /dev/null +++ b/src/render/ps2/SDL_blendpoint.h @@ -0,0 +1,33 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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 int SDL_BlendPoint(SDL_Surface * dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a); +extern int 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_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/ps2/SDL_draw.h b/src/render/ps2/SDL_draw.h new file mode 100644 index 000000000..2acb3d3a1 --- /dev/null +++ b/src/render/ps2/SDL_draw.h @@ -0,0 +1,632 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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_blit.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_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; sa = 0xFF; \ + 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; \ + sa = DRAW_MUL(sa, a) + DRAW_MUL(inva, sa); if (sa > 0xff) sa = 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_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_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_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_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_RGB888 \ + DRAW_SETPIXEL(RGB888_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_BLEND_RGB888 \ + DRAW_SETPIXEL_BLEND(RGB_FROM_RGB888(*pixel, sr, sg, sb), \ + RGB888_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_ADD_RGB888 \ + DRAW_SETPIXEL_ADD(RGB_FROM_RGB888(*pixel, sr, sg, sb), \ + RGB888_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_MOD_RGB888 \ + DRAW_SETPIXEL_MOD(RGB_FROM_RGB888(*pixel, sr, sg, sb), \ + RGB888_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXEL_MUL_RGB888 \ + DRAW_SETPIXEL_MUL(RGB_FROM_RGB888(*pixel, sr, sg, sb), \ + RGB888_FROM_RGB(*pixel, sr, sg, sb)) + +#define DRAW_SETPIXELXY_RGB888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_RGB888) + +#define DRAW_SETPIXELXY_BLEND_RGB888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_RGB888) + +#define DRAW_SETPIXELXY_ADD_RGB888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_ADD_RGB888) + +#define DRAW_SETPIXELXY_MOD_RGB888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MOD_RGB888) + +#define DRAW_SETPIXELXY_MUL_RGB888(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MUL_RGB888) + +/* + * 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_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_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_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_SETPIXELXY4_BLEND_RGB(x, y) \ + DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_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_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_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->format->BytesPerPixel); \ + 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->format->BytesPerPixel); \ + 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->format->BytesPerPixel); \ + 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 currrent 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 currrent 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->format->BytesPerPixel); \ + 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) + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/ps2/SDL_drawline.c b/src/render/ps2/SDL_drawline.c new file mode 100644 index 000000000..15798b462 --- /dev/null +++ b/src/render/ps2/SDL_drawline.c @@ -0,0 +1,213 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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" + +#if SDL_VIDEO_RENDER_PS2 && !SDL_RENDER_DISABLED + +#include "SDL_draw.h" +#include "SDL_drawline.h" +#include "SDL_drawpoint.h" + +#include +#include + +static void +SDL_DrawLine1(SDL_Surface * dst, int x1, int y1, int x2, int y2, Uint32 color, + SDL_bool draw_end) +{ + if (y1 == y2) { + int length; + int pitch = (dst->pitch / dst->format->BytesPerPixel); + 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, + SDL_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_PixelFormat * fmt = dst->format; + SDL_GetRGBA(color, fmt, &_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, + SDL_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_PixelFormat * fmt = dst->format; + SDL_GetRGBA(color, fmt, &_r, &_g, &_b, &_a); + if (fmt->Rmask == 0x00FF0000) { + if (!fmt->Amask) { + AALINE(x1, y1, x2, y2, + DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY_BLEND_RGB888, + 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, SDL_bool draw_end); + +static DrawLineFunc +SDL_CalculateDrawLineFunc(const SDL_PixelFormat * fmt) +{ + switch (fmt->BytesPerPixel) { + case 1: + if (fmt->BitsPerPixel < 8) { + break; + } + return SDL_DrawLine1; + case 2: + return SDL_DrawLine2; + case 4: + return SDL_DrawLine4; + } + + return NULL; +} + +int +SDL_DrawLine(SDL_Surface * dst, int x1, int y1, int x2, int y2, Uint32 color) +{ + DrawLineFunc func; + + if (!dst) { + return SDL_InvalidParamError("SDL_DrawLine(): dst"); + } + + func = SDL_CalculateDrawLineFunc(dst->format); + 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_IntersectRectAndLine(&dst->clip_rect, &x1, &y1, &x2, &y2)) { + return 0; + } + + func(dst, x1, y1, x2, y2, color, SDL_TRUE); + return 0; +} + +int +SDL_DrawLines(SDL_Surface * dst, const SDL_Point * points, int count, + Uint32 color) +{ + int i; + int x1, y1; + int x2, y2; + SDL_bool draw_end; + DrawLineFunc func; + + if (!dst) { + return SDL_InvalidParamError("SDL_DrawLines(): dst"); + } + + func = SDL_CalculateDrawLineFunc(dst->format); + 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_IntersectRectAndLine(&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); + //gsKit_prim_line(dst->userdata, 10.0, 10.0, 15.0, 15.0, 1, GS_SETREG_RGBAQ(0x20,0,0x80,0x80,0x00)); + } + 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 0; +} + +#endif /* SDL_VIDEO_RENDER_SW && !SDL_RENDER_DISABLED */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/ps2/SDL_drawline.h b/src/render/ps2/SDL_drawline.h new file mode 100644 index 000000000..186119e8e --- /dev/null +++ b/src/render/ps2/SDL_drawline.h @@ -0,0 +1,33 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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 int SDL_DrawLine(SDL_Surface * dst, int x1, int y1, int x2, int y2, Uint32 color); +extern int SDL_DrawLines(SDL_Surface * dst, const SDL_Point * points, int count, Uint32 color); + +#endif /* SDL_drawline_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/ps2/SDL_drawpoint.c b/src/render/ps2/SDL_drawpoint.c new file mode 100644 index 000000000..9e1407499 --- /dev/null +++ b/src/render/ps2/SDL_drawpoint.c @@ -0,0 +1,114 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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" + +#if SDL_VIDEO_RENDER_PS2 && !SDL_RENDER_DISABLED + +#include "SDL_draw.h" +#include "SDL_drawpoint.h" + + +int +SDL_DrawPoint(SDL_Surface * dst, int x, int y, Uint32 color) +{ + if (!dst) { + return SDL_InvalidParamError("SDL_DrawPoint(): dst"); + } + + /* This function doesn't work on surfaces < 8 bpp */ + if (dst->format->BitsPerPixel < 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 0; + } + + switch (dst->format->BytesPerPixel) { + 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 0; +} + +int +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 (!dst) { + return SDL_InvalidParamError("SDL_DrawPoints(): dst"); + } + + /* This function doesn't work on surfaces < 8 bpp */ + if (dst->format->BitsPerPixel < 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->format->BytesPerPixel) { + 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 0; +} + +#endif /* SDL_VIDEO_RENDER_SW && !SDL_RENDER_DISABLED */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/ps2/SDL_drawpoint.h b/src/render/ps2/SDL_drawpoint.h new file mode 100644 index 000000000..4c019e014 --- /dev/null +++ b/src/render/ps2/SDL_drawpoint.h @@ -0,0 +1,33 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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 int SDL_DrawPoint(SDL_Surface * dst, int x, int y, Uint32 color); +extern int SDL_DrawPoints(SDL_Surface * dst, const SDL_Point * points, int count, Uint32 color); + +#endif /* SDL_drawpoint_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/ps2/SDL_render_sw.c b/src/render/ps2/SDL_render_sw.c new file mode 100644 index 000000000..70b699498 --- /dev/null +++ b/src/render/ps2/SDL_render_sw.c @@ -0,0 +1,1229 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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" + +#if SDL_VIDEO_RENDER_PS2 && !SDL_RENDER_DISABLED + +#include "../SDL_sysrender.h" +#include "SDL_render_sw_c.h" +#include "SDL_hints.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" + +/* SDL surface based renderer implementation */ + +typedef struct +{ + const SDL_Rect *viewport; + const SDL_Rect *cliprect; + SDL_bool surface_cliprect_dirty; +} PS2_DrawStateCache; + +typedef struct +{ + SDL_Surface *surface; + SDL_Surface *window; +} PS2_RenderData; + + +static GSGLOBAL *gsGlobal = NULL; +static int vsync_sema_id = 0; + + +/* PRIVATE METHODS */ +static int vsync_handler() +{ + iSignalSema(vsync_sema_id); + + ExitHandler(); + return 0; +} + +/* Copy of gsKit_sync_flip, but without the 'flip' */ +static void gsKit_sync(GSGLOBAL *gsGlobal) +{ + if (!gsGlobal->FirstFrame) WaitSema(vsync_sema_id); + while (PollSema(vsync_sema_id) >= 0) + ; +} + +/* Copy of gsKit_sync_flip, but without the 'sync' */ +static void gsKit_flip(GSGLOBAL *gsGlobal) +{ + if (!gsGlobal->FirstFrame) + { + if (gsGlobal->DoubleBuffering == GS_SETTING_ON) + { + GS_SET_DISPFB2( gsGlobal->ScreenBuffer[ + gsGlobal->ActiveBuffer & 1] / 8192, + gsGlobal->Width / 64, gsGlobal->PSM, 0, 0 ); + + gsGlobal->ActiveBuffer ^= 1; + } + + } + + gsKit_setactive(gsGlobal); +} + + +static SDL_Surface * +PS2_ActivateRenderer(SDL_Renderer * renderer) +{ + PS2_RenderData *data = (PS2_RenderData *) renderer->driverdata; + + 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 +PS2_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) +{ + PS2_RenderData *data = (PS2_RenderData *) renderer->driverdata; + + if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) { + data->surface = NULL; + data->window = NULL; + } +} + +static int +PS2_GetOutputSize(SDL_Renderer * renderer, int *w, int *h) +{ + PS2_RenderData *data = (PS2_RenderData *) renderer->driverdata; + + if (data->surface) { + if (w) { + *w = data->surface->w; + } + if (h) { + *h = data->surface->h; + } + return 0; + } + + if (renderer->window) { + SDL_GetWindowSize(renderer->window, w, h); + return 0; + } + + return SDL_SetError("Software renderer doesn't have an output surface"); +} + +static int +PS2_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + int bpp; + Uint32 Rmask, Gmask, Bmask, Amask; + + if (!SDL_PixelFormatEnumToMasks + (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { + return SDL_SetError("Unknown texture format"); + } + + texture->driverdata = + SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask, + Bmask, Amask); + SDL_SetSurfaceColorMod(texture->driverdata, texture->color.r, texture->color.g, texture->color.b); + SDL_SetSurfaceAlphaMod(texture->driverdata, texture->color.a); + SDL_SetSurfaceBlendMode(texture->driverdata, 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 && !Amask) { + SDL_SetSurfaceRLE(texture->driverdata, 1); + } + + if (!texture->driverdata) { + return -1; + } + return 0; +} + +static int +PS2_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, const void *pixels, int pitch) +{ + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + Uint8 *src, *dst; + int row; + size_t length; + + if(SDL_MUSTLOCK(surface)) + SDL_LockSurface(surface); + src = (Uint8 *) pixels; + dst = (Uint8 *) surface->pixels + + rect->y * surface->pitch + + rect->x * surface->format->BytesPerPixel; + length = rect->w * surface->format->BytesPerPixel; + 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 0; +} + +static int +PS2_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, void **pixels, int *pitch) +{ + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + + *pixels = + (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch + + rect->x * surface->format->BytesPerPixel); + *pitch = surface->pitch; + return 0; +} + +static void +PS2_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ +} + +static void +PS2_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode) +{ +} + +static int +PS2_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) +{ + PS2_RenderData *data = (PS2_RenderData *) renderer->driverdata; + + if (texture) { + data->surface = (SDL_Surface *) texture->driverdata; + } else { + data->surface = data->window; + } + return 0; +} + +static int +PS2_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd) +{ + return 0; /* nothing to do in this backend. */ +} + +static int +PS2_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 -1; + } + + cmd->data.draw.count = count; + + for (i = 0; i < count; i++, verts++, points++) { + verts->x = (int)points->x; + verts->y = (int)points->y; + } + + return 0; +} + +static int +PS2_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 -1; + } + + 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 0; +} + +static int +PS2_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture, + const SDL_Rect * 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 -1; + } + + cmd->data.draw.count = 1; + + SDL_copyp(verts, srcrect); + verts++; + + verts->x = (int)dstrect->x; + verts->y = (int)dstrect->y; + verts->w = (int)dstrect->w; + verts->h = (int)dstrect->h; + + return 0; +} + +typedef struct CopyExData +{ + SDL_Rect srcrect; + SDL_Rect dstrect; + double angle; + SDL_FPoint center; + SDL_RendererFlip flip; + float scale_x; + float scale_y; +} CopyExData; + +static int +PS2_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture, + const SDL_Rect * srcrect, const SDL_FRect * dstrect, + const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, float scale_x, float scale_y) +{ + CopyExData *verts = (CopyExData *) SDL_AllocateRenderVertices(renderer, sizeof (CopyExData), 0, &cmd->data.draw.first); + + if (!verts) { + return -1; + } + + cmd->data.draw.count = 1; + + SDL_copyp(&verts->srcrect, srcrect); + + 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 0; +} + +static int +Blit_to_Screen(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *surface, SDL_Rect *dstrect, + float scale_x, float scale_y, SDL_ScaleMode scaleMode) +{ + int retval; + /* 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); + retval = SDL_PrivateUpperBlitScaled(src, srcrect, surface, &r, scaleMode); + } else { + retval = SDL_BlitSurface(src, srcrect, surface, dstrect); + } + return retval; +} + +static int +PS2_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_RendererFlip flip, float scale_x, float scale_y) +{ + SDL_Surface *src = (SDL_Surface *) texture->driverdata; + SDL_Rect tmp_rect; + SDL_Surface *src_clone, *src_rotated, *src_scaled; + SDL_Surface *mask = NULL, *mask_rotated = NULL; + int retval = 0; + SDL_BlendMode blendmode; + Uint8 alphaMod, rMod, gMod, bMod; + int applyModulation = SDL_FALSE; + int blitRequired = SDL_FALSE; + int isOpaque = SDL_FALSE; + + if (!surface) { + return -1; + } + + 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)) { + SDL_LockSurface(src); + } + + /* Clone the source surface but use its pixel buffer directly. + * The original source surface must be treated as read-only. + */ + src_clone = SDL_CreateRGBSurfaceFrom(src->pixels, src->w, src->h, src->format->BitsPerPixel, src->pitch, + src->format->Rmask, src->format->Gmask, + src->format->Bmask, src->format->Amask); + if (src_clone == NULL) { + if (SDL_MUSTLOCK(src)) { + SDL_UnlockSurface(src); + } + return -1; + } + + 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->format->BitsPerPixel != 32 || SDL_PIXELLAYOUT(src->format->format) != SDL_PACKEDLAYOUT_8888 || !src->format->Amask) { + blitRequired = SDL_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 = SDL_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 = SDL_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 = SDL_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 && !src->format->Amask && alphaMod == 255) { + isOpaque = SDL_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_CreateRGBSurface(0, final_rect->w, final_rect->h, 32, + 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); + if (mask == NULL) { + retval = -1; + } 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 (!retval && (blitRequired || applyModulation)) { + SDL_Rect scale_rect = tmp_rect; + src_scaled = SDL_CreateRGBSurface(0, final_rect->w, final_rect->h, 32, + 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); + if (src_scaled == NULL) { + retval = -1; + } else { + SDL_SetSurfaceBlendMode(src_clone, SDL_BLENDMODE_NONE); + retval = SDL_PrivateUpperBlitScaled(src_clone, srcrect, src_scaled, &scale_rect, texture->scaleMode); + SDL_FreeSurface(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 (!retval) { + 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_ScaleModeNearest) ? 0 : 1, flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, + &rect_dest, cangle, sangle, center); + if (src_rotated == NULL) { + retval = -1; + } + if (!retval && mask != NULL) { + /* The mask needed for the NONE blend mode gets rotated with the same parameters. */ + mask_rotated = SDLgfx_rotateSurface(mask, angle, + SDL_FALSE, 0, 0, + &rect_dest, cangle, sangle, center); + if (mask_rotated == NULL) { + retval = -1; + } + } + if (!retval) { + + 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 == SDL_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 */ + retval = 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 */ + retval = Blit_to_Screen(mask_rotated, NULL, surface, &mask_rect, scale_x, scale_y, texture->scaleMode); + if (!retval) { + /* 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 */ + retval = Blit_to_Screen(src_rotated, NULL, surface, &mask_rect, scale_x, scale_y, texture->scaleMode); + if (!retval) { + /* 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; + src_rotated_rgb = SDL_CreateRGBSurfaceFrom(src_rotated->pixels, src_rotated->w, src_rotated->h, + src_rotated->format->BitsPerPixel, src_rotated->pitch, + src_rotated->format->Rmask, src_rotated->format->Gmask, + src_rotated->format->Bmask, 0); + if (src_rotated_rgb == NULL) { + retval = -1; + } else { + SDL_SetSurfaceBlendMode(src_rotated_rgb, SDL_BLENDMODE_ADD); + /* Renderer scaling, if needed */ + retval = Blit_to_Screen(src_rotated_rgb, NULL, surface, &tmp_rect, scale_x, scale_y, texture->scaleMode); + SDL_FreeSurface(src_rotated_rgb); + } + } + } + SDL_FreeSurface(mask_rotated); + } + if (src_rotated != NULL) { + SDL_FreeSurface(src_rotated); + } + } + } + + if (SDL_MUSTLOCK(src)) { + SDL_UnlockSurface(src); + } + if (mask != NULL) { + SDL_FreeSurface(mask); + } + if (src_clone != NULL) { + SDL_FreeSurface(src_clone); + } + return retval; +} + + +typedef struct GeometryFillData +{ + SDL_Point dst; + SDL_Color color; +} GeometryFillData; + +typedef struct GeometryCopyData +{ + SDL_Point src; + SDL_Point dst; + SDL_Color color; +} GeometryCopyData; + +static int +PS2_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, + const float *xy, int xy_stride, const SDL_Color *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; + int sz = texture ? sizeof (GeometryCopyData) : sizeof (GeometryFillData); + + verts = (void *) SDL_AllocateRenderVertices(renderer, count * sz, 0, &cmd->data.draw.first); + if (!verts) { + return -1; + } + + 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_Color 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_Color *)((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 = col_; + + ptr++; + } + } else { + GeometryFillData *ptr = (GeometryFillData *) verts; + + for (i = 0; i < count; i++) { + int j; + float *xy_; + SDL_Color 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_Color *)((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 = col_; + + ptr++; + } + } + return 0; +} + +static void +PrepTextureForCopy(const SDL_RenderCommand *cmd) +{ + const Uint8 r = cmd->data.draw.r; + const Uint8 g = cmd->data.draw.g; + const Uint8 b = cmd->data.draw.b; + const Uint8 a = cmd->data.draw.a; + const SDL_BlendMode blend = cmd->data.draw.blend; + SDL_Texture *texture = cmd->data.draw.texture; + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + const SDL_bool colormod = ((r & g & b) != 0xFF); + const SDL_bool alphamod = (a != 0xFF); + const SDL_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, PS2_DrawStateCache *drawstate) +{ + if (drawstate->surface_cliprect_dirty) { + const SDL_Rect *viewport = drawstate->viewport; + const SDL_Rect *cliprect = drawstate->cliprect; + SDL_assert(viewport != NULL); /* the higher level should have forced a SDL_RENDERCMD_SETVIEWPORT */ + + if (cliprect != NULL) { + 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_IntersectRect(viewport, &clip_rect, &clip_rect); + SDL_SetClipRect(surface, &clip_rect); + } else { + SDL_SetClipRect(surface, drawstate->viewport); + } + drawstate->surface_cliprect_dirty = SDL_FALSE; + } +} + +static int +PS2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) +{ + SDL_Surface *surface = PS2_ActivateRenderer(renderer); + PS2_DrawStateCache drawstate; + + if (!surface) { + return -1; + } + + drawstate.viewport = NULL; + drawstate.cliprect = NULL; + drawstate.surface_cliprect_dirty = SDL_TRUE; + + while (cmd) { + switch (cmd->command) { + case SDL_RENDERCMD_SETDRAWCOLOR: { + break; /* Not used in this backend. */ + } + + case SDL_RENDERCMD_SETVIEWPORT: { + drawstate.viewport = &cmd->data.viewport.rect; + drawstate.surface_cliprect_dirty = SDL_TRUE; + break; + } + + case SDL_RENDERCMD_SETCLIPRECT: { + drawstate.cliprect = cmd->data.cliprect.enabled ? &cmd->data.cliprect.rect : NULL; + drawstate.surface_cliprect_dirty = SDL_TRUE; + break; + } + + case SDL_RENDERCMD_CLEAR: { + const Uint8 r = cmd->data.color.r; + const Uint8 g = cmd->data.color.g; + const Uint8 b = cmd->data.color.b; + const Uint8 a = cmd->data.color.a; + gsKit_clear(gsGlobal, GS_SETREG_RGBAQ(r,g,b,a/2,0x00)); + drawstate.surface_cliprect_dirty = SDL_TRUE; + break; + } + + case SDL_RENDERCMD_DRAW_POINTS: { + const Uint8 r = cmd->data.draw.r; + const Uint8 g = cmd->data.draw.g; + const Uint8 b = cmd->data.draw.b; + const Uint8 a = cmd->data.draw.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->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_MapRGBA(surface->format, r, g, b, a)); + } else { + SDL_BlendPoints(surface, verts, count, blend, r, g, b, a); + } + break; + } + + case SDL_RENDERCMD_DRAW_LINES: { + const Uint8 r = cmd->data.draw.r; + const Uint8 g = cmd->data.draw.g; + const Uint8 b = cmd->data.draw.b; + const Uint8 a = cmd->data.draw.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->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_MapRGBA(surface->format, r, g, b, a)); + } else { + SDL_BlendLines(surface, verts, count, blend, r, g, b, a); + } + + break; + } + + case SDL_RENDERCMD_FILL_RECTS: { + const Uint8 r = cmd->data.draw.r; + const Uint8 g = cmd->data.draw.g; + const Uint8 b = cmd->data.draw.b; + const Uint8 a = cmd->data.draw.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->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_FillRects(surface, verts, count, SDL_MapRGBA(surface->format, 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->driverdata; + + SetDrawState(surface, &drawstate); + + PrepTextureForCopy(cmd); + + /* Apply viewport */ + if (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_CreateRGBSurfaceWithFormat(0, dstrect->w, dstrect->h, 0, src->format->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_PrivateUpperBlitScaled(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_FreeSurface(tmp); + /* No need to set back r/g/b/a/blendmode to 'src' since it's done in PrepTextureForCopy() */ + } + } else{ + SDL_PrivateUpperBlitScaled(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); + + /* Apply viewport */ + if (drawstate.viewport->x || drawstate.viewport->y) { + copydata->dstrect.x += drawstate.viewport->x; + copydata->dstrect.y += drawstate.viewport->y; + } + + PS2_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->driverdata; + + GeometryCopyData *ptr = (GeometryCopyData *) verts; + + PrepTextureForCopy(cmd); + + /* Apply viewport */ + if (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_PS2_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); + } + } else { + GeometryFillData *ptr = (GeometryFillData *) verts; + + /* Apply viewport */ + if (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_PS2_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 0; +} + +static int +PS2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, + Uint32 format, void * pixels, int pitch) +{ + SDL_Surface *surface = PS2_ActivateRenderer(renderer); + Uint32 src_format; + void *src_pixels; + + if (!surface) { + return -1; + } + + /* 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) { + return SDL_SetError("Tried to read outside of surface bounds"); + } + + src_format = surface->format->format; + src_pixels = (void*)((Uint8 *) surface->pixels + + rect->y * surface->pitch + + rect->x * surface->format->BytesPerPixel); + + return SDL_ConvertPixels(rect->w, rect->h, + src_format, src_pixels, surface->pitch, + format, pixels, pitch); +} + +static void +PS2_RenderPresent(SDL_Renderer * renderer) +{ + SDL_Window *window = renderer->window; + + if (window) { + SDL_UpdateWindowSurface(window); + } + if (gsGlobal->DoubleBuffering == GS_SETTING_OFF) { + gsKit_sync(gsGlobal); + gsKit_queue_exec(gsGlobal); + } else { + gsKit_queue_exec(gsGlobal); + gsKit_finish(); + gsKit_sync(gsGlobal); + gsKit_flip(gsGlobal); + } + gsKit_TexManager_nextFrame(gsGlobal); +} + +static void +PS2_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + + SDL_FreeSurface(surface); +} + +static void +PS2_DestroyRenderer(SDL_Renderer * renderer) +{ + PS2_RenderData *data = (PS2_RenderData *) renderer->driverdata; + + SDL_free(data); + SDL_free(renderer); +} + +SDL_Renderer * +PS2_CreateRendererForSurface(SDL_Surface * surface) +{ + SDL_Renderer *renderer; + PS2_RenderData *data; + + if (!surface) { + SDL_InvalidParamError("surface"); + return NULL; + } + + renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); + if (!renderer) { + SDL_OutOfMemory(); + return NULL; + } + + data = (PS2_RenderData *) SDL_calloc(1, sizeof(*data)); + if (!data) { + PS2_DestroyRenderer(renderer); + SDL_OutOfMemory(); + return NULL; + } + data->surface = surface; + data->window = surface; + + renderer->WindowEvent = PS2_WindowEvent; + renderer->GetOutputSize = PS2_GetOutputSize; + renderer->CreateTexture = PS2_CreateTexture; + renderer->UpdateTexture = PS2_UpdateTexture; + renderer->LockTexture = PS2_LockTexture; + renderer->UnlockTexture = PS2_UnlockTexture; + renderer->SetTextureScaleMode = PS2_SetTextureScaleMode; + renderer->SetRenderTarget = PS2_SetRenderTarget; + renderer->QueueSetViewport = PS2_QueueSetViewport; + renderer->QueueSetDrawColor = PS2_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */ + renderer->QueueDrawPoints = PS2_QueueDrawPoints; + renderer->QueueDrawLines = PS2_QueueDrawPoints; /* lines and points queue vertices the same way. */ + renderer->QueueFillRects = PS2_QueueFillRects; + renderer->QueueCopy = PS2_QueueCopy; + renderer->QueueCopyEx = PS2_QueueCopyEx; + renderer->QueueGeometry = PS2_QueueGeometry; + renderer->RunCommandQueue = PS2_RunCommandQueue; + renderer->RenderReadPixels = PS2_RenderReadPixels; + renderer->RenderPresent = PS2_RenderPresent; + renderer->DestroyTexture = PS2_DestroyTexture; + renderer->DestroyRenderer = PS2_DestroyRenderer; + renderer->info = PS2_RenderDriver.info; + renderer->driverdata = data; + + PS2_ActivateRenderer(renderer); + + return renderer; +} + +static SDL_Renderer * +PS2_CreateRenderer(SDL_Window * window, Uint32 flags) +{ + const char *hint; + SDL_Surface *surface; + SDL_bool no_hint_set; + + /* Set the vsync hint based on our flags, if it's not already set */ + hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC); + if (!hint || !*hint) { + no_hint_set = SDL_TRUE; + } else { + no_hint_set = SDL_FALSE; + } + + if (no_hint_set) { + SDL_SetHint(SDL_HINT_RENDER_VSYNC, (flags & SDL_RENDERER_PRESENTVSYNC) ? "1" : "0"); + } + + surface = SDL_GetWindowSurface(window); + + /* Reset the vsync hint if we set it above */ + if (no_hint_set) { + SDL_SetHint(SDL_HINT_RENDER_VSYNC, ""); + } + + ee_sema_t sema; + sema.init_count = 0; + sema.max_count = 1; + sema.option = 0; + vsync_sema_id = CreateSema(&sema); + + gsGlobal = gsKit_init_global(); + + gsGlobal->Mode = gsKit_check_rom(); + if (gsGlobal->Mode == GS_MODE_PAL){ + gsGlobal->Height = 512; + } else { + gsGlobal->Height = 448; + } + + gsGlobal->PSM = GS_PSM_CT24; + gsGlobal->PSMZ = GS_PSMZ_16S; + gsGlobal->ZBuffering = GS_SETTING_OFF; + gsGlobal->DoubleBuffering = GS_SETTING_ON; + gsGlobal->PrimAlphaEnable = GS_SETTING_ON; + gsGlobal->Dithering = GS_SETTING_OFF; + + gsKit_set_primalpha(gsGlobal, GS_SETREG_ALPHA(0, 1, 0, 1, 0), 0); + + dmaKit_init(D_CTRL_RELE_OFF, D_CTRL_MFD_OFF, D_CTRL_STS_UNSPEC, D_CTRL_STD_OFF, D_CTRL_RCYC_8, 1 << DMA_CHANNEL_GIF); + dmaKit_chan_init(DMA_CHANNEL_GIF); + + printf("\nGraphics: created %ix%i video surface\n", + gsGlobal->Width, gsGlobal->Height); + + gsKit_set_clamp(gsGlobal, GS_CMODE_REPEAT); + + gsKit_vram_clear(gsGlobal); + + gsKit_init_screen(gsGlobal); + + gsKit_TexManager_init(gsGlobal); + + gsKit_add_vsync_handler(vsync_handler); + + gsKit_mode_switch(gsGlobal, GS_ONESHOT); + + gsKit_clear(gsGlobal, GS_SETREG_RGBAQ(0x80,0x00,0x00,0x80,0x00)); + + if (gsGlobal->DoubleBuffering == GS_SETTING_OFF) { + gsKit_sync(gsGlobal); + gsKit_queue_exec(gsGlobal); + } else { + gsKit_queue_exec(gsGlobal); + gsKit_finish(); + gsKit_sync(gsGlobal); + gsKit_flip(gsGlobal); + } + gsKit_TexManager_nextFrame(gsGlobal); + + surface->userdata = gsGlobal; + + if (!surface) { + return NULL; + } + return PS2_CreateRendererForSurface(surface); +} + +SDL_RenderDriver PS2_RenderDriver = { + PS2_CreateRenderer, + { + "PS2 gsKit", + SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE, + 8, + { + SDL_PIXELFORMAT_ARGB8888, + SDL_PIXELFORMAT_ABGR8888, + SDL_PIXELFORMAT_RGBA8888, + SDL_PIXELFORMAT_BGRA8888, + SDL_PIXELFORMAT_RGB888, + SDL_PIXELFORMAT_BGR888, + SDL_PIXELFORMAT_RGB565, + SDL_PIXELFORMAT_RGB555 + }, + .max_texture_width = 512, + .max_texture_height = 512,} +}; + +#endif /* SDL_VIDEO_RENDER_PS2 && !SDL_RENDER_DISABLED */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/ps2/SDL_render_sw_c.h b/src/render/ps2/SDL_render_sw_c.h new file mode 100644 index 000000000..e4812d3df --- /dev/null +++ b/src/render/ps2/SDL_render_sw_c.h @@ -0,0 +1,37 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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_ + +#include + +#include +#include + +#include +#include + +extern SDL_Renderer * SW_CreateRendererForSurface(SDL_Surface * surface); + +#endif /* SDL_render_sw_c_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/ps2/SDL_rotate.c b/src/render/ps2/SDL_rotate.c new file mode 100644 index 000000000..e35a5ebea --- /dev/null +++ b/src/render/ps2/SDL_rotate.c @@ -0,0 +1,577 @@ +/* + +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" + +#if SDL_VIDEO_RENDER_PS2 && !SDL_RENDER_DISABLED + +#if defined(__WIN32__) || defined(__GDK__) +#include "../../core/windows/SDL_windows.h" +#endif + +#include +#include + +#include "SDL.h" +#include "SDL_rotate.h" + +/* ---- Internally used structures */ + +/* ! +\brief A 32 bit RGBA pixel. +*/ +typedef struct tColorRGBA { + Uint8 r; + Uint8 g; + Uint8 b; + Uint8 a; +} tColorRGBA; + +/* ! +\brief A 8bit Y/palette pixel. +*/ +typedef struct tColorY { + Uint8 y; +} tColorY; + +/* ! +\brief 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) + +/* ! +\brief Returns colorkey info for a surface +*/ +static Uint32 +get_colorkey(SDL_Surface *src) +{ + Uint32 key = 0; + if (SDL_HasColorKey(src)) { + SDL_GetColorKey(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; +} + +/* ! +\brief 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 dstwidth The calculated width of the destination surface. +\param dstheight The calculated height of the destination surface. +\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 * (M_PI / 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 + +/* ! +\brief 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 dst_rect 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 = (rect_dest->x + 0 + 0.5 - center->x); + double src_y = (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 = (((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 = (((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 = (((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 = (((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 = (rect_dest->x + 0 + 0.5 - center->x); + double src_y = (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); + } + } +} + +/* ! + +\brief 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 dst_rect 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), dst->pitch * dst->h); + /* + * Iterate through destination surface + */ + for (y = 0; y < dst->h; y++) { + int x; + double src_x = (rect_dest->x + 0 + 0.5 - center->x); + double src_y = (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; + } +} + + +/* ! +\brief 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 zoomy The vertical coordinate of the center of rotation +\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; + int i; + SDL_BlendMode blendmode; + Uint32 colorkey = 0; + int colorKeyAvailable = SDL_FALSE; + double sangleinv, cangleinv; + + /* Sanity check */ + if (src == NULL) + return NULL; + + if (SDL_HasColorKey(src)) { + if (SDL_GetColorKey(src, &colorkey) == 0) { + colorKeyAvailable = SDL_TRUE; + } + } + /* This function requires a 32-bit surface or 8-bit surface with a colorkey */ + is8bit = src->format->BitsPerPixel == 8 && colorKeyAvailable; + if (!(is8bit || (src->format->BitsPerPixel == 32 && src->format->Amask))) + 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_CreateRGBSurfaceWithFormat(0, rect_dest->w, rect_dest->h + GUARD_ROWS, 8, src->format->format); + if (rz_dst != NULL) { + if (src->format->palette) { + for (i = 0; i < src->format->palette->ncolors; i++) { + rz_dst->format->palette->colors[i] = src->format->palette->colors[i]; + } + rz_dst->format->palette->ncolors = src->format->palette->ncolors; + } + } + } else { + /* Target surface is 32 bit with source RGBA ordering */ + rz_dst = SDL_CreateRGBSurface(0, rect_dest->w, rect_dest->h + GUARD_ROWS, 32, + src->format->Rmask, src->format->Gmask, + src->format->Bmask, src->format->Amask); + } + + /* Check target */ + if (rz_dst == NULL) + return NULL; + + /* Adjust for guard rows */ + rz_dst->h = rect_dest->h; + + SDL_GetSurfaceBlendMode(src, &blendmode); + + if (colorKeyAvailable == SDL_TRUE) { + /* If available, the colorkey will be used to discard the pixels that are outside of the rotated area. */ + SDL_SetColorKey(rz_dst, SDL_TRUE, colorkey); + SDL_FillRect(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_MapRGBA(rz_dst->format, 255, 255, 255, 0); + SDL_FillRect(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_SetColorKey(rz_dst, SDL_TRUE, colorkey); + } + + SDL_SetSurfaceBlendMode(rz_dst, blendmode); + + /* Lock source surface */ + if (SDL_MUSTLOCK(src)) { + SDL_LockSurface(src); + } + + /* 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 && !SDL_RENDER_DISABLED */ diff --git a/src/render/ps2/SDL_rotate.h b/src/render/ps2/SDL_rotate.h new file mode 100644 index 000000000..8d7ec9d28 --- /dev/null +++ b/src/render/ps2/SDL_rotate.h @@ -0,0 +1,30 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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/src/render/ps2/SDL_triangle.c b/src/render/ps2/SDL_triangle.c new file mode 100644 index 000000000..a7bc2058d --- /dev/null +++ b/src/render/ps2/SDL_triangle.c @@ -0,0 +1,888 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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" + +#if SDL_VIDEO_RENDER_PS2 && !SDL_RENDER_DISABLED + +#include "SDL_surface.h" +#include "SDL_triangle.h" + +#include "../../video/SDL_blit.h" + +/* fixed points bits precision + * Set to 1, so that it can start rendering wth 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, int is_uniform); + +#if 0 +int 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 -1; + } + + 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); +} + +int SDL_FillTriangle(SDL_Surface *dst, const SDL_Point points[3], Uint32 color) +{ + int i; + SDL_Point points_tmp[3]; + if (dst == NULL) { + return -1; + } + 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 int cross_product(const SDL_Point *a, const SDL_Point *b, int c_x, int c_y) +{ + return (b->x - a->x) * (c_y - a->y) - (b->y - a->y) * (c_x - a->x); +} + +/* check for top left rules */ +static int 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 1; + } + if (b->y < a->y) { + return 1; + } + } else { + if (a->y == b->y && b->x < a->x) { + return 1; + } + if (a->y < b->y) { + return 1; + } + } + return 0; +} + +void trianglepoint_2_fixedpoint(SDL_Point *a) { + a->x <<= FP_BITS; + a->y <<= FP_BITS; +} + +/* 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 */ \ + int w0 = w0_row; \ + int w1 = w1_row; \ + int 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); \ + +#define TRIANGLE_GET_MAPPED_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); \ + int color = SDL_MapRGBA(format, 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; \ + } \ + } \ + +int 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) +{ + int ret = 0; + int dst_locked = 0; + + SDL_Rect dstrect; + + int dstbpp; + Uint8 *dst_ptr; + int dst_pitch; + + int area, is_clockwise; + + int d2d1_y, d1d2_x, d0d2_y, d2d0_x, d1d0_y, d0d1_x; + int w0_row, w1_row, w2_row; + int bias_w0, bias_w1, bias_w2; + + int is_uniform; + + SDL_Surface *tmp = NULL; + + if (dst == NULL) { + return -1; + } + + 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 0; + } + + /* Lock the destination, if needed */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + ret = -1; + 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_IntersectRect(&dstrect, &rect, &dstrect); + } + + { + /* Clip triangle with surface clip rect */ + SDL_Rect rect; + SDL_GetClipRect(dst, &rect); + SDL_IntersectRect(&dstrect, &rect, &dstrect); + } + + + if (blend != SDL_BLENDMODE_NONE) { + int format = dst->format->format; + + /* need an alpha format */ + if (! dst->format->Amask) { + format = SDL_PIXELFORMAT_ARGB8888; + } + + /* Use an intermediate surface */ + tmp = SDL_CreateRGBSurfaceWithFormat(0, dstrect.w, dstrect.h, 0, format); + if (tmp == NULL) { + ret = -1; + goto end; + } + + if (blend == SDL_BLENDMODE_MOD) { + Uint32 c = SDL_MapRGBA(tmp->format, 255, 255, 255, 255); + SDL_FillRect(tmp, NULL, c); + } + + SDL_SetSurfaceBlendMode(tmp, blend); + + dstbpp = tmp->format->BytesPerPixel; + dst_ptr = tmp->pixels; + dst_pitch = tmp->pitch; + + } else { + /* Write directly to destination surface */ + dstbpp = dst->format->BytesPerPixel; + dst_ptr = (Uint8 *)dst->pixels + dstrect.x * dstbpp + dstrect.y * dst->pitch; + dst_pitch = dst->pitch; + } + + is_clockwise = area > 0; + area = SDL_abs(area); + + d2d1_y = (d1->y - d2->y) << FP_BITS; + d0d2_y = (d2->y - d0->y) << FP_BITS; + d1d0_y = (d0->y - d1->y) << FP_BITS; + d1d2_x = (d2->x - d1->x) << FP_BITS; + d2d0_x = (d0->x - d2->x) << FP_BITS; + d0d1_x = (d1->x - d0->x) << FP_BITS; + + /* 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) { + if (dst->format->Amask) { + color = SDL_MapRGBA(tmp->format, c0.r, c0.g, c0.b, c0.a); + } else { + //color = SDL_MapRGB(tmp->format, c0.r, c0.g, c0.b); + color = SDL_MapRGBA(tmp->format, c0.r, c0.g, c0.b, c0.a); + } + } else { + color = SDL_MapRGBA(dst->format, 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 = color; + } + TRIANGLE_END_LOOP + } else if (dstbpp == 1) { + TRIANGLE_BEGIN_LOOP + { + *dptr = color; + } + TRIANGLE_END_LOOP + } + } else { + SDL_PixelFormat *format = dst->format; + if (tmp) { + format = tmp->format; + } + 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 = color; + } + TRIANGLE_END_LOOP + } else if (dstbpp == 1) { + TRIANGLE_BEGIN_LOOP + { + TRIANGLE_GET_MAPPED_COLOR + *dptr = color; + } + TRIANGLE_END_LOOP + } + } + + if (tmp) { + SDL_BlitSurface(tmp, NULL, dst, &dstrect); + SDL_FreeSurface(tmp); + } + +end: + if (dst_locked) { + SDL_UnlockSurface(dst); + } + + return ret; +} + + + + + + + +int 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) +{ + int ret = 0; + 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; + + int *src_ptr; + int src_pitch; + + int area, is_clockwise; + + int d2d1_y, d1d2_x, d0d2_y, d2d0_x, d1d0_y, d0d1_x; + int s2s0_x, s2s1_x, s2s0_y, s2s1_y; + + int w0_row, w1_row, w2_row; + int bias_w0, bias_w1, bias_w2; + + int is_uniform; + + int has_modulation; + + if (src == NULL || dst == NULL) { + return -1; + } + + area = cross_product(d0, d1, d2->x, d2->y); + + /* Flat triangle */ + if (area == 0) { + return 0; + } + + /* Lock the destination, if needed */ + if (SDL_MUSTLOCK(dst)) { + if (SDL_LockSurface(dst) < 0) { + ret = -1; + goto end; + } else { + dst_locked = 1; + } + } + + /* Lock the source, if needed */ + if (SDL_MUSTLOCK(src)) { + if (SDL_LockSurface(src) < 0) { + ret = -1; + 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 */ + { + 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 = SDL_TRUE; + } + + { + /* Clip triangle rect with surface rect */ + SDL_Rect rect; + rect.x = 0; + rect.y = 0; + rect.w = dst->w; + rect.h = dst->h; + + SDL_IntersectRect(&dstrect, &rect, &dstrect); + } + + { + /* Clip triangle with surface clip rect */ + SDL_Rect rect; + SDL_GetClipRect(dst, &rect); + SDL_IntersectRect(&dstrect, &rect, &dstrect); + } + + /* Set destination pointer */ + dstbpp = dst->format->BytesPerPixel; + dst_ptr = (Uint8 *)dst->pixels + dstrect.x * dstbpp + dstrect.y * dst->pitch; + dst_pitch = dst->pitch; + + /* Set source pointer */ + src_ptr = src->pixels; + src_pitch = src->pitch; + + is_clockwise = area > 0; + area = SDL_abs(area); + + d2d1_y = (d1->y - d2->y) << FP_BITS; + d0d2_y = (d2->y - d0->y) << FP_BITS; + d1d0_y = (d0->y - d1->y) << FP_BITS; + + + d1d2_x = (d2->x - d1->x) << FP_BITS; + d2d0_x = (d0->x - d2->x) << FP_BITS; + d0d1_x = (d1->x - d0->x) << FP_BITS; + + 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 */ + s2_x_area.x = s2->x * area; + s2_x_area.y = s2->y * area; + + if (blend != SDL_BLENDMODE_NONE || src->format->format != dst->format->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->format; + tmp_info.dst_fmt = dst->format; + 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 = (Uint8 *) src_ptr; + tmp_info.src_pitch = src_pitch; + + /* dst */ + tmp_info.dst = (Uint8 *) dst_ptr; + tmp_info.dst_pitch = dst_pitch; + + SDL_BlitTriangle_Slow(&tmp_info, s2_x_area, dstrect, 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, w0_row, w1_row, w2_row, + c0, c1, c2, is_uniform); + + 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 *)((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 *)((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 ret; +} + + +#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 SDL_INLINE detect_format(SDL_PixelFormat *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, int is_uniform) +{ + 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; + SDL_PixelFormat *src_fmt = info->src_fmt; + SDL_PixelFormat *dst_fmt = info->dst_fmt; + int srcbpp = src_fmt->BytesPerPixel; + int dstbpp = dst_fmt->BytesPerPixel; + 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 (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); + } + + 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; + dstA = ((srcA * dstA) + (dstA * (255 - srcA))) / 255; + if (dstA > 255) + dstA = 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 && !SDL_RENDER_DISABLED */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/ps2/SDL_triangle.h b/src/render/ps2/SDL_triangle.h new file mode 100644 index 000000000..c120b39cf --- /dev/null +++ b/src/render/ps2/SDL_triangle.h @@ -0,0 +1,42 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 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" + +extern int 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 int 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); + +extern void trianglepoint_2_fixedpoint(SDL_Point *a); + +#endif /* SDL_triangle_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/ps2/SDL_ps2video.c b/src/video/ps2/SDL_ps2video.c index ed666ddee..ff9613fd8 100644 --- a/src/video/ps2/SDL_ps2video.c +++ b/src/video/ps2/SDL_ps2video.c @@ -57,9 +57,6 @@ static void PS2_VideoQuit(_THIS); /* PS2 driver bootstrap functions */ -static GSGLOBAL *gsGlobal = NULL; -static int vsync_sema_id = 0; - static void PS2_DeleteDevice(SDL_VideoDevice * device) { @@ -98,46 +95,10 @@ VideoBootStrap PS2_bootstrap = { PS2_CreateDevice }; - -/* PRIVATE METHODS */ -static int vsync_handler() -{ - iSignalSema(vsync_sema_id); - - ExitHandler(); - return 0; -} - -/* Copy of gsKit_sync_flip, but without the 'flip' */ -static void gsKit_sync(GSGLOBAL *gsGlobal) -{ - if (!gsGlobal->FirstFrame) WaitSema(vsync_sema_id); - while (PollSema(vsync_sema_id) >= 0) - ; -} - -/* Copy of gsKit_sync_flip, but without the 'sync' */ -static void gsKit_flip(GSGLOBAL *gsGlobal) -{ - if (!gsGlobal->FirstFrame) - { - if (gsGlobal->DoubleBuffering == GS_SETTING_ON) - { - GS_SET_DISPFB2( gsGlobal->ScreenBuffer[ - gsGlobal->ActiveBuffer & 1] / 8192, - gsGlobal->Width / 64, gsGlobal->PSM, 0, 0 ); - - gsGlobal->ActiveBuffer ^= 1; - } - - } - - gsKit_setactive(gsGlobal); -} - int PS2_VideoInit(_THIS) { + /* ee_sema_t sema; sema.init_count = 0; sema.max_count = 1; @@ -192,6 +153,7 @@ PS2_VideoInit(_THIS) gsKit_flip(gsGlobal); } gsKit_TexManager_nextFrame(gsGlobal); + */ SDL_DisplayMode mode; @@ -199,11 +161,12 @@ PS2_VideoInit(_THIS) SDL_zero(mode); mode.format = SDL_PIXELFORMAT_RGB888; mode.w = 640; - if (gsGlobal->Mode == GS_MODE_PAL){ + /*if (gsGlobal->Mode == GS_MODE_PAL){ mode.h = 512; } else { mode.h = 448; - } + }*/ + mode.h = 448; mode.refresh_rate = 60; mode.driverdata = NULL; if (SDL_AddBasicVideoDisplay(&mode) < 0) { @@ -234,41 +197,13 @@ SDL_to_PS2_PFM(Uint32 format) static int PS2_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) { - gsGlobal->Mode = GS_MODE_NTSC; - gsGlobal->Width = mode->w; - if ((gsGlobal->Interlace == GS_INTERLACED) && (gsGlobal->Field == GS_FRAME)) - gsGlobal->Height = mode->h / 2; - else - gsGlobal->Height = mode->h; - - gsGlobal->PSM = SDL_to_PS2_PFM(mode->format); - gsGlobal->PSMZ = GS_PSMZ_16S; - - gsGlobal->ZBuffering = GS_SETTING_OFF; - gsGlobal->DoubleBuffering = GS_SETTING_ON; - gsGlobal->PrimAlphaEnable = GS_SETTING_ON; - gsGlobal->Dithering = GS_SETTING_OFF; - - gsGlobal->Interlace = GS_INTERLACED; - gsGlobal->Field = GS_FIELD; - - gsKit_set_primalpha(gsGlobal, GS_SETREG_ALPHA(0, 1, 0, 1, 0), 0); - - gsKit_set_clamp(gsGlobal, GS_CMODE_REPEAT); - gsKit_vram_clear(gsGlobal); - gsKit_init_screen(gsGlobal); - gsKit_set_display_offset(gsGlobal, -0.5f, -0.5f); - gsKit_sync_flip(gsGlobal); - - gsKit_mode_switch(gsGlobal, GS_ONESHOT); - gsKit_clear(gsGlobal, GS_SETREG_RGBAQ(0x00,0x00,0x00,0x80,0x00)); return 0; } void PS2_VideoQuit(_THIS) { - gsKit_deinit_global(gsGlobal); + /*gsKit_deinit_global(gsGlobal);*/ } #endif /* SDL_VIDEO_DRIVER_PS2 */