This commit is contained in:
Nitload
2025-08-25 09:50:30 +08:00
parent bd0e31e922
commit 1359ff4ecc
1630 changed files with 738486 additions and 2399 deletions
@@ -0,0 +1,371 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_RENDER_SW
#include "SDL_draw.h"
#include "SDL_blendfillrect.h"
static bool SDL_BlendFillRect_RGB555(SDL_Surface *dst, const SDL_Rect *rect,
SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
unsigned inva = 0xff - a;
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB555);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB555);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
FILLRECT(Uint16, DRAW_SETPIXEL_ADD_RGB555);
break;
case SDL_BLENDMODE_MOD:
FILLRECT(Uint16, DRAW_SETPIXEL_MOD_RGB555);
break;
case SDL_BLENDMODE_MUL:
FILLRECT(Uint16, DRAW_SETPIXEL_MUL_RGB555);
break;
default:
FILLRECT(Uint16, DRAW_SETPIXEL_RGB555);
break;
}
return true;
}
static bool SDL_BlendFillRect_RGB565(SDL_Surface *dst, const SDL_Rect *rect,
SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
unsigned inva = 0xff - a;
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB565);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB565);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
FILLRECT(Uint16, DRAW_SETPIXEL_ADD_RGB565);
break;
case SDL_BLENDMODE_MOD:
FILLRECT(Uint16, DRAW_SETPIXEL_MOD_RGB565);
break;
case SDL_BLENDMODE_MUL:
FILLRECT(Uint16, DRAW_SETPIXEL_MUL_RGB565);
break;
default:
FILLRECT(Uint16, DRAW_SETPIXEL_RGB565);
break;
}
return true;
}
static bool SDL_BlendFillRect_XRGB8888(SDL_Surface *dst, const SDL_Rect *rect,
SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
unsigned inva = 0xff - a;
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_XRGB8888);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
FILLRECT(Uint32, DRAW_SETPIXEL_ADD_XRGB8888);
break;
case SDL_BLENDMODE_MOD:
FILLRECT(Uint32, DRAW_SETPIXEL_MOD_XRGB8888);
break;
case SDL_BLENDMODE_MUL:
FILLRECT(Uint32, DRAW_SETPIXEL_MUL_XRGB8888);
break;
default:
FILLRECT(Uint32, DRAW_SETPIXEL_XRGB8888);
break;
}
return true;
}
static bool SDL_BlendFillRect_ARGB8888(SDL_Surface *dst, const SDL_Rect *rect,
SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
unsigned inva = 0xff - a;
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
FILLRECT(Uint32, DRAW_SETPIXEL_ADD_ARGB8888);
break;
case SDL_BLENDMODE_MOD:
FILLRECT(Uint32, DRAW_SETPIXEL_MOD_ARGB8888);
break;
case SDL_BLENDMODE_MUL:
FILLRECT(Uint32, DRAW_SETPIXEL_MUL_ARGB8888);
break;
default:
FILLRECT(Uint32, DRAW_SETPIXEL_ARGB8888);
break;
}
return true;
}
static bool SDL_BlendFillRect_RGB(SDL_Surface *dst, const SDL_Rect *rect,
SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
const SDL_PixelFormatDetails *fmt = dst->fmt;
unsigned inva = 0xff - a;
switch (fmt->bytes_per_pixel) {
case 2:
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_RGB);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
FILLRECT(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
FILLRECT(Uint16, DRAW_SETPIXEL_ADD_RGB);
break;
case SDL_BLENDMODE_MOD:
FILLRECT(Uint16, DRAW_SETPIXEL_MOD_RGB);
break;
case SDL_BLENDMODE_MUL:
FILLRECT(Uint16, DRAW_SETPIXEL_MUL_RGB);
break;
default:
FILLRECT(Uint16, DRAW_SETPIXEL_RGB);
break;
}
return true;
case 4:
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGB);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGB);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
FILLRECT(Uint32, DRAW_SETPIXEL_ADD_RGB);
break;
case SDL_BLENDMODE_MOD:
FILLRECT(Uint32, DRAW_SETPIXEL_MOD_RGB);
break;
case SDL_BLENDMODE_MUL:
FILLRECT(Uint32, DRAW_SETPIXEL_MUL_RGB);
break;
default:
FILLRECT(Uint32, DRAW_SETPIXEL_RGB);
break;
}
return true;
default:
return SDL_Unsupported();
}
}
static bool SDL_BlendFillRect_RGBA(SDL_Surface *dst, const SDL_Rect *rect,
SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
const SDL_PixelFormatDetails *fmt = dst->fmt;
unsigned inva = 0xff - a;
switch (fmt->bytes_per_pixel) {
case 4:
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_RGBA);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
FILLRECT(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGBA);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
FILLRECT(Uint32, DRAW_SETPIXEL_ADD_RGBA);
break;
case SDL_BLENDMODE_MOD:
FILLRECT(Uint32, DRAW_SETPIXEL_MOD_RGBA);
break;
case SDL_BLENDMODE_MUL:
FILLRECT(Uint32, DRAW_SETPIXEL_MUL_RGBA);
break;
default:
FILLRECT(Uint32, DRAW_SETPIXEL_RGBA);
break;
}
return true;
default:
return SDL_Unsupported();
}
}
bool SDL_BlendFillRect(SDL_Surface *dst, const SDL_Rect *rect, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
SDL_Rect clipped;
if (!SDL_SurfaceValid(dst)) {
return SDL_InvalidParamError("SDL_BlendFillRect(): dst");
}
// This function doesn't work on surfaces < 8 bpp
if (SDL_BITSPERPIXEL(dst->format) < 8) {
return SDL_SetError("SDL_BlendFillRect(): Unsupported surface format");
}
// If 'rect' == NULL, then fill the whole surface
if (rect) {
// Perform clipping
if (!SDL_GetRectIntersection(rect, &dst->clip_rect, &clipped)) {
return true;
}
rect = &clipped;
} else {
rect = &dst->clip_rect;
}
if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
r = DRAW_MUL(r, a);
g = DRAW_MUL(g, a);
b = DRAW_MUL(b, a);
}
switch (dst->fmt->bits_per_pixel) {
case 15:
switch (dst->fmt->Rmask) {
case 0x7C00:
return SDL_BlendFillRect_RGB555(dst, rect, blendMode, r, g, b, a);
}
break;
case 16:
switch (dst->fmt->Rmask) {
case 0xF800:
return SDL_BlendFillRect_RGB565(dst, rect, blendMode, r, g, b, a);
}
break;
case 32:
switch (dst->fmt->Rmask) {
case 0x00FF0000:
if (!dst->fmt->Amask) {
return SDL_BlendFillRect_XRGB8888(dst, rect, blendMode, r, g, b, a);
} else {
return SDL_BlendFillRect_ARGB8888(dst, rect, blendMode, r, g, b, a);
}
// break; -Wunreachable-code-break
}
break;
default:
break;
}
if (!dst->fmt->Amask) {
return SDL_BlendFillRect_RGB(dst, rect, blendMode, r, g, b, a);
} else {
return SDL_BlendFillRect_RGBA(dst, rect, blendMode, r, g, b, a);
}
}
bool SDL_BlendFillRects(SDL_Surface *dst, const SDL_Rect *rects, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
SDL_Rect rect;
int i;
bool (*func)(SDL_Surface * dst, const SDL_Rect *rect, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) = NULL;
bool result = true;
if (!SDL_SurfaceValid(dst)) {
return SDL_InvalidParamError("SDL_BlendFillRects(): dst");
}
// This function doesn't work on surfaces < 8 bpp
if (dst->fmt->bits_per_pixel < 8) {
return SDL_SetError("SDL_BlendFillRects(): Unsupported surface format");
}
if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
r = DRAW_MUL(r, a);
g = DRAW_MUL(g, a);
b = DRAW_MUL(b, a);
}
// FIXME: Does this function pointer slow things down significantly?
switch (dst->fmt->bits_per_pixel) {
case 15:
switch (dst->fmt->Rmask) {
case 0x7C00:
func = SDL_BlendFillRect_RGB555;
}
break;
case 16:
switch (dst->fmt->Rmask) {
case 0xF800:
func = SDL_BlendFillRect_RGB565;
}
break;
case 32:
switch (dst->fmt->Rmask) {
case 0x00FF0000:
if (!dst->fmt->Amask) {
func = SDL_BlendFillRect_XRGB8888;
} else {
func = SDL_BlendFillRect_ARGB8888;
}
break;
}
break;
default:
break;
}
if (!func) {
if (!dst->fmt->Amask) {
func = SDL_BlendFillRect_RGB;
} else {
func = SDL_BlendFillRect_RGBA;
}
}
for (i = 0; i < count; ++i) {
// Perform clipping
if (!SDL_GetRectIntersection(&rects[i], &dst->clip_rect, &rect)) {
continue;
}
result = func(dst, &rect, blendMode, r, g, b, a);
}
return result;
}
#endif // SDL_VIDEO_RENDER_SW
@@ -0,0 +1,30 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_blendfillrect_h_
#define SDL_blendfillrect_h_
#include "SDL_internal.h"
extern bool SDL_BlendFillRect(SDL_Surface *dst, const SDL_Rect *rect, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
extern bool SDL_BlendFillRects(SDL_Surface *dst, const SDL_Rect *rects, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
#endif // SDL_blendfillrect_h_
@@ -0,0 +1,986 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_RENDER_SW
#include "SDL_draw.h"
#include "SDL_blendline.h"
#include "SDL_blendpoint.h"
static void SDL_BlendLine_RGB2(SDL_Surface *dst, int x1, int y1, int x2, int y2,
SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
bool draw_end)
{
const SDL_PixelFormatDetails *fmt = dst->fmt;
unsigned r, g, b, a, inva;
if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
r = DRAW_MUL(_r, _a);
g = DRAW_MUL(_g, _a);
b = DRAW_MUL(_b, _a);
a = _a;
} else {
r = _r;
g = _g;
b = _b;
a = _a;
}
inva = (a ^ 0xff);
if (y1 == y2) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
HLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
HLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
HLINE(Uint16, DRAW_SETPIXEL_ADD_RGB, draw_end);
break;
case SDL_BLENDMODE_MOD:
HLINE(Uint16, DRAW_SETPIXEL_MOD_RGB, draw_end);
break;
case SDL_BLENDMODE_MUL:
HLINE(Uint16, DRAW_SETPIXEL_MUL_RGB, draw_end);
break;
default:
HLINE(Uint16, DRAW_SETPIXEL_RGB, draw_end);
break;
}
} else if (x1 == x2) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
VLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
VLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
VLINE(Uint16, DRAW_SETPIXEL_ADD_RGB, draw_end);
break;
case SDL_BLENDMODE_MOD:
VLINE(Uint16, DRAW_SETPIXEL_MOD_RGB, draw_end);
break;
case SDL_BLENDMODE_MUL:
VLINE(Uint16, DRAW_SETPIXEL_MUL_RGB, draw_end);
break;
default:
VLINE(Uint16, DRAW_SETPIXEL_RGB, draw_end);
break;
}
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
DLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
DLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
DLINE(Uint16, DRAW_SETPIXEL_ADD_RGB, draw_end);
break;
case SDL_BLENDMODE_MOD:
DLINE(Uint16, DRAW_SETPIXEL_MOD_RGB, draw_end);
break;
case SDL_BLENDMODE_MUL:
DLINE(Uint16, DRAW_SETPIXEL_MUL_RGB, draw_end);
break;
default:
DLINE(Uint16, DRAW_SETPIXEL_RGB, draw_end);
break;
}
} else {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY2_BLEND_RGB, DRAW_SETPIXELXY2_BLEND_RGB,
draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY2_BLEND_CLAMPED_RGB, DRAW_SETPIXELXY2_BLEND_CLAMPED_RGB,
draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY2_ADD_RGB, DRAW_SETPIXELXY2_ADD_RGB,
draw_end);
break;
case SDL_BLENDMODE_MOD:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY2_MOD_RGB, DRAW_SETPIXELXY2_MOD_RGB,
draw_end);
break;
case SDL_BLENDMODE_MUL:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY2_MUL_RGB, DRAW_SETPIXELXY2_MUL_RGB,
draw_end);
break;
default:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY2_RGB, DRAW_SETPIXELXY2_BLEND_RGB,
draw_end);
break;
}
}
}
static void SDL_BlendLine_RGB555(SDL_Surface *dst, int x1, int y1, int x2, int y2,
SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
bool draw_end)
{
unsigned r, g, b, a, inva;
if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
r = DRAW_MUL(_r, _a);
g = DRAW_MUL(_g, _a);
b = DRAW_MUL(_b, _a);
a = _a;
} else {
r = _r;
g = _g;
b = _b;
a = _a;
}
inva = (a ^ 0xff);
if (y1 == y2) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
HLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB555, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
HLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB555, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
HLINE(Uint16, DRAW_SETPIXEL_ADD_RGB555, draw_end);
break;
case SDL_BLENDMODE_MOD:
HLINE(Uint16, DRAW_SETPIXEL_MOD_RGB555, draw_end);
break;
case SDL_BLENDMODE_MUL:
HLINE(Uint16, DRAW_SETPIXEL_MUL_RGB555, draw_end);
break;
default:
HLINE(Uint16, DRAW_SETPIXEL_RGB555, draw_end);
break;
}
} else if (x1 == x2) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
VLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB555, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
VLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB555, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
VLINE(Uint16, DRAW_SETPIXEL_ADD_RGB555, draw_end);
break;
case SDL_BLENDMODE_MOD:
VLINE(Uint16, DRAW_SETPIXEL_MOD_RGB555, draw_end);
break;
case SDL_BLENDMODE_MUL:
VLINE(Uint16, DRAW_SETPIXEL_MUL_RGB555, draw_end);
break;
default:
VLINE(Uint16, DRAW_SETPIXEL_RGB555, draw_end);
break;
}
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
DLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB555, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
DLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB555, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
DLINE(Uint16, DRAW_SETPIXEL_ADD_RGB555, draw_end);
break;
case SDL_BLENDMODE_MOD:
DLINE(Uint16, DRAW_SETPIXEL_MOD_RGB555, draw_end);
break;
case SDL_BLENDMODE_MUL:
DLINE(Uint16, DRAW_SETPIXEL_MUL_RGB555, draw_end);
break;
default:
DLINE(Uint16, DRAW_SETPIXEL_RGB555, draw_end);
break;
}
} else {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_BLEND_RGB555, DRAW_SETPIXELXY_BLEND_RGB555,
draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_BLEND_CLAMPED_RGB555, DRAW_SETPIXELXY_BLEND_CLAMPED_RGB555,
draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_ADD_RGB555, DRAW_SETPIXELXY_ADD_RGB555,
draw_end);
break;
case SDL_BLENDMODE_MOD:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_MOD_RGB555, DRAW_SETPIXELXY_MOD_RGB555,
draw_end);
break;
case SDL_BLENDMODE_MUL:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_MUL_RGB555, DRAW_SETPIXELXY_MUL_RGB555,
draw_end);
break;
default:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_RGB555, DRAW_SETPIXELXY_BLEND_RGB555,
draw_end);
break;
}
}
}
static void SDL_BlendLine_RGB565(SDL_Surface *dst, int x1, int y1, int x2, int y2,
SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
bool draw_end)
{
unsigned r, g, b, a, inva;
if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
r = DRAW_MUL(_r, _a);
g = DRAW_MUL(_g, _a);
b = DRAW_MUL(_b, _a);
a = _a;
} else {
r = _r;
g = _g;
b = _b;
a = _a;
}
inva = (a ^ 0xff);
if (y1 == y2) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
HLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB565, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
HLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB565, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
HLINE(Uint16, DRAW_SETPIXEL_ADD_RGB565, draw_end);
break;
case SDL_BLENDMODE_MOD:
HLINE(Uint16, DRAW_SETPIXEL_MOD_RGB565, draw_end);
break;
case SDL_BLENDMODE_MUL:
HLINE(Uint16, DRAW_SETPIXEL_MUL_RGB565, draw_end);
break;
default:
HLINE(Uint16, DRAW_SETPIXEL_RGB565, draw_end);
break;
}
} else if (x1 == x2) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
VLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB565, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
VLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB565, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
VLINE(Uint16, DRAW_SETPIXEL_ADD_RGB565, draw_end);
break;
case SDL_BLENDMODE_MOD:
VLINE(Uint16, DRAW_SETPIXEL_MOD_RGB565, draw_end);
break;
case SDL_BLENDMODE_MUL:
VLINE(Uint16, DRAW_SETPIXEL_MUL_RGB565, draw_end);
break;
default:
VLINE(Uint16, DRAW_SETPIXEL_RGB565, draw_end);
break;
}
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
DLINE(Uint16, DRAW_SETPIXEL_BLEND_RGB565, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
DLINE(Uint16, DRAW_SETPIXEL_BLEND_CLAMPED_RGB565, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
DLINE(Uint16, DRAW_SETPIXEL_ADD_RGB565, draw_end);
break;
case SDL_BLENDMODE_MOD:
DLINE(Uint16, DRAW_SETPIXEL_MOD_RGB565, draw_end);
break;
case SDL_BLENDMODE_MUL:
DLINE(Uint16, DRAW_SETPIXEL_MUL_RGB565, draw_end);
break;
default:
DLINE(Uint16, DRAW_SETPIXEL_RGB565, draw_end);
break;
}
} else {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_BLEND_RGB565, DRAW_SETPIXELXY_BLEND_RGB565,
draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_BLEND_CLAMPED_RGB565, DRAW_SETPIXELXY_BLEND_CLAMPED_RGB565,
draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_ADD_RGB565, DRAW_SETPIXELXY_ADD_RGB565,
draw_end);
break;
case SDL_BLENDMODE_MOD:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_MOD_RGB565, DRAW_SETPIXELXY_MOD_RGB565,
draw_end);
break;
case SDL_BLENDMODE_MUL:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_MUL_RGB565, DRAW_SETPIXELXY_MUL_RGB565,
draw_end);
break;
default:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_RGB565, DRAW_SETPIXELXY_BLEND_RGB565,
draw_end);
break;
}
}
}
static void SDL_BlendLine_RGB4(SDL_Surface *dst, int x1, int y1, int x2, int y2,
SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
bool draw_end)
{
const SDL_PixelFormatDetails *fmt = dst->fmt;
unsigned r, g, b, a, inva;
if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
r = DRAW_MUL(_r, _a);
g = DRAW_MUL(_g, _a);
b = DRAW_MUL(_b, _a);
a = _a;
} else {
r = _r;
g = _g;
b = _b;
a = _a;
}
inva = (a ^ 0xff);
if (y1 == y2) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
HLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
HLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
HLINE(Uint32, DRAW_SETPIXEL_ADD_RGB, draw_end);
break;
case SDL_BLENDMODE_MOD:
HLINE(Uint32, DRAW_SETPIXEL_MOD_RGB, draw_end);
break;
case SDL_BLENDMODE_MUL:
HLINE(Uint32, DRAW_SETPIXEL_MUL_RGB, draw_end);
break;
default:
HLINE(Uint32, DRAW_SETPIXEL_RGB, draw_end);
break;
}
} else if (x1 == x2) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
VLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
VLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
VLINE(Uint32, DRAW_SETPIXEL_ADD_RGB, draw_end);
break;
case SDL_BLENDMODE_MOD:
VLINE(Uint32, DRAW_SETPIXEL_MOD_RGB, draw_end);
break;
case SDL_BLENDMODE_MUL:
VLINE(Uint32, DRAW_SETPIXEL_MUL_RGB, draw_end);
break;
default:
VLINE(Uint32, DRAW_SETPIXEL_RGB, draw_end);
break;
}
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
DLINE(Uint32, DRAW_SETPIXEL_BLEND_RGB, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
DLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGB, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
DLINE(Uint32, DRAW_SETPIXEL_ADD_RGB, draw_end);
break;
case SDL_BLENDMODE_MOD:
DLINE(Uint32, DRAW_SETPIXEL_MOD_RGB, draw_end);
break;
case SDL_BLENDMODE_MUL:
DLINE(Uint32, DRAW_SETPIXEL_MUL_RGB, draw_end);
break;
default:
DLINE(Uint32, DRAW_SETPIXEL_RGB, draw_end);
break;
}
} else {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY4_BLEND_RGB, DRAW_SETPIXELXY4_BLEND_RGB,
draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY4_BLEND_CLAMPED_RGB, DRAW_SETPIXELXY4_BLEND_CLAMPED_RGB,
draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY4_ADD_RGB, DRAW_SETPIXELXY4_ADD_RGB,
draw_end);
break;
case SDL_BLENDMODE_MOD:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY4_MOD_RGB, DRAW_SETPIXELXY4_MOD_RGB,
draw_end);
break;
case SDL_BLENDMODE_MUL:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY4_MUL_RGB, DRAW_SETPIXELXY4_MUL_RGB,
draw_end);
break;
default:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY4_RGB, DRAW_SETPIXELXY4_BLEND_RGB,
draw_end);
break;
}
}
}
static void SDL_BlendLine_RGBA4(SDL_Surface *dst, int x1, int y1, int x2, int y2,
SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
bool draw_end)
{
const SDL_PixelFormatDetails *fmt = dst->fmt;
unsigned r, g, b, a, inva;
if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
r = DRAW_MUL(_r, _a);
g = DRAW_MUL(_g, _a);
b = DRAW_MUL(_b, _a);
a = _a;
} else {
r = _r;
g = _g;
b = _b;
a = _a;
}
inva = (a ^ 0xff);
if (y1 == y2) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
HLINE(Uint32, DRAW_SETPIXEL_BLEND_RGBA, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
HLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGBA, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
HLINE(Uint32, DRAW_SETPIXEL_ADD_RGBA, draw_end);
break;
case SDL_BLENDMODE_MOD:
HLINE(Uint32, DRAW_SETPIXEL_MOD_RGBA, draw_end);
break;
case SDL_BLENDMODE_MUL:
HLINE(Uint32, DRAW_SETPIXEL_MUL_RGBA, draw_end);
break;
default:
HLINE(Uint32, DRAW_SETPIXEL_RGBA, draw_end);
break;
}
} else if (x1 == x2) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
VLINE(Uint32, DRAW_SETPIXEL_BLEND_RGBA, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
VLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGBA, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
VLINE(Uint32, DRAW_SETPIXEL_ADD_RGBA, draw_end);
break;
case SDL_BLENDMODE_MOD:
VLINE(Uint32, DRAW_SETPIXEL_MOD_RGBA, draw_end);
break;
case SDL_BLENDMODE_MUL:
VLINE(Uint32, DRAW_SETPIXEL_MUL_RGBA, draw_end);
break;
default:
VLINE(Uint32, DRAW_SETPIXEL_RGBA, draw_end);
break;
}
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
DLINE(Uint32, DRAW_SETPIXEL_BLEND_RGBA, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
DLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_RGBA, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
DLINE(Uint32, DRAW_SETPIXEL_ADD_RGBA, draw_end);
break;
case SDL_BLENDMODE_MOD:
DLINE(Uint32, DRAW_SETPIXEL_MOD_RGBA, draw_end);
break;
case SDL_BLENDMODE_MUL:
DLINE(Uint32, DRAW_SETPIXEL_MUL_RGBA, draw_end);
break;
default:
DLINE(Uint32, DRAW_SETPIXEL_RGBA, draw_end);
break;
}
} else {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY4_BLEND_RGBA, DRAW_SETPIXELXY4_BLEND_RGBA,
draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY4_BLEND_CLAMPED_RGBA, DRAW_SETPIXELXY4_BLEND_CLAMPED_RGBA,
draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY4_ADD_RGBA, DRAW_SETPIXELXY4_ADD_RGBA,
draw_end);
break;
case SDL_BLENDMODE_MOD:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY4_MOD_RGBA, DRAW_SETPIXELXY4_MOD_RGBA,
draw_end);
break;
case SDL_BLENDMODE_MUL:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY4_MUL_RGBA, DRAW_SETPIXELXY4_MUL_RGBA,
draw_end);
break;
default:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY4_RGBA, DRAW_SETPIXELXY4_BLEND_RGBA,
draw_end);
break;
}
}
}
static void SDL_BlendLine_XRGB8888(SDL_Surface *dst, int x1, int y1, int x2, int y2,
SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
bool draw_end)
{
unsigned r, g, b, a, inva;
if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
r = DRAW_MUL(_r, _a);
g = DRAW_MUL(_g, _a);
b = DRAW_MUL(_b, _a);
a = _a;
} else {
r = _r;
g = _g;
b = _b;
a = _a;
}
inva = (a ^ 0xff);
if (y1 == y2) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
HLINE(Uint32, DRAW_SETPIXEL_BLEND_XRGB8888, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
HLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
HLINE(Uint32, DRAW_SETPIXEL_ADD_XRGB8888, draw_end);
break;
case SDL_BLENDMODE_MOD:
HLINE(Uint32, DRAW_SETPIXEL_MOD_XRGB8888, draw_end);
break;
case SDL_BLENDMODE_MUL:
HLINE(Uint32, DRAW_SETPIXEL_MUL_XRGB8888, draw_end);
break;
default:
HLINE(Uint32, DRAW_SETPIXEL_XRGB8888, draw_end);
break;
}
} else if (x1 == x2) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
VLINE(Uint32, DRAW_SETPIXEL_BLEND_XRGB8888, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
VLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
VLINE(Uint32, DRAW_SETPIXEL_ADD_XRGB8888, draw_end);
break;
case SDL_BLENDMODE_MOD:
VLINE(Uint32, DRAW_SETPIXEL_MOD_XRGB8888, draw_end);
break;
case SDL_BLENDMODE_MUL:
VLINE(Uint32, DRAW_SETPIXEL_MUL_XRGB8888, draw_end);
break;
default:
VLINE(Uint32, DRAW_SETPIXEL_XRGB8888, draw_end);
break;
}
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
DLINE(Uint32, DRAW_SETPIXEL_BLEND_XRGB8888, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
DLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
DLINE(Uint32, DRAW_SETPIXEL_ADD_XRGB8888, draw_end);
break;
case SDL_BLENDMODE_MOD:
DLINE(Uint32, DRAW_SETPIXEL_MOD_XRGB8888, draw_end);
break;
case SDL_BLENDMODE_MUL:
DLINE(Uint32, DRAW_SETPIXEL_MUL_XRGB8888, draw_end);
break;
default:
DLINE(Uint32, DRAW_SETPIXEL_XRGB8888, draw_end);
break;
}
} else {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_BLEND_XRGB8888, DRAW_SETPIXELXY_BLEND_XRGB8888,
draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_BLEND_CLAMPED_XRGB8888, DRAW_SETPIXELXY_BLEND_CLAMPED_XRGB8888,
draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_ADD_XRGB8888, DRAW_SETPIXELXY_ADD_XRGB8888,
draw_end);
break;
case SDL_BLENDMODE_MOD:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_MOD_XRGB8888, DRAW_SETPIXELXY_MOD_XRGB8888,
draw_end);
break;
case SDL_BLENDMODE_MUL:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_MUL_XRGB8888, DRAW_SETPIXELXY_MUL_XRGB8888,
draw_end);
break;
default:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_XRGB8888, DRAW_SETPIXELXY_BLEND_XRGB8888,
draw_end);
break;
}
}
}
static void SDL_BlendLine_ARGB8888(SDL_Surface *dst, int x1, int y1, int x2, int y2,
SDL_BlendMode blendMode, Uint8 _r, Uint8 _g, Uint8 _b, Uint8 _a,
bool draw_end)
{
unsigned r, g, b, a, inva;
if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
r = DRAW_MUL(_r, _a);
g = DRAW_MUL(_g, _a);
b = DRAW_MUL(_b, _a);
a = _a;
} else {
r = _r;
g = _g;
b = _b;
a = _a;
}
inva = (a ^ 0xff);
if (y1 == y2) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
HLINE(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
HLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
HLINE(Uint32, DRAW_SETPIXEL_ADD_ARGB8888, draw_end);
break;
case SDL_BLENDMODE_MOD:
HLINE(Uint32, DRAW_SETPIXEL_MOD_ARGB8888, draw_end);
break;
case SDL_BLENDMODE_MUL:
HLINE(Uint32, DRAW_SETPIXEL_MUL_ARGB8888, draw_end);
break;
default:
HLINE(Uint32, DRAW_SETPIXEL_ARGB8888, draw_end);
break;
}
} else if (x1 == x2) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
VLINE(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
VLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
VLINE(Uint32, DRAW_SETPIXEL_ADD_ARGB8888, draw_end);
break;
case SDL_BLENDMODE_MOD:
VLINE(Uint32, DRAW_SETPIXEL_MOD_ARGB8888, draw_end);
break;
case SDL_BLENDMODE_MUL:
VLINE(Uint32, DRAW_SETPIXEL_MUL_ARGB8888, draw_end);
break;
default:
VLINE(Uint32, DRAW_SETPIXEL_ARGB8888, draw_end);
break;
}
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
DLINE(Uint32, DRAW_SETPIXEL_BLEND_ARGB8888, draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
DLINE(Uint32, DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888, draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
DLINE(Uint32, DRAW_SETPIXEL_ADD_ARGB8888, draw_end);
break;
case SDL_BLENDMODE_MOD:
DLINE(Uint32, DRAW_SETPIXEL_MOD_ARGB8888, draw_end);
break;
case SDL_BLENDMODE_MUL:
DLINE(Uint32, DRAW_SETPIXEL_MUL_ARGB8888, draw_end);
break;
default:
DLINE(Uint32, DRAW_SETPIXEL_ARGB8888, draw_end);
break;
}
} else {
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_BLEND_ARGB8888, DRAW_SETPIXELXY_BLEND_ARGB8888,
draw_end);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_BLEND_CLAMPED_ARGB8888, DRAW_SETPIXELXY_BLEND_CLAMPED_ARGB8888,
draw_end);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_ADD_ARGB8888, DRAW_SETPIXELXY_ADD_ARGB8888,
draw_end);
break;
case SDL_BLENDMODE_MOD:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_MOD_ARGB8888, DRAW_SETPIXELXY_MOD_ARGB8888,
draw_end);
break;
case SDL_BLENDMODE_MUL:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_MUL_ARGB8888, DRAW_SETPIXELXY_MUL_ARGB8888,
draw_end);
break;
default:
AALINE(x1, y1, x2, y2,
DRAW_SETPIXELXY_ARGB8888, DRAW_SETPIXELXY_BLEND_ARGB8888,
draw_end);
break;
}
}
}
typedef void (*BlendLineFunc)(SDL_Surface *dst,
int x1, int y1, int x2, int y2,
SDL_BlendMode blendMode,
Uint8 r, Uint8 g, Uint8 b, Uint8 a,
bool draw_end);
static BlendLineFunc SDL_CalculateBlendLineFunc(const SDL_PixelFormatDetails *fmt)
{
switch (fmt->bytes_per_pixel) {
case 2:
if (fmt->Rmask == 0x7C00) {
return SDL_BlendLine_RGB555;
} else if (fmt->Rmask == 0xF800) {
return SDL_BlendLine_RGB565;
} else {
return SDL_BlendLine_RGB2;
}
// break; -Wunreachable-code-break
case 4:
if (fmt->Rmask == 0x00FF0000) {
if (fmt->Amask) {
return SDL_BlendLine_ARGB8888;
} else {
return SDL_BlendLine_XRGB8888;
}
} else {
if (fmt->Amask) {
return SDL_BlendLine_RGBA4;
} else {
return SDL_BlendLine_RGB4;
}
}
}
return NULL;
}
bool SDL_BlendLine(SDL_Surface *dst, int x1, int y1, int x2, int y2, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
BlendLineFunc func;
if (!SDL_SurfaceValid(dst)) {
return SDL_InvalidParamError("SDL_BlendLine(): dst");
}
func = SDL_CalculateBlendLineFunc(dst->fmt);
if (!func) {
return SDL_SetError("SDL_BlendLine(): Unsupported surface format");
}
// Perform clipping
// FIXME: We don't actually want to clip, as it may change line slope
if (!SDL_GetRectAndLineIntersection(&dst->clip_rect, &x1, &y1, &x2, &y2)) {
return true;
}
func(dst, x1, y1, x2, y2, blendMode, r, g, b, a, true);
return true;
}
bool SDL_BlendLines(SDL_Surface *dst, const SDL_Point *points, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
int i;
int x1, y1;
int x2, y2;
bool draw_end;
BlendLineFunc func;
if (!SDL_SurfaceValid(dst)) {
return SDL_SetError("SDL_BlendLines(): Passed NULL destination surface");
}
func = SDL_CalculateBlendLineFunc(dst->fmt);
if (!func) {
return SDL_SetError("SDL_BlendLines(): Unsupported surface format");
}
for (i = 1; i < count; ++i) {
x1 = points[i - 1].x;
y1 = points[i - 1].y;
x2 = points[i].x;
y2 = points[i].y;
// Perform clipping
// FIXME: We don't actually want to clip, as it may change line slope
if (!SDL_GetRectAndLineIntersection(&dst->clip_rect, &x1, &y1, &x2, &y2)) {
continue;
}
// Draw the end if it was clipped
draw_end = (x2 != points[i].x || y2 != points[i].y);
func(dst, x1, y1, x2, y2, blendMode, r, g, b, a, draw_end);
}
if (points[0].x != points[count - 1].x || points[0].y != points[count - 1].y) {
SDL_BlendPoint(dst, points[count - 1].x, points[count - 1].y,
blendMode, r, g, b, a);
}
return true;
}
#endif // SDL_VIDEO_RENDER_SW
@@ -0,0 +1,30 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_blendline_h_
#define SDL_blendline_h_
#include "SDL_internal.h"
extern bool SDL_BlendLine(SDL_Surface *dst, int x1, int y1, int x2, int y2, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
extern bool SDL_BlendLines(SDL_Surface *dst, const SDL_Point *points, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
#endif // SDL_blendline_h_
@@ -0,0 +1,376 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_RENDER_SW
#include "SDL_draw.h"
#include "SDL_blendpoint.h"
static bool SDL_BlendPoint_RGB555(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r,
Uint8 g, Uint8 b, Uint8 a)
{
unsigned inva = 0xff - a;
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
DRAW_SETPIXELXY_BLEND_RGB555(x, y);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
DRAW_SETPIXELXY_BLEND_CLAMPED_RGB555(x, y);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
DRAW_SETPIXELXY_ADD_RGB555(x, y);
break;
case SDL_BLENDMODE_MOD:
DRAW_SETPIXELXY_MOD_RGB555(x, y);
break;
case SDL_BLENDMODE_MUL:
DRAW_SETPIXELXY_MUL_RGB555(x, y);
break;
default:
DRAW_SETPIXELXY_RGB555(x, y);
break;
}
return true;
}
static bool SDL_BlendPoint_RGB565(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r,
Uint8 g, Uint8 b, Uint8 a)
{
unsigned inva = 0xff - a;
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
DRAW_SETPIXELXY_BLEND_RGB565(x, y);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
DRAW_SETPIXELXY_BLEND_CLAMPED_RGB565(x, y);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
DRAW_SETPIXELXY_ADD_RGB565(x, y);
break;
case SDL_BLENDMODE_MOD:
DRAW_SETPIXELXY_MOD_RGB565(x, y);
break;
case SDL_BLENDMODE_MUL:
DRAW_SETPIXELXY_MUL_RGB565(x, y);
break;
default:
DRAW_SETPIXELXY_RGB565(x, y);
break;
}
return true;
}
static bool SDL_BlendPoint_XRGB8888(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r,
Uint8 g, Uint8 b, Uint8 a)
{
unsigned inva = 0xff - a;
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
DRAW_SETPIXELXY_BLEND_XRGB8888(x, y);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
DRAW_SETPIXELXY_BLEND_CLAMPED_XRGB8888(x, y);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
DRAW_SETPIXELXY_ADD_XRGB8888(x, y);
break;
case SDL_BLENDMODE_MOD:
DRAW_SETPIXELXY_MOD_XRGB8888(x, y);
break;
case SDL_BLENDMODE_MUL:
DRAW_SETPIXELXY_MUL_XRGB8888(x, y);
break;
default:
DRAW_SETPIXELXY_XRGB8888(x, y);
break;
}
return true;
}
static bool SDL_BlendPoint_ARGB8888(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode,
Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
unsigned inva = 0xff - a;
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
DRAW_SETPIXELXY_BLEND_ARGB8888(x, y);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
DRAW_SETPIXELXY_BLEND_CLAMPED_ARGB8888(x, y);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
DRAW_SETPIXELXY_ADD_ARGB8888(x, y);
break;
case SDL_BLENDMODE_MOD:
DRAW_SETPIXELXY_MOD_ARGB8888(x, y);
break;
case SDL_BLENDMODE_MUL:
DRAW_SETPIXELXY_MUL_ARGB8888(x, y);
break;
default:
DRAW_SETPIXELXY_ARGB8888(x, y);
break;
}
return true;
}
static bool SDL_BlendPoint_RGB(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r,
Uint8 g, Uint8 b, Uint8 a)
{
const SDL_PixelFormatDetails *fmt = dst->fmt;
unsigned inva = 0xff - a;
switch (fmt->bytes_per_pixel) {
case 2:
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
DRAW_SETPIXELXY2_BLEND_RGB(x, y);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
DRAW_SETPIXELXY2_BLEND_CLAMPED_RGB(x, y);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
DRAW_SETPIXELXY2_ADD_RGB(x, y);
break;
case SDL_BLENDMODE_MOD:
DRAW_SETPIXELXY2_MOD_RGB(x, y);
break;
case SDL_BLENDMODE_MUL:
DRAW_SETPIXELXY2_MUL_RGB(x, y);
break;
default:
DRAW_SETPIXELXY2_RGB(x, y);
break;
}
return true;
case 4:
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
DRAW_SETPIXELXY4_BLEND_RGB(x, y);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
DRAW_SETPIXELXY4_BLEND_CLAMPED_RGB(x, y);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
DRAW_SETPIXELXY4_ADD_RGB(x, y);
break;
case SDL_BLENDMODE_MOD:
DRAW_SETPIXELXY4_MOD_RGB(x, y);
break;
case SDL_BLENDMODE_MUL:
DRAW_SETPIXELXY4_MUL_RGB(x, y);
break;
default:
DRAW_SETPIXELXY4_RGB(x, y);
break;
}
return true;
default:
return SDL_Unsupported();
}
}
static bool SDL_BlendPoint_RGBA(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r,
Uint8 g, Uint8 b, Uint8 a)
{
const SDL_PixelFormatDetails *fmt = dst->fmt;
unsigned inva = 0xff - a;
switch (fmt->bytes_per_pixel) {
case 4:
switch (blendMode) {
case SDL_BLENDMODE_BLEND:
DRAW_SETPIXELXY4_BLEND_RGBA(x, y);
break;
case SDL_BLENDMODE_BLEND_PREMULTIPLIED:
DRAW_SETPIXELXY4_BLEND_CLAMPED_RGBA(x, y);
break;
case SDL_BLENDMODE_ADD:
case SDL_BLENDMODE_ADD_PREMULTIPLIED:
DRAW_SETPIXELXY4_ADD_RGBA(x, y);
break;
case SDL_BLENDMODE_MOD:
DRAW_SETPIXELXY4_MOD_RGBA(x, y);
break;
case SDL_BLENDMODE_MUL:
DRAW_SETPIXELXY4_MUL_RGBA(x, y);
break;
default:
DRAW_SETPIXELXY4_RGBA(x, y);
break;
}
return true;
default:
return SDL_Unsupported();
}
}
bool SDL_BlendPoint(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
if (!SDL_SurfaceValid(dst)) {
return SDL_InvalidParamError("SDL_BlendPoint(): dst");
}
// This function doesn't work on surfaces < 8 bpp
if (SDL_BITSPERPIXEL(dst->format) < 8) {
return SDL_SetError("SDL_BlendPoint(): Unsupported surface format");
}
// Perform clipping
if (x < dst->clip_rect.x || y < dst->clip_rect.y ||
x >= (dst->clip_rect.x + dst->clip_rect.w) ||
y >= (dst->clip_rect.y + dst->clip_rect.h)) {
return true;
}
if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
r = DRAW_MUL(r, a);
g = DRAW_MUL(g, a);
b = DRAW_MUL(b, a);
}
switch (dst->fmt->bits_per_pixel) {
case 15:
switch (dst->fmt->Rmask) {
case 0x7C00:
return SDL_BlendPoint_RGB555(dst, x, y, blendMode, r, g, b, a);
}
break;
case 16:
switch (dst->fmt->Rmask) {
case 0xF800:
return SDL_BlendPoint_RGB565(dst, x, y, blendMode, r, g, b, a);
}
break;
case 32:
switch (dst->fmt->Rmask) {
case 0x00FF0000:
if (!dst->fmt->Amask) {
return SDL_BlendPoint_XRGB8888(dst, x, y, blendMode, r, g, b, a);
} else {
return SDL_BlendPoint_ARGB8888(dst, x, y, blendMode, r, g, b, a);
}
// break; -Wunreachable-code-break
}
break;
default:
break;
}
if (!dst->fmt->Amask) {
return SDL_BlendPoint_RGB(dst, x, y, blendMode, r, g, b, a);
} else {
return SDL_BlendPoint_RGBA(dst, x, y, blendMode, r, g, b, a);
}
}
bool SDL_BlendPoints(SDL_Surface *dst, const SDL_Point *points, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
int minx, miny;
int maxx, maxy;
int i;
int x, y;
bool (*func)(SDL_Surface * dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a) = NULL;
bool result = true;
if (!SDL_SurfaceValid(dst)) {
return SDL_InvalidParamError("SDL_BlendPoints(): dst");
}
// This function doesn't work on surfaces < 8 bpp
if (dst->fmt->bits_per_pixel < 8) {
return SDL_SetError("SDL_BlendPoints(): Unsupported surface format");
}
if (blendMode == SDL_BLENDMODE_BLEND || blendMode == SDL_BLENDMODE_ADD) {
r = DRAW_MUL(r, a);
g = DRAW_MUL(g, a);
b = DRAW_MUL(b, a);
}
// FIXME: Does this function pointer slow things down significantly?
switch (dst->fmt->bits_per_pixel) {
case 15:
switch (dst->fmt->Rmask) {
case 0x7C00:
func = SDL_BlendPoint_RGB555;
break;
}
break;
case 16:
switch (dst->fmt->Rmask) {
case 0xF800:
func = SDL_BlendPoint_RGB565;
break;
}
break;
case 32:
switch (dst->fmt->Rmask) {
case 0x00FF0000:
if (!dst->fmt->Amask) {
func = SDL_BlendPoint_XRGB8888;
} else {
func = SDL_BlendPoint_ARGB8888;
}
break;
}
break;
default:
break;
}
if (!func) {
if (!dst->fmt->Amask) {
func = SDL_BlendPoint_RGB;
} else {
func = SDL_BlendPoint_RGBA;
}
}
minx = dst->clip_rect.x;
maxx = dst->clip_rect.x + dst->clip_rect.w - 1;
miny = dst->clip_rect.y;
maxy = dst->clip_rect.y + dst->clip_rect.h - 1;
for (i = 0; i < count; ++i) {
x = points[i].x;
y = points[i].y;
if (x < minx || x > maxx || y < miny || y > maxy) {
continue;
}
result = func(dst, x, y, blendMode, r, g, b, a);
}
return result;
}
#endif // SDL_VIDEO_RENDER_SW
@@ -0,0 +1,30 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_blendpoint_h_
#define SDL_blendpoint_h_
#include "SDL_internal.h"
extern bool SDL_BlendPoint(SDL_Surface *dst, int x, int y, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
extern bool SDL_BlendPoints(SDL_Surface *dst, const SDL_Point *points, int count, SDL_BlendMode blendMode, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
#endif // SDL_blendpoint_h_
@@ -0,0 +1,724 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "../../video/SDL_surface_c.h"
/* This code assumes that r, g, b, a are the source color,
* and in the blend and add case, the RGB values are premultiplied by a.
*/
#define DRAW_MUL(_a, _b) (((unsigned)(_a) * (_b)) / 255)
#define DRAW_FASTSETPIXEL(type) \
*pixels = (type)color
#define DRAW_FASTSETPIXEL1 DRAW_FASTSETPIXEL(Uint8)
#define DRAW_FASTSETPIXEL2 DRAW_FASTSETPIXEL(Uint16)
#define DRAW_FASTSETPIXEL4 DRAW_FASTSETPIXEL(Uint32)
#define DRAW_FASTSETPIXELXY(x, y, type, bpp, color) \
*(type *)((Uint8 *)dst->pixels + (y)*dst->pitch + (x)*bpp) = (type)color
#define DRAW_FASTSETPIXELXY1(x, y) DRAW_FASTSETPIXELXY(x, y, Uint8, 1, color)
#define DRAW_FASTSETPIXELXY2(x, y) DRAW_FASTSETPIXELXY(x, y, Uint16, 2, color)
#define DRAW_FASTSETPIXELXY4(x, y) DRAW_FASTSETPIXELXY(x, y, Uint32, 4, color)
#define DRAW_SETPIXEL(setpixel) \
do { \
unsigned sr = r, sg = g, sb = b, sa = a; \
(void)sa; \
setpixel; \
} while (0)
#define DRAW_SETPIXEL_BLEND(getpixel, setpixel) \
do { \
unsigned sr, sg, sb, sa = 0xFF; \
getpixel; \
sr = DRAW_MUL(inva, sr) + r; \
sg = DRAW_MUL(inva, sg) + g; \
sb = DRAW_MUL(inva, sb) + b; \
sa = DRAW_MUL(inva, sa) + a; \
setpixel; \
} while (0)
#define DRAW_SETPIXEL_BLEND_CLAMPED(getpixel, setpixel) \
do { \
unsigned sr, sg, sb, sa = 0xFF; \
getpixel; \
sr = DRAW_MUL(inva, sr) + r; \
if (sr > 0xff) \
sr = 0xff; \
sg = DRAW_MUL(inva, sg) + g; \
if (sg > 0xff) \
sg = 0xff; \
sb = DRAW_MUL(inva, sb) + b; \
if (sb > 0xff) \
sb = 0xff; \
sa = DRAW_MUL(inva, sa) + a; \
if (sa > 0xff) \
sa = 0xff; \
setpixel; \
} while (0)
#define DRAW_SETPIXEL_ADD(getpixel, setpixel) \
do { \
unsigned sr, sg, sb, sa; \
(void)sa; \
getpixel; \
sr += r; \
if (sr > 0xff) \
sr = 0xff; \
sg += g; \
if (sg > 0xff) \
sg = 0xff; \
sb += b; \
if (sb > 0xff) \
sb = 0xff; \
setpixel; \
} while (0)
#define DRAW_SETPIXEL_MOD(getpixel, setpixel) \
do { \
unsigned sr, sg, sb, sa; \
(void)sa; \
getpixel; \
sr = DRAW_MUL(sr, r); \
sg = DRAW_MUL(sg, g); \
sb = DRAW_MUL(sb, b); \
setpixel; \
} while (0)
#define DRAW_SETPIXEL_MUL(getpixel, setpixel) \
do { \
unsigned sr, sg, sb, sa; \
(void)sa; \
getpixel; \
sr = DRAW_MUL(sr, r) + DRAW_MUL(inva, sr); \
if (sr > 0xff) \
sr = 0xff; \
sg = DRAW_MUL(sg, g) + DRAW_MUL(inva, sg); \
if (sg > 0xff) \
sg = 0xff; \
sb = DRAW_MUL(sb, b) + DRAW_MUL(inva, sb); \
if (sb > 0xff) \
sb = 0xff; \
setpixel; \
} while (0)
#define DRAW_SETPIXELXY(x, y, type, bpp, op) \
do { \
type *pixels = (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(*pixels, sr, sg, sb))
#define DRAW_SETPIXEL_BLEND_RGB555 \
DRAW_SETPIXEL_BLEND(RGB_FROM_RGB555(*pixels, sr, sg, sb),\
RGB555_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXEL_BLEND_CLAMPED_RGB555 \
DRAW_SETPIXEL_BLEND_CLAMPED(RGB_FROM_RGB555(*pixels, sr, sg, sb),\
RGB555_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXEL_ADD_RGB555 \
DRAW_SETPIXEL_ADD(RGB_FROM_RGB555(*pixels, sr, sg, sb),\
RGB555_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXEL_MOD_RGB555 \
DRAW_SETPIXEL_MOD(RGB_FROM_RGB555(*pixels, sr, sg, sb),\
RGB555_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXEL_MUL_RGB555 \
DRAW_SETPIXEL_MUL(RGB_FROM_RGB555(*pixels, sr, sg, sb),\
RGB555_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXELXY_RGB555(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_RGB555)
#define DRAW_SETPIXELXY_BLEND_RGB555(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_RGB555)
#define DRAW_SETPIXELXY_BLEND_CLAMPED_RGB555(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_CLAMPED_RGB555)
#define DRAW_SETPIXELXY_ADD_RGB555(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_ADD_RGB555)
#define DRAW_SETPIXELXY_MOD_RGB555(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MOD_RGB555)
#define DRAW_SETPIXELXY_MUL_RGB555(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MUL_RGB555)
/*
* Define draw operators for RGB565
*/
#define DRAW_SETPIXEL_RGB565 \
DRAW_SETPIXEL(RGB565_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXEL_BLEND_RGB565 \
DRAW_SETPIXEL_BLEND(RGB_FROM_RGB565(*pixels, sr, sg, sb),\
RGB565_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXEL_BLEND_CLAMPED_RGB565 \
DRAW_SETPIXEL_BLEND_CLAMPED(RGB_FROM_RGB565(*pixels, sr, sg, sb),\
RGB565_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXEL_ADD_RGB565 \
DRAW_SETPIXEL_ADD(RGB_FROM_RGB565(*pixels, sr, sg, sb),\
RGB565_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXEL_MOD_RGB565 \
DRAW_SETPIXEL_MOD(RGB_FROM_RGB565(*pixels, sr, sg, sb),\
RGB565_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXEL_MUL_RGB565 \
DRAW_SETPIXEL_MUL(RGB_FROM_RGB565(*pixels, sr, sg, sb),\
RGB565_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXELXY_RGB565(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_RGB565)
#define DRAW_SETPIXELXY_BLEND_RGB565(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_RGB565)
#define DRAW_SETPIXELXY_BLEND_CLAMPED_RGB565(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_CLAMPED_RGB565)
#define DRAW_SETPIXELXY_ADD_RGB565(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_ADD_RGB565)
#define DRAW_SETPIXELXY_MOD_RGB565(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MOD_RGB565)
#define DRAW_SETPIXELXY_MUL_RGB565(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MUL_RGB565)
/*
* Define draw operators for RGB888
*/
#define DRAW_SETPIXEL_XRGB8888 \
DRAW_SETPIXEL(XRGB8888_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXEL_BLEND_XRGB8888 \
DRAW_SETPIXEL_BLEND(RGB_FROM_XRGB8888(*pixels, sr, sg, sb),\
XRGB8888_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888 \
DRAW_SETPIXEL_BLEND_CLAMPED(RGB_FROM_XRGB8888(*pixels, sr, sg, sb),\
XRGB8888_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXEL_ADD_XRGB8888 \
DRAW_SETPIXEL_ADD(RGB_FROM_XRGB8888(*pixels, sr, sg, sb),\
XRGB8888_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXEL_MOD_XRGB8888 \
DRAW_SETPIXEL_MOD(RGB_FROM_XRGB8888(*pixels, sr, sg, sb),\
XRGB8888_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXEL_MUL_XRGB8888 \
DRAW_SETPIXEL_MUL(RGB_FROM_XRGB8888(*pixels, sr, sg, sb),\
XRGB8888_FROM_RGB(*pixels, sr, sg, sb))
#define DRAW_SETPIXELXY_XRGB8888(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_XRGB8888)
#define DRAW_SETPIXELXY_BLEND_XRGB8888(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_XRGB8888)
#define DRAW_SETPIXELXY_BLEND_CLAMPED_XRGB8888(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_CLAMPED_XRGB8888)
#define DRAW_SETPIXELXY_ADD_XRGB8888(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_ADD_XRGB8888)
#define DRAW_SETPIXELXY_MOD_XRGB8888(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MOD_XRGB8888)
#define DRAW_SETPIXELXY_MUL_XRGB8888(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MUL_XRGB8888)
/*
* Define draw operators for ARGB8888
*/
#define DRAW_SETPIXEL_ARGB8888 \
DRAW_SETPIXEL(ARGB8888_FROM_RGBA(*pixels, sr, sg, sb, sa))
#define DRAW_SETPIXEL_BLEND_ARGB8888 \
DRAW_SETPIXEL_BLEND(RGBA_FROM_ARGB8888(*pixels, sr, sg, sb, sa),\
ARGB8888_FROM_RGBA(*pixels, sr, sg, sb, sa))
#define DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888 \
DRAW_SETPIXEL_BLEND_CLAMPED(RGBA_FROM_ARGB8888(*pixels, sr, sg, sb, sa),\
ARGB8888_FROM_RGBA(*pixels, sr, sg, sb, sa))
#define DRAW_SETPIXEL_ADD_ARGB8888 \
DRAW_SETPIXEL_ADD(RGBA_FROM_ARGB8888(*pixels, sr, sg, sb, sa),\
ARGB8888_FROM_RGBA(*pixels, sr, sg, sb, sa))
#define DRAW_SETPIXEL_MOD_ARGB8888 \
DRAW_SETPIXEL_MOD(RGBA_FROM_ARGB8888(*pixels, sr, sg, sb, sa),\
ARGB8888_FROM_RGBA(*pixels, sr, sg, sb, sa))
#define DRAW_SETPIXEL_MUL_ARGB8888 \
DRAW_SETPIXEL_MUL(RGBA_FROM_ARGB8888(*pixels, sr, sg, sb, sa),\
ARGB8888_FROM_RGBA(*pixels, sr, sg, sb, sa))
#define DRAW_SETPIXELXY_ARGB8888(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_ARGB8888)
#define DRAW_SETPIXELXY_BLEND_ARGB8888(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_ARGB8888)
#define DRAW_SETPIXELXY_BLEND_CLAMPED_ARGB8888(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_CLAMPED_ARGB8888)
#define DRAW_SETPIXELXY_ADD_ARGB8888(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_ADD_ARGB8888)
#define DRAW_SETPIXELXY_MOD_ARGB8888(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MOD_ARGB8888)
#define DRAW_SETPIXELXY_MUL_ARGB8888(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MUL_ARGB8888)
/*
* Define draw operators for general RGB
*/
#define DRAW_SETPIXEL_RGB \
DRAW_SETPIXEL(PIXEL_FROM_RGB(*pixels, fmt, sr, sg, sb))
#define DRAW_SETPIXEL_BLEND_RGB \
DRAW_SETPIXEL_BLEND(RGB_FROM_PIXEL(*pixels, fmt, sr, sg, sb),\
PIXEL_FROM_RGB(*pixels, fmt, sr, sg, sb))
#define DRAW_SETPIXEL_BLEND_CLAMPED_RGB \
DRAW_SETPIXEL_BLEND_CLAMPED(RGB_FROM_PIXEL(*pixels, fmt, sr, sg, sb),\
PIXEL_FROM_RGB(*pixels, fmt, sr, sg, sb))
#define DRAW_SETPIXEL_ADD_RGB \
DRAW_SETPIXEL_ADD(RGB_FROM_PIXEL(*pixels, fmt, sr, sg, sb),\
PIXEL_FROM_RGB(*pixels, fmt, sr, sg, sb))
#define DRAW_SETPIXEL_MOD_RGB \
DRAW_SETPIXEL_MOD(RGB_FROM_PIXEL(*pixels, fmt, sr, sg, sb),\
PIXEL_FROM_RGB(*pixels, fmt, sr, sg, sb))
#define DRAW_SETPIXEL_MUL_RGB \
DRAW_SETPIXEL_MUL(RGB_FROM_PIXEL(*pixels, fmt, sr, sg, sb),\
PIXEL_FROM_RGB(*pixels, fmt, sr, sg, sb))
#define DRAW_SETPIXELXY2_RGB(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_RGB)
#define DRAW_SETPIXELXY4_RGB(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_RGB)
#define DRAW_SETPIXELXY2_BLEND_RGB(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_RGB)
#define DRAW_SETPIXELXY2_BLEND_CLAMPED_RGB(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_BLEND_CLAMPED_RGB)
#define DRAW_SETPIXELXY4_BLEND_RGB(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_RGB)
#define DRAW_SETPIXELXY4_BLEND_CLAMPED_RGB(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_CLAMPED_RGB)
#define DRAW_SETPIXELXY2_ADD_RGB(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_ADD_RGB)
#define DRAW_SETPIXELXY4_ADD_RGB(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_ADD_RGB)
#define DRAW_SETPIXELXY2_MOD_RGB(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MOD_RGB)
#define DRAW_SETPIXELXY4_MOD_RGB(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MOD_RGB)
#define DRAW_SETPIXELXY2_MUL_RGB(x, y) \
DRAW_SETPIXELXY(x, y, Uint16, 2, DRAW_SETPIXEL_MUL_RGB)
#define DRAW_SETPIXELXY4_MUL_RGB(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MUL_RGB)
/*
* Define draw operators for general RGBA
*/
#define DRAW_SETPIXEL_RGBA \
DRAW_SETPIXEL(PIXEL_FROM_RGBA(*pixels, fmt, sr, sg, sb, sa))
#define DRAW_SETPIXEL_BLEND_RGBA \
DRAW_SETPIXEL_BLEND(RGBA_FROM_PIXEL(*pixels, fmt, sr, sg, sb, sa),\
PIXEL_FROM_RGBA(*pixels, fmt, sr, sg, sb, sa))
#define DRAW_SETPIXEL_BLEND_CLAMPED_RGBA \
DRAW_SETPIXEL_BLEND_CLAMPED(RGBA_FROM_PIXEL(*pixels, fmt, sr, sg, sb, sa),\
PIXEL_FROM_RGBA(*pixels, fmt, sr, sg, sb, sa))
#define DRAW_SETPIXEL_ADD_RGBA \
DRAW_SETPIXEL_ADD(RGBA_FROM_PIXEL(*pixels, fmt, sr, sg, sb, sa),\
PIXEL_FROM_RGBA(*pixels, fmt, sr, sg, sb, sa))
#define DRAW_SETPIXEL_MOD_RGBA \
DRAW_SETPIXEL_MOD(RGBA_FROM_PIXEL(*pixels, fmt, sr, sg, sb, sa),\
PIXEL_FROM_RGBA(*pixels, fmt, sr, sg, sb, sa))
#define DRAW_SETPIXEL_MUL_RGBA \
DRAW_SETPIXEL_MUL(RGBA_FROM_PIXEL(*pixels, fmt, sr, sg, sb, sa),\
PIXEL_FROM_RGBA(*pixels, fmt, sr, sg, sb, sa))
#define DRAW_SETPIXELXY4_RGBA(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_RGBA)
#define DRAW_SETPIXELXY4_BLEND_RGBA(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_RGBA)
#define DRAW_SETPIXELXY4_BLEND_CLAMPED_RGBA(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_BLEND_CLAMPED_RGBA)
#define DRAW_SETPIXELXY4_ADD_RGBA(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_ADD_RGBA)
#define DRAW_SETPIXELXY4_MOD_RGBA(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MOD_RGBA)
#define DRAW_SETPIXELXY4_MUL_RGBA(x, y) \
DRAW_SETPIXELXY(x, y, Uint32, 4, DRAW_SETPIXEL_MUL_RGBA)
/*
* Define line drawing macro
*/
#define ABS(_x) ((_x) < 0 ? -(_x) : (_x))
// Horizontal line
#define HLINE(type, op, draw_end) \
{ \
int length; \
int pitch = (dst->pitch / dst->fmt->bytes_per_pixel); \
type *pixels; \
if (x1 <= x2) { \
pixels = (type *)dst->pixels + y1 * pitch + x1; \
length = draw_end ? (x2 - x1 + 1) : (x2 - x1); \
} else { \
pixels = (type *)dst->pixels + y1 * pitch + x2; \
if (!draw_end) { \
++pixels; \
} \
length = draw_end ? (x1 - x2 + 1) : (x1 - x2); \
} \
while (length--) { \
op; \
++pixels; \
} \
}
// Vertical line
#define VLINE(type, op, draw_end) \
{ \
int length; \
int pitch = (dst->pitch / dst->fmt->bytes_per_pixel); \
type *pixels; \
if (y1 <= y2) { \
pixels = (type *)dst->pixels + y1 * pitch + x1; \
length = draw_end ? (y2 - y1 + 1) : (y2 - y1); \
} else { \
pixels = (type *)dst->pixels + y2 * pitch + x1; \
if (!draw_end) { \
pixels += pitch; \
} \
length = draw_end ? (y1 - y2 + 1) : (y1 - y2); \
} \
while (length--) { \
op; \
pixels += pitch; \
} \
}
// Diagonal line
#define DLINE(type, op, draw_end) \
{ \
int length; \
int pitch = (dst->pitch / dst->fmt->bytes_per_pixel); \
type *pixels; \
if (y1 <= y2) { \
pixels = (type *)dst->pixels + y1 * pitch + x1; \
if (x1 <= x2) { \
++pitch; \
} else { \
--pitch; \
} \
length = (y2 - y1); \
} else { \
pixels = (type *)dst->pixels + y2 * pitch + x2; \
if (x2 <= x1) { \
++pitch; \
} else { \
--pitch; \
} \
if (!draw_end) { \
pixels += pitch; \
} \
length = (y1 - y2); \
} \
if (draw_end) { \
++length; \
} \
while (length--) { \
op; \
pixels += pitch; \
} \
}
// Bresenham's line algorithm
#define BLINE(x1, y1, x2, y2, op, draw_end) \
{ \
int i, deltax, deltay, numpixels; \
int d, dinc1, dinc2; \
int x, xinc1, xinc2; \
int y, yinc1, yinc2; \
\
deltax = ABS(x2 - x1); \
deltay = ABS(y2 - y1); \
\
if (deltax >= deltay) { \
numpixels = deltax + 1; \
d = (2 * deltay) - deltax; \
dinc1 = deltay * 2; \
dinc2 = (deltay - deltax) * 2; \
xinc1 = 1; \
xinc2 = 1; \
yinc1 = 0; \
yinc2 = 1; \
} else { \
numpixels = deltay + 1; \
d = (2 * deltax) - deltay; \
dinc1 = deltax * 2; \
dinc2 = (deltax - deltay) * 2; \
xinc1 = 0; \
xinc2 = 1; \
yinc1 = 1; \
yinc2 = 1; \
} \
\
if (x1 > x2) { \
xinc1 = -xinc1; \
xinc2 = -xinc2; \
} \
if (y1 > y2) { \
yinc1 = -yinc1; \
yinc2 = -yinc2; \
} \
\
x = x1; \
y = y1; \
\
if (!draw_end) { \
--numpixels; \
} \
for (i = 0; i < numpixels; ++i) { \
op(x, y); \
if (d < 0) { \
d += dinc1; \
x += xinc1; \
y += yinc1; \
} else { \
d += dinc2; \
x += xinc2; \
y += yinc2; \
} \
} \
}
// Xiaolin Wu's line algorithm, based on Michael Abrash's implementation
#define WULINE(x1, y1, x2, y2, opaque_op, blend_op, draw_end) \
{ \
Uint16 ErrorAdj, ErrorAcc; \
Uint16 ErrorAccTemp, Weighting; \
int DeltaX, DeltaY, Temp, XDir; \
unsigned r, g, b, a, inva; \
\
/* Draw the initial pixel, which is always exactly intersected by \
the line and so needs no weighting */ \
opaque_op(x1, y1); \
\
/* Draw the final pixel, which is always exactly intersected by the line \
and so needs no weighting */ \
if (draw_end) { \
opaque_op(x2, y2); \
} \
\
/* Make sure the line runs top to bottom */ \
if (y1 > y2) { \
Temp = y1; \
y1 = y2; \
y2 = Temp; \
Temp = x1; \
x1 = x2; \
x2 = Temp; \
} \
DeltaY = y2 - y1; \
\
if ((DeltaX = x2 - x1) >= 0) { \
XDir = 1; \
} else { \
XDir = -1; \
DeltaX = -DeltaX; /* make DeltaX positive */ \
} \
\
/* line is not horizontal, diagonal, or vertical */ \
ErrorAcc = 0; /* initialize the line error accumulator to 0 */ \
\
/* Is this an X-major or Y-major line? */ \
if (DeltaY > DeltaX) { \
/* Y-major line; calculate 16-bit fixed-point fractional part of a \
pixel that X advances each time Y advances 1 pixel, truncating the \
result so that we won't overrun the endpoint along the X axis */ \
ErrorAdj = ((unsigned long)DeltaX << 16) / (unsigned long)DeltaY; \
/* Draw all pixels other than the first and last */ \
while (--DeltaY) { \
ErrorAccTemp = ErrorAcc; /* remember current accumulated error */ \
ErrorAcc += ErrorAdj; /* calculate error for next pixel */ \
if (ErrorAcc <= ErrorAccTemp) { \
/* The error accumulator turned over, so advance the X coord */ \
x1 += XDir; \
} \
y1++; /* Y-major, so always advance Y */ \
/* The IntensityBits most significant bits of ErrorAcc give us the \
intensity weighting for this pixel, and the complement of the \
weighting for the paired pixel */ \
Weighting = ErrorAcc >> 8; \
{ \
a = DRAW_MUL(_a, (Weighting ^ 255)); \
r = DRAW_MUL(_r, a); \
g = DRAW_MUL(_g, a); \
b = DRAW_MUL(_b, a); \
inva = (a ^ 0xFF); \
blend_op(x1, y1); \
} \
{ \
a = DRAW_MUL(_a, Weighting); \
r = DRAW_MUL(_r, a); \
g = DRAW_MUL(_g, a); \
b = DRAW_MUL(_b, a); \
inva = (a ^ 0xFF); \
blend_op(x1 + XDir, y1); \
} \
} \
} else { \
/* X-major line; calculate 16-bit fixed-point fractional part of a \
pixel that Y advances each time X advances 1 pixel, truncating the \
result to avoid overrunning the endpoint along the X axis */ \
ErrorAdj = ((unsigned long)DeltaY << 16) / (unsigned long)DeltaX; \
/* Draw all pixels other than the first and last */ \
while (--DeltaX) { \
ErrorAccTemp = ErrorAcc; /* remember current accumulated error */ \
ErrorAcc += ErrorAdj; /* calculate error for next pixel */ \
if (ErrorAcc <= ErrorAccTemp) { \
/* The error accumulator turned over, so advance the Y coord */ \
y1++; \
} \
x1 += XDir; /* X-major, so always advance X */ \
/* The IntensityBits most significant bits of ErrorAcc give us the \
intensity weighting for this pixel, and the complement of the \
weighting for the paired pixel */ \
Weighting = ErrorAcc >> 8; \
{ \
a = DRAW_MUL(_a, (Weighting ^ 255)); \
r = DRAW_MUL(_r, a); \
g = DRAW_MUL(_g, a); \
b = DRAW_MUL(_b, a); \
inva = (a ^ 0xFF); \
blend_op(x1, y1); \
} \
{ \
a = DRAW_MUL(_a, Weighting); \
r = DRAW_MUL(_r, a); \
g = DRAW_MUL(_g, a); \
b = DRAW_MUL(_b, a); \
inva = (a ^ 0xFF); \
blend_op(x1, y1 + 1); \
} \
} \
} \
}
#ifdef AA_LINES
#define AALINE(x1, y1, x2, y2, opaque_op, blend_op, draw_end) \
WULINE(x1, y1, x2, y2, opaque_op, blend_op, draw_end)
#else
#define AALINE(x1, y1, x2, y2, opaque_op, blend_op, draw_end) \
BLINE(x1, y1, x2, y2, opaque_op, draw_end)
#endif
/*
* Define fill rect macro
*/
#define FILLRECT(type, op) \
do { \
int width = rect->w; \
int height = rect->h; \
int pitch = (dst->pitch / dst->fmt->bytes_per_pixel); \
int skip = pitch - width; \
type *pixels = (type *)dst->pixels + rect->y * pitch + rect->x;\
while (height--) { \
{ \
int n = (width + 3) / 4; \
switch (width & 3) { \
case 0: \
do { \
op; \
pixels++; \
SDL_FALLTHROUGH; \
case 3: \
op; \
pixels++; \
SDL_FALLTHROUGH; \
case 2: \
op; \
pixels++; \
SDL_FALLTHROUGH; \
case 1: \
op; \
pixels++; \
} while (--n > 0); \
} \
} \
pixels += skip; \
} \
} while (0)
@@ -0,0 +1,199 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_RENDER_SW
#include "SDL_draw.h"
#include "SDL_drawline.h"
#include "SDL_drawpoint.h"
static void SDL_DrawLine1(SDL_Surface *dst, int x1, int y1, int x2, int y2, Uint32 color,
bool draw_end)
{
if (y1 == y2) {
int length;
int pitch = (dst->pitch / dst->fmt->bytes_per_pixel);
Uint8 *pixels;
if (x1 <= x2) {
pixels = (Uint8 *)dst->pixels + y1 * pitch + x1;
length = draw_end ? (x2 - x1 + 1) : (x2 - x1);
} else {
pixels = (Uint8 *)dst->pixels + y1 * pitch + x2;
if (!draw_end) {
++pixels;
}
length = draw_end ? (x1 - x2 + 1) : (x1 - x2);
}
SDL_memset(pixels, color, length);
} else if (x1 == x2) {
VLINE(Uint8, DRAW_FASTSETPIXEL1, draw_end);
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
DLINE(Uint8, DRAW_FASTSETPIXEL1, draw_end);
} else {
BLINE(x1, y1, x2, y2, DRAW_FASTSETPIXELXY1, draw_end);
}
}
static void SDL_DrawLine2(SDL_Surface *dst, int x1, int y1, int x2, int y2, Uint32 color,
bool draw_end)
{
if (y1 == y2) {
HLINE(Uint16, DRAW_FASTSETPIXEL2, draw_end);
} else if (x1 == x2) {
VLINE(Uint16, DRAW_FASTSETPIXEL2, draw_end);
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
DLINE(Uint16, DRAW_FASTSETPIXEL2, draw_end);
} else {
Uint8 _r, _g, _b, _a;
const SDL_PixelFormatDetails *fmt = dst->fmt;
SDL_GetRGBA(color, fmt, dst->palette, &_r, &_g, &_b, &_a);
if (fmt->Rmask == 0x7C00) {
AALINE(x1, y1, x2, y2,
DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY_BLEND_RGB555,
draw_end);
} else if (fmt->Rmask == 0xF800) {
AALINE(x1, y1, x2, y2,
DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY_BLEND_RGB565,
draw_end);
} else {
AALINE(x1, y1, x2, y2,
DRAW_FASTSETPIXELXY2, DRAW_SETPIXELXY2_BLEND_RGB,
draw_end);
}
}
}
static void SDL_DrawLine4(SDL_Surface *dst, int x1, int y1, int x2, int y2, Uint32 color,
bool draw_end)
{
if (y1 == y2) {
HLINE(Uint32, DRAW_FASTSETPIXEL4, draw_end);
} else if (x1 == x2) {
VLINE(Uint32, DRAW_FASTSETPIXEL4, draw_end);
} else if (ABS(x1 - x2) == ABS(y1 - y2)) {
DLINE(Uint32, DRAW_FASTSETPIXEL4, draw_end);
} else {
Uint8 _r, _g, _b, _a;
const SDL_PixelFormatDetails *fmt = dst->fmt;
SDL_GetRGBA(color, fmt, dst->palette, &_r, &_g, &_b, &_a);
if (fmt->Rmask == 0x00FF0000) {
if (!fmt->Amask) {
AALINE(x1, y1, x2, y2,
DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY_BLEND_XRGB8888,
draw_end);
} else {
AALINE(x1, y1, x2, y2,
DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY_BLEND_ARGB8888,
draw_end);
}
} else {
AALINE(x1, y1, x2, y2,
DRAW_FASTSETPIXELXY4, DRAW_SETPIXELXY4_BLEND_RGB,
draw_end);
}
}
}
typedef void (*DrawLineFunc)(SDL_Surface *dst,
int x1, int y1, int x2, int y2,
Uint32 color, bool draw_end);
static DrawLineFunc SDL_CalculateDrawLineFunc(const SDL_PixelFormatDetails *fmt)
{
switch (fmt->bytes_per_pixel) {
case 1:
if (fmt->bits_per_pixel < 8) {
break;
}
return SDL_DrawLine1;
case 2:
return SDL_DrawLine2;
case 4:
return SDL_DrawLine4;
}
return NULL;
}
bool SDL_DrawLine(SDL_Surface *dst, int x1, int y1, int x2, int y2, Uint32 color)
{
DrawLineFunc func;
if (!SDL_SurfaceValid(dst)) {
return SDL_InvalidParamError("SDL_DrawLine(): dst");
}
func = SDL_CalculateDrawLineFunc(dst->fmt);
if (!func) {
return SDL_SetError("SDL_DrawLine(): Unsupported surface format");
}
// Perform clipping
// FIXME: We don't actually want to clip, as it may change line slope
if (!SDL_GetRectAndLineIntersection(&dst->clip_rect, &x1, &y1, &x2, &y2)) {
return true;
}
func(dst, x1, y1, x2, y2, color, true);
return true;
}
bool SDL_DrawLines(SDL_Surface *dst, const SDL_Point *points, int count, Uint32 color)
{
int i;
int x1, y1;
int x2, y2;
bool draw_end;
DrawLineFunc func;
if (!SDL_SurfaceValid(dst)) {
return SDL_InvalidParamError("SDL_DrawLines(): dst");
}
func = SDL_CalculateDrawLineFunc(dst->fmt);
if (!func) {
return SDL_SetError("SDL_DrawLines(): Unsupported surface format");
}
for (i = 1; i < count; ++i) {
x1 = points[i - 1].x;
y1 = points[i - 1].y;
x2 = points[i].x;
y2 = points[i].y;
// Perform clipping
// FIXME: We don't actually want to clip, as it may change line slope
if (!SDL_GetRectAndLineIntersection(&dst->clip_rect, &x1, &y1, &x2, &y2)) {
continue;
}
// Draw the end if the whole line is a single point or it was clipped
draw_end = ((x1 == x2) && (y1 == y2)) || (x2 != points[i].x || y2 != points[i].y);
func(dst, x1, y1, x2, y2, color, draw_end);
}
if (points[0].x != points[count - 1].x || points[0].y != points[count - 1].y) {
SDL_DrawPoint(dst, points[count - 1].x, points[count - 1].y, color);
}
return true;
}
#endif // SDL_VIDEO_RENDER_SW
@@ -0,0 +1,30 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_drawline_h_
#define SDL_drawline_h_
#include "SDL_internal.h"
extern bool SDL_DrawLine(SDL_Surface *dst, int x1, int y1, int x2, int y2, Uint32 color);
extern bool SDL_DrawLines(SDL_Surface *dst, const SDL_Point *points, int count, Uint32 color);
#endif // SDL_drawline_h_
@@ -0,0 +1,108 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_RENDER_SW
#include "SDL_draw.h"
#include "SDL_drawpoint.h"
bool SDL_DrawPoint(SDL_Surface *dst, int x, int y, Uint32 color)
{
if (!SDL_SurfaceValid(dst)) {
return SDL_InvalidParamError("SDL_DrawPoint(): dst");
}
// This function doesn't work on surfaces < 8 bpp
if (dst->fmt->bits_per_pixel < 8) {
return SDL_SetError("SDL_DrawPoint(): Unsupported surface format");
}
// Perform clipping
if (x < dst->clip_rect.x || y < dst->clip_rect.y ||
x >= (dst->clip_rect.x + dst->clip_rect.w) ||
y >= (dst->clip_rect.y + dst->clip_rect.h)) {
return true;
}
switch (dst->fmt->bytes_per_pixel) {
case 1:
DRAW_FASTSETPIXELXY1(x, y);
break;
case 2:
DRAW_FASTSETPIXELXY2(x, y);
break;
case 3:
return SDL_Unsupported();
case 4:
DRAW_FASTSETPIXELXY4(x, y);
break;
}
return true;
}
bool SDL_DrawPoints(SDL_Surface *dst, const SDL_Point *points, int count, Uint32 color)
{
int minx, miny;
int maxx, maxy;
int i;
int x, y;
if (!SDL_SurfaceValid(dst)) {
return SDL_InvalidParamError("SDL_DrawPoints(): dst");
}
// This function doesn't work on surfaces < 8 bpp
if (dst->fmt->bits_per_pixel < 8) {
return SDL_SetError("SDL_DrawPoints(): Unsupported surface format");
}
minx = dst->clip_rect.x;
maxx = dst->clip_rect.x + dst->clip_rect.w - 1;
miny = dst->clip_rect.y;
maxy = dst->clip_rect.y + dst->clip_rect.h - 1;
for (i = 0; i < count; ++i) {
x = points[i].x;
y = points[i].y;
if (x < minx || x > maxx || y < miny || y > maxy) {
continue;
}
switch (dst->fmt->bytes_per_pixel) {
case 1:
DRAW_FASTSETPIXELXY1(x, y);
break;
case 2:
DRAW_FASTSETPIXELXY2(x, y);
break;
case 3:
return SDL_Unsupported();
case 4:
DRAW_FASTSETPIXELXY4(x, y);
break;
}
}
return true;
}
#endif // SDL_VIDEO_RENDER_SW
@@ -0,0 +1,30 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_drawpoint_h_
#define SDL_drawpoint_h_
#include "SDL_internal.h"
extern bool SDL_DrawPoint(SDL_Surface *dst, int x, int y, Uint32 color);
extern bool SDL_DrawPoints(SDL_Surface *dst, const SDL_Point *points, int count, Uint32 color);
#endif // SDL_drawpoint_h_
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,27 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_render_sw_c_h_
#define SDL_render_sw_c_h_
extern bool SW_CreateRendererForSurface(SDL_Renderer *renderer, SDL_Surface *surface, SDL_PropertiesID create_props);
#endif // SDL_render_sw_c_h_
@@ -0,0 +1,612 @@
/*
SDL_rotate.c: rotates 32bit or 8bit surfaces
Shamelessly stolen from SDL_gfx by Andreas Schiffler. Original copyright follows:
Copyright (C) 2001-2011 Andreas Schiffler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
Andreas Schiffler -- aschiffler at ferzkopp dot net
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_RENDER_SW
#if defined(SDL_PLATFORM_WINDOWS)
#include "../../core/windows/SDL_windows.h"
#endif
#include "SDL_rotate.h"
#include "../../video/SDL_surface_c.h"
// ---- Internally used structures
/**
A 32 bit RGBA pixel.
*/
typedef struct tColorRGBA
{
Uint8 r;
Uint8 g;
Uint8 b;
Uint8 a;
} tColorRGBA;
/**
A 8bit Y/palette pixel.
*/
typedef struct tColorY
{
Uint8 y;
} tColorY;
/**
Number of guard rows added to destination surfaces.
This is a simple but effective workaround for observed issues.
These rows allocate extra memory and are then hidden from the surface.
Rows are added to the end of destination surfaces when they are allocated.
This catches any potential overflows which seem to happen with
just the right src image dimensions and scale/rotation and can lead
to a situation where the program can segfault.
*/
#define GUARD_ROWS (2)
/**
Returns colorkey info for a surface
*/
static Uint32 get_colorkey(SDL_Surface *src)
{
Uint32 key = 0;
if (SDL_SurfaceHasColorKey(src)) {
SDL_GetSurfaceColorKey(src, &key);
}
return key;
}
// rotate (sx, sy) by (angle, center) into (dx, dy)
static void rotate(double sx, double sy, double sinangle, double cosangle, const SDL_FPoint *center, double *dx, double *dy)
{
sx -= center->x;
sy -= center->y;
*dx = cosangle * sx - sinangle * sy;
*dy = sinangle * sx + cosangle * sy;
*dx += center->x;
*dy += center->y;
}
/**
Internal target surface sizing function for rotations with trig result return.
\param width The source surface width.
\param height The source surface height.
\param angle The angle to rotate in degrees.
\param center The center of ratation
\param rect_dest Bounding box of rotated rectangle
\param cangle The sine of the angle
\param sangle The cosine of the angle
*/
void SDLgfx_rotozoomSurfaceSizeTrig(int width, int height, double angle, const SDL_FPoint *center,
SDL_Rect *rect_dest, double *cangle, double *sangle)
{
int minx, maxx, miny, maxy;
double radangle;
double x0, x1, x2, x3;
double y0, y1, y2, y3;
double sinangle;
double cosangle;
radangle = angle * (SDL_PI_D / 180.0);
sinangle = SDL_sin(radangle);
cosangle = SDL_cos(radangle);
/*
* Determine destination width and height by rotating a source box, at pixel center
*/
rotate(0.5, 0.5, sinangle, cosangle, center, &x0, &y0);
rotate(width - 0.5, 0.5, sinangle, cosangle, center, &x1, &y1);
rotate(0.5, height - 0.5, sinangle, cosangle, center, &x2, &y2);
rotate(width - 0.5, height - 0.5, sinangle, cosangle, center, &x3, &y3);
minx = (int)SDL_floor(SDL_min(SDL_min(x0, x1), SDL_min(x2, x3)));
maxx = (int)SDL_ceil(SDL_max(SDL_max(x0, x1), SDL_max(x2, x3)));
miny = (int)SDL_floor(SDL_min(SDL_min(y0, y1), SDL_min(y2, y3)));
maxy = (int)SDL_ceil(SDL_max(SDL_max(y0, y1), SDL_max(y2, y3)));
rect_dest->w = maxx - minx;
rect_dest->h = maxy - miny;
rect_dest->x = minx;
rect_dest->y = miny;
// reverse the angle because our rotations are clockwise
*sangle = -sinangle;
*cangle = cosangle;
{
// The trig code below gets the wrong size (due to FP inaccuracy?) when angle is a multiple of 90 degrees
int angle90 = (int)(angle / 90);
if (angle90 == angle / 90) { // if the angle is a multiple of 90 degrees
angle90 %= 4;
if (angle90 < 0) {
angle90 += 4; // 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg
}
if (angle90 & 1) {
rect_dest->w = height;
rect_dest->h = width;
*cangle = 0;
*sangle = angle90 == 1 ? -1 : 1; // reversed because our rotations are clockwise
} else {
rect_dest->w = width;
rect_dest->h = height;
*cangle = angle90 == 0 ? 1 : -1;
*sangle = 0;
}
}
}
}
// Computes source pointer X/Y increments for a rotation that's a multiple of 90 degrees.
static void computeSourceIncrements90(SDL_Surface *src, int bpp, int angle, int flipx, int flipy,
int *sincx, int *sincy, int *signx, int *signy)
{
int pitch = flipy ? -src->pitch : src->pitch;
if (flipx) {
bpp = -bpp;
}
switch (angle) { // 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg
case 0:
*sincx = bpp;
*sincy = pitch - src->w * *sincx;
*signx = *signy = 1;
break;
case 1:
*sincx = -pitch;
*sincy = bpp - *sincx * src->h;
*signx = 1;
*signy = -1;
break;
case 2:
*sincx = -bpp;
*sincy = -src->w * *sincx - pitch;
*signx = *signy = -1;
break;
case 3:
default:
*sincx = pitch;
*sincy = -*sincx * src->h - bpp;
*signx = -1;
*signy = 1;
break;
}
if (flipx) {
*signx = -*signx;
}
if (flipy) {
*signy = -*signy;
}
}
// Performs a relatively fast rotation/flip when the angle is a multiple of 90 degrees.
#define TRANSFORM_SURFACE_90(pixelType) \
int dy, dincy = dst->pitch - dst->w * sizeof(pixelType), sincx, sincy, signx, signy; \
Uint8 *sp = (Uint8 *)src->pixels, *dp = (Uint8 *)dst->pixels, *de; \
\
computeSourceIncrements90(src, sizeof(pixelType), angle, flipx, flipy, &sincx, &sincy, &signx, &signy); \
if (signx < 0) \
sp += (src->w - 1) * sizeof(pixelType); \
if (signy < 0) \
sp += (src->h - 1) * src->pitch; \
\
for (dy = 0; dy < dst->h; sp += sincy, dp += dincy, dy++) { \
if (sincx == sizeof(pixelType)) { /* if advancing src and dest equally, use SDL_memcpy */ \
SDL_memcpy(dp, sp, dst->w * sizeof(pixelType)); \
sp += dst->w * sizeof(pixelType); \
dp += dst->w * sizeof(pixelType); \
} else { \
for (de = dp + dst->w * sizeof(pixelType); dp != de; sp += sincx, dp += sizeof(pixelType)) { \
*(pixelType *)dp = *(pixelType *)sp; \
} \
} \
}
static void transformSurfaceRGBA90(SDL_Surface *src, SDL_Surface *dst, int angle, int flipx, int flipy)
{
TRANSFORM_SURFACE_90(tColorRGBA);
}
static void transformSurfaceY90(SDL_Surface *src, SDL_Surface *dst, int angle, int flipx, int flipy)
{
TRANSFORM_SURFACE_90(tColorY);
}
#undef TRANSFORM_SURFACE_90
/**
Internal 32 bit rotozoomer with optional anti-aliasing.
Rotates and zooms 32 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
parameters by scanning the destination surface and applying optionally anti-aliasing
by bilinear interpolation.
Assumes src and dst surfaces are of 32 bit depth.
Assumes dst surface was allocated with the correct dimensions.
\param src Source surface.
\param dst Destination surface.
\param isin Integer version of sine of angle.
\param icos Integer version of cosine of angle.
\param flipx Flag indicating horizontal mirroring should be applied.
\param flipy Flag indicating vertical mirroring should be applied.
\param smooth Flag indicating anti-aliasing should be used.
\param rect_dest destination coordinates
\param center true center.
*/
static void transformSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst, int isin, int icos,
int flipx, int flipy, int smooth,
const SDL_Rect *rect_dest,
const SDL_FPoint *center)
{
int sw, sh;
int cx, cy;
tColorRGBA c00, c01, c10, c11, cswap;
tColorRGBA *pc, *sp;
int gap;
const int fp_half = (1 << 15);
/*
* Variable setup
*/
sw = src->w - 1;
sh = src->h - 1;
pc = (tColorRGBA *)dst->pixels;
gap = dst->pitch - dst->w * 4;
cx = (int)(center->x * 65536.0);
cy = (int)(center->y * 65536.0);
/*
* Switch between interpolating and non-interpolating code
*/
if (smooth) {
int y;
for (y = 0; y < dst->h; y++) {
int x;
double src_x = ((double)rect_dest->x + 0 + 0.5 - center->x);
double src_y = ((double)rect_dest->y + y + 0.5 - center->y);
int sdx = (int)((icos * src_x - isin * src_y) + cx - fp_half);
int sdy = (int)((isin * src_x + icos * src_y) + cy - fp_half);
for (x = 0; x < dst->w; x++) {
int dx = (sdx >> 16);
int dy = (sdy >> 16);
if (flipx) {
dx = sw - dx;
}
if (flipy) {
dy = sh - dy;
}
if ((dx > -1) && (dy > -1) && (dx < (src->w - 1)) && (dy < (src->h - 1))) {
int ex, ey;
int t1, t2;
sp = (tColorRGBA *)((Uint8 *)src->pixels + src->pitch * dy) + dx;
c00 = *sp;
sp += 1;
c01 = *sp;
sp += (src->pitch / 4);
c11 = *sp;
sp -= 1;
c10 = *sp;
if (flipx) {
cswap = c00;
c00 = c01;
c01 = cswap;
cswap = c10;
c10 = c11;
c11 = cswap;
}
if (flipy) {
cswap = c00;
c00 = c10;
c10 = cswap;
cswap = c01;
c01 = c11;
c11 = cswap;
}
/*
* Interpolate colors
*/
ex = (sdx & 0xffff);
ey = (sdy & 0xffff);
t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
pc->r = (Uint8)((((t2 - t1) * ey) >> 16) + t1);
t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
pc->g = (Uint8)((((t2 - t1) * ey) >> 16) + t1);
t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
pc->b = (Uint8)((((t2 - t1) * ey) >> 16) + t1);
t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
pc->a = (Uint8)((((t2 - t1) * ey) >> 16) + t1);
}
sdx += icos;
sdy += isin;
pc++;
}
pc = (tColorRGBA *)((Uint8 *)pc + gap);
}
} else {
int y;
for (y = 0; y < dst->h; y++) {
int x;
double src_x = ((double)rect_dest->x + 0 + 0.5 - center->x);
double src_y = ((double)rect_dest->y + y + 0.5 - center->y);
int sdx = (int)((icos * src_x - isin * src_y) + cx - fp_half);
int sdy = (int)((isin * src_x + icos * src_y) + cy - fp_half);
for (x = 0; x < dst->w; x++) {
int dx = (sdx >> 16);
int dy = (sdy >> 16);
if ((unsigned)dx < (unsigned)src->w && (unsigned)dy < (unsigned)src->h) {
if (flipx) {
dx = sw - dx;
}
if (flipy) {
dy = sh - dy;
}
*pc = *((tColorRGBA *)((Uint8 *)src->pixels + src->pitch * dy) + dx);
}
sdx += icos;
sdy += isin;
pc++;
}
pc = (tColorRGBA *)((Uint8 *)pc + gap);
}
}
}
/**
Rotates and zooms 8 bit palette/Y 'src' surface to 'dst' surface without smoothing.
Rotates and zooms 8 bit RGBA/ABGR 'src' surface to 'dst' surface based on the control
parameters by scanning the destination surface.
Assumes src and dst surfaces are of 8 bit depth.
Assumes dst surface was allocated with the correct dimensions.
\param src Source surface.
\param dst Destination surface.
\param isin Integer version of sine of angle.
\param icos Integer version of cosine of angle.
\param flipx Flag indicating horizontal mirroring should be applied.
\param flipy Flag indicating vertical mirroring should be applied.
\param rect_dest destination coordinates
\param center true center.
*/
static void transformSurfaceY(SDL_Surface *src, SDL_Surface *dst, int isin, int icos, int flipx, int flipy,
const SDL_Rect *rect_dest,
const SDL_FPoint *center)
{
int sw, sh;
int cx, cy;
tColorY *pc;
int gap;
const int fp_half = (1 << 15);
int y;
/*
* Variable setup
*/
sw = src->w - 1;
sh = src->h - 1;
pc = (tColorY *)dst->pixels;
gap = dst->pitch - dst->w;
cx = (int)(center->x * 65536.0);
cy = (int)(center->y * 65536.0);
/*
* Clear surface to colorkey
*/
SDL_memset(pc, (int)(get_colorkey(src) & 0xff), (size_t)dst->pitch * dst->h);
/*
* Iterate through destination surface
*/
for (y = 0; y < dst->h; y++) {
int x;
double src_x = ((double)rect_dest->x + 0 + 0.5 - center->x);
double src_y = ((double)rect_dest->y + y + 0.5 - center->y);
int sdx = (int)((icos * src_x - isin * src_y) + cx - fp_half);
int sdy = (int)((isin * src_x + icos * src_y) + cy - fp_half);
for (x = 0; x < dst->w; x++) {
int dx = (sdx >> 16);
int dy = (sdy >> 16);
if ((unsigned)dx < (unsigned)src->w && (unsigned)dy < (unsigned)src->h) {
if (flipx) {
dx = sw - dx;
}
if (flipy) {
dy = sh - dy;
}
*pc = *((tColorY *)src->pixels + src->pitch * dy + dx);
}
sdx += icos;
sdy += isin;
pc++;
}
pc += gap;
}
}
/**
Rotates and zooms a surface with different horizontal and vertival scaling factors and optional anti-aliasing.
Rotates a 32-bit or 8-bit 'src' surface to newly created 'dst' surface.
'angle' is the rotation in degrees, 'center' the rotation center. If 'smooth' is set
then the destination 32-bit surface is anti-aliased. 8-bit surfaces must have a colorkey. 32-bit
surfaces must have a 8888 layout with red, green, blue and alpha masks (any ordering goes).
The blend mode of the 'src' surface has some effects on generation of the 'dst' surface: The NONE
mode will set the BLEND mode on the 'dst' surface. The MOD mode either generates a white 'dst'
surface and sets the colorkey or fills the it with the colorkey before copying the pixels.
When using the NONE and MOD modes, color and alpha modulation must be applied before using this function.
\param src The surface to rotozoom.
\param angle The angle to rotate in degrees.
\param smooth Antialiasing flag; set to SMOOTHING_ON to enable.
\param flipx Set to 1 to flip the image horizontally
\param flipy Set to 1 to flip the image vertically
\param rect_dest The destination rect bounding box
\param cangle The angle cosine
\param sangle The angle sine
\param center The true coordinate of the center of rotation
\return The new rotated surface.
*/
SDL_Surface *SDLgfx_rotateSurface(SDL_Surface *src, double angle, int smooth, int flipx, int flipy,
const SDL_Rect *rect_dest, double cangle, double sangle, const SDL_FPoint *center)
{
SDL_Surface *rz_dst;
int is8bit, angle90;
SDL_BlendMode blendmode;
Uint32 colorkey = 0;
bool colorKeyAvailable = false;
double sangleinv, cangleinv;
// Sanity check
if (!SDL_SurfaceValid(src)) {
return NULL;
}
if (SDL_SurfaceHasColorKey(src)) {
if (SDL_GetSurfaceColorKey(src, &colorkey)) {
colorKeyAvailable = true;
}
}
// This function requires a 32-bit surface or 8-bit surface with a colorkey
is8bit = src->fmt->bits_per_pixel == 8 && colorKeyAvailable;
if (!(is8bit || (src->fmt->bits_per_pixel == 32 && SDL_ISPIXELFORMAT_ALPHA(src->format)))) {
return NULL;
}
// Calculate target factors from sine/cosine and zoom
sangleinv = sangle * 65536.0;
cangleinv = cangle * 65536.0;
// Alloc space to completely contain the rotated surface
rz_dst = NULL;
if (is8bit) {
// Target surface is 8 bit
rz_dst = SDL_CreateSurface(rect_dest->w, rect_dest->h + GUARD_ROWS, src->format);
if (rz_dst) {
SDL_SetSurfacePalette(rz_dst, src->palette);
}
} else {
// Target surface is 32 bit with source RGBA ordering
rz_dst = SDL_CreateSurface(rect_dest->w, rect_dest->h + GUARD_ROWS, src->format);
}
// Check target
if (!rz_dst) {
return NULL;
}
// Adjust for guard rows
rz_dst->h = rect_dest->h;
SDL_GetSurfaceBlendMode(src, &blendmode);
if (colorKeyAvailable) {
// If available, the colorkey will be used to discard the pixels that are outside of the rotated area.
SDL_SetSurfaceColorKey(rz_dst, true, colorkey);
SDL_FillSurfaceRect(rz_dst, NULL, colorkey);
} else if (blendmode == SDL_BLENDMODE_NONE) {
blendmode = SDL_BLENDMODE_BLEND;
} else if (blendmode == SDL_BLENDMODE_MOD || blendmode == SDL_BLENDMODE_MUL) {
/* Without a colorkey, the target texture has to be white for the MOD and MUL blend mode so
* that the pixels outside the rotated area don't affect the destination surface.
*/
colorkey = SDL_MapSurfaceRGBA(rz_dst, 255, 255, 255, 0);
SDL_FillSurfaceRect(rz_dst, NULL, colorkey);
/* Setting a white colorkey for the destination surface makes the final blit discard
* all pixels outside of the rotated area. This doesn't interfere with anything because
* white pixels are already a no-op and the MOD blend mode does not interact with alpha.
*/
SDL_SetSurfaceColorKey(rz_dst, true, colorkey);
}
SDL_SetSurfaceBlendMode(rz_dst, blendmode);
// Lock source surface
if (SDL_MUSTLOCK(src)) {
if (!SDL_LockSurface(src)) {
SDL_DestroySurface(rz_dst);
return NULL;
}
}
/* check if the rotation is a multiple of 90 degrees so we can take a fast path and also somewhat reduce
* the off-by-one problem in transformSurfaceRGBA that expresses itself when the rotation is near
* multiples of 90 degrees.
*/
angle90 = (int)(angle / 90);
if (angle90 == angle / 90) {
angle90 %= 4;
if (angle90 < 0) {
angle90 += 4; // 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg
}
} else {
angle90 = -1;
}
if (is8bit) {
// Call the 8-bit transformation routine to do the rotation
if (angle90 >= 0) {
transformSurfaceY90(src, rz_dst, angle90, flipx, flipy);
} else {
transformSurfaceY(src, rz_dst, (int)sangleinv, (int)cangleinv,
flipx, flipy, rect_dest, center);
}
} else {
// Call the 32-bit transformation routine to do the rotation
if (angle90 >= 0) {
transformSurfaceRGBA90(src, rz_dst, angle90, flipx, flipy);
} else {
transformSurfaceRGBA(src, rz_dst, (int)sangleinv, (int)cangleinv,
flipx, flipy, smooth, rect_dest, center);
}
}
// Unlock source surface
if (SDL_MUSTLOCK(src)) {
SDL_UnlockSurface(src);
}
// Return rotated surface
return rz_dst;
}
#endif // SDL_VIDEO_RENDER_SW
@@ -0,0 +1,30 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
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_
@@ -0,0 +1,956 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_RENDER_SW
#include <limits.h>
#include "SDL_triangle.h"
#include "../../video/SDL_surface_c.h"
/* fixed points bits precision
* Set to 1, so that it can start rendering with middle of a pixel precision.
* It doesn't need to be increased.
* But, if increased too much, it overflows (srcx, srcy) coordinates used for filling with texture.
* (which could be turned to int64).
*/
#define FP_BITS 1
#define COLOR_EQ(c1, c2) ((c1).r == (c2).r && (c1).g == (c2).g && (c1).b == (c2).b && (c1).a == (c2).a)
static void SDL_BlitTriangle_Slow(SDL_BlitInfo *info,
SDL_Point s2_x_area, SDL_Rect dstrect, int area, int bias_w0, int bias_w1, int bias_w2,
int d2d1_y, int d1d2_x, int d0d2_y, int d2d0_x, int d1d0_y, int d0d1_x,
int s2s0_x, int s2s1_x, int s2s0_y, int s2s1_y, int w0_row, int w1_row, int w2_row,
SDL_Color c0, SDL_Color c1, SDL_Color c2, bool is_uniform,
SDL_TextureAddressMode texture_address_mode_u,
SDL_TextureAddressMode texture_address_mode_v);
#if 0
bool SDL_BlitTriangle(SDL_Surface *src, const SDL_Point srcpoints[3], SDL_Surface *dst, const SDL_Point dstpoints[3])
{
int i;
SDL_Point points[6];
if (src == NULL || dst == NULL) {
return false;
}
for (i = 0; i < 3; i++) {
if (srcpoints[i].x < 0 || srcpoints[i].y < 0 || srcpoints[i].x >= src->w || srcpoints[i].y >= src->h) {
return SDL_SetError("Values of 'srcpoints' out of bounds");
}
}
points[0] = srcpoints[0];
points[1] = dstpoints[0];
points[2] = srcpoints[1];
points[3] = dstpoints[1];
points[4] = srcpoints[2];
points[5] = dstpoints[2];
for (i = 0; i < 3; i++) {
trianglepoint_2_fixedpoint(&points[2 * i + 1]);
}
return SDL_SW_BlitTriangle(src, dst, points);
}
bool SDL_FillTriangle(SDL_Surface *dst, const SDL_Point points[3], Uint32 color)
{
int i;
SDL_Point points_tmp[3];
if (dst == NULL) {
return false;
}
for (i = 0; i < 3; i++) {
points_tmp[i] = points[i];
trianglepoint_2_fixedpoint(&points_tmp[i]);
}
return SDL_SW_FillTriangle(dst, points_tmp, SDL_BLENDMODE_NONE, color);
}
#endif
// cross product AB x AC
static Sint64 cross_product(const SDL_Point *a, const SDL_Point *b, int c_x, int c_y)
{
return ((Sint64)(b->x - a->x)) * ((Sint64)(c_y - a->y)) - ((Sint64)(b->y - a->y)) * ((Sint64)(c_x - a->x));
}
// check for top left rules
static bool is_top_left(const SDL_Point *a, const SDL_Point *b, int is_clockwise)
{
if (is_clockwise) {
if (a->y == b->y && a->x < b->x) {
return true;
}
if (b->y < a->y) {
return true;
}
} else {
if (a->y == b->y && b->x < a->x) {
return true;
}
if (a->y < b->y) {
return true;
}
}
return false;
}
// x = (y << FP_BITS)
// prevent runtime error: left shift of negative value
#define PRECOMP(x, y) \
val = y; \
if (val >= 0) { \
x = val << FP_BITS; \
} else { \
val *= -1; \
x = val << FP_BITS; \
x *= -1; \
}
void trianglepoint_2_fixedpoint(SDL_Point *a)
{
int val;
PRECOMP(a->x, a->x);
PRECOMP(a->y, a->y);
}
// bounding rect of three points (in fixed point)
static void bounding_rect_fixedpoint(const SDL_Point *a, const SDL_Point *b, const SDL_Point *c, SDL_Rect *r)
{
int min_x = SDL_min(a->x, SDL_min(b->x, c->x));
int max_x = SDL_max(a->x, SDL_max(b->x, c->x));
int min_y = SDL_min(a->y, SDL_min(b->y, c->y));
int max_y = SDL_max(a->y, SDL_max(b->y, c->y));
// points are in fixed point, shift back
r->x = min_x >> FP_BITS;
r->y = min_y >> FP_BITS;
r->w = (max_x - min_x) >> FP_BITS;
r->h = (max_y - min_y) >> FP_BITS;
}
// bounding rect of three points
static void bounding_rect(const SDL_Point *a, const SDL_Point *b, const SDL_Point *c, SDL_Rect *r)
{
int min_x = SDL_min(a->x, SDL_min(b->x, c->x));
int max_x = SDL_max(a->x, SDL_max(b->x, c->x));
int min_y = SDL_min(a->y, SDL_min(b->y, c->y));
int max_y = SDL_max(a->y, SDL_max(b->y, c->y));
r->x = min_x;
r->y = min_y;
r->w = (max_x - min_x);
r->h = (max_y - min_y);
}
/* Triangle rendering, using Barycentric coordinates (w0, w1, w2)
*
* The cross product isn't computed from scratch at each iteration,
* but optimized using constant step increments
*
*/
#define TRIANGLE_BEGIN_LOOP \
{ \
int x, y; \
for (y = 0; y < dstrect.h; y++) { \
/* y start */ \
Sint64 w0 = w0_row; \
Sint64 w1 = w1_row; \
Sint64 w2 = w2_row; \
for (x = 0; x < dstrect.w; x++) { \
/* In triangle */ \
if (w0 + bias_w0 >= 0 && w1 + bias_w1 >= 0 && w2 + bias_w2 >= 0) { \
Uint8 *dptr = (Uint8 *)dst_ptr + x * dstbpp;
// Use 64 bits precision to prevent overflow when interpolating color / texture with wide triangles
#define TRIANGLE_GET_TEXTCOORD \
int srcx = (int)(((Sint64)w0 * s2s0_x + (Sint64)w1 * s2s1_x + s2_x_area.x) / area); \
int srcy = (int)(((Sint64)w0 * s2s0_y + (Sint64)w1 * s2s1_y + s2_x_area.y) / area); \
if (texture_address_mode_u == SDL_TEXTURE_ADDRESS_WRAP) { \
srcx %= src_surface->w; \
if (srcx < 0) { \
srcx += (src_surface->w - 1); \
} \
} \
if (texture_address_mode_v == SDL_TEXTURE_ADDRESS_WRAP) { \
srcy %= src_surface->h; \
if (srcy < 0) { \
srcy += (src_surface->h - 1); \
} \
}
#define TRIANGLE_GET_MAPPED_COLOR \
Uint8 r = (Uint8)(((Sint64)w0 * c0.r + (Sint64)w1 * c1.r + (Sint64)w2 * c2.r) / area); \
Uint8 g = (Uint8)(((Sint64)w0 * c0.g + (Sint64)w1 * c1.g + (Sint64)w2 * c2.g) / area); \
Uint8 b = (Uint8)(((Sint64)w0 * c0.b + (Sint64)w1 * c1.b + (Sint64)w2 * c2.b) / area); \
Uint8 a = (Uint8)(((Sint64)w0 * c0.a + (Sint64)w1 * c1.a + (Sint64)w2 * c2.a) / area); \
Uint32 color = SDL_MapRGBA(format, palette, r, g, b, a);
#define TRIANGLE_GET_COLOR \
int r = (int)(((Sint64)w0 * c0.r + (Sint64)w1 * c1.r + (Sint64)w2 * c2.r) / area); \
int g = (int)(((Sint64)w0 * c0.g + (Sint64)w1 * c1.g + (Sint64)w2 * c2.g) / area); \
int b = (int)(((Sint64)w0 * c0.b + (Sint64)w1 * c1.b + (Sint64)w2 * c2.b) / area); \
int a = (int)(((Sint64)w0 * c0.a + (Sint64)w1 * c1.a + (Sint64)w2 * c2.a) / area);
#define TRIANGLE_END_LOOP \
} \
/* x += 1 */ \
w0 += d2d1_y; \
w1 += d0d2_y; \
w2 += d1d0_y; \
} \
/* y += 1 */ \
w0_row += d1d2_x; \
w1_row += d2d0_x; \
w2_row += d0d1_x; \
dst_ptr += dst_pitch; \
} \
}
bool SDL_SW_FillTriangle(SDL_Surface *dst, SDL_Point *d0, SDL_Point *d1, SDL_Point *d2, SDL_BlendMode blend, SDL_Color c0, SDL_Color c1, SDL_Color c2)
{
bool result = true;
int dst_locked = 0;
SDL_Rect dstrect;
int dstbpp;
Uint8 *dst_ptr;
int dst_pitch;
Sint64 area;
int is_clockwise;
int d2d1_y, d1d2_x, d0d2_y, d2d0_x, d1d0_y, d0d1_x;
Sint64 w0_row, w1_row, w2_row;
int bias_w0, bias_w1, bias_w2;
bool is_uniform;
SDL_Surface *tmp = NULL;
if (!SDL_SurfaceValid(dst)) {
return false;
}
area = cross_product(d0, d1, d2->x, d2->y);
is_uniform = COLOR_EQ(c0, c1) && COLOR_EQ(c1, c2);
// Flat triangle
if (area == 0) {
return true;
}
// Lock the destination, if needed
if (SDL_MUSTLOCK(dst)) {
if (!SDL_LockSurface(dst)) {
result = false;
goto end;
} else {
dst_locked = 1;
}
}
bounding_rect_fixedpoint(d0, d1, d2, &dstrect);
{
// Clip triangle rect with surface rect
SDL_Rect rect;
rect.x = 0;
rect.y = 0;
rect.w = dst->w;
rect.h = dst->h;
SDL_GetRectIntersection(&dstrect, &rect, &dstrect);
}
{
// Clip triangle with surface clip rect
SDL_Rect rect;
SDL_GetSurfaceClipRect(dst, &rect);
SDL_GetRectIntersection(&dstrect, &rect, &dstrect);
}
if (blend != SDL_BLENDMODE_NONE) {
SDL_PixelFormat format = dst->format;
// need an alpha format
if (!SDL_ISPIXELFORMAT_ALPHA(format)) {
format = SDL_PIXELFORMAT_ARGB8888;
}
// Use an intermediate surface
tmp = SDL_CreateSurface(dstrect.w, dstrect.h, format);
if (!tmp) {
result = false;
goto end;
}
if (blend == SDL_BLENDMODE_MOD) {
Uint32 c = SDL_MapSurfaceRGBA(tmp, 255, 255, 255, 255);
SDL_FillSurfaceRect(tmp, NULL, c);
}
SDL_SetSurfaceBlendMode(tmp, blend);
dstbpp = tmp->fmt->bytes_per_pixel;
dst_ptr = (Uint8 *)tmp->pixels;
dst_pitch = tmp->pitch;
} else {
// Write directly to destination surface
dstbpp = dst->fmt->bytes_per_pixel;
dst_ptr = (Uint8 *)dst->pixels + dstrect.x * dstbpp + dstrect.y * dst->pitch;
dst_pitch = dst->pitch;
}
is_clockwise = area > 0;
if (area < 0) {
area = -area;
}
{
int val;
PRECOMP(d2d1_y, d1->y - d2->y)
PRECOMP(d0d2_y, d2->y - d0->y)
PRECOMP(d1d0_y, d0->y - d1->y)
PRECOMP(d1d2_x, d2->x - d1->x)
PRECOMP(d2d0_x, d0->x - d2->x)
PRECOMP(d0d1_x, d1->x - d0->x)
}
// Starting point for rendering, at the middle of a pixel
{
SDL_Point p;
p.x = dstrect.x;
p.y = dstrect.y;
trianglepoint_2_fixedpoint(&p);
p.x += (1 << FP_BITS) / 2;
p.y += (1 << FP_BITS) / 2;
w0_row = cross_product(d1, d2, p.x, p.y);
w1_row = cross_product(d2, d0, p.x, p.y);
w2_row = cross_product(d0, d1, p.x, p.y);
}
// Handle anti-clockwise triangles
if (!is_clockwise) {
d2d1_y *= -1;
d0d2_y *= -1;
d1d0_y *= -1;
d1d2_x *= -1;
d2d0_x *= -1;
d0d1_x *= -1;
w0_row *= -1;
w1_row *= -1;
w2_row *= -1;
}
// Add a bias to respect top-left rasterization rule
bias_w0 = (is_top_left(d1, d2, is_clockwise) ? 0 : -1);
bias_w1 = (is_top_left(d2, d0, is_clockwise) ? 0 : -1);
bias_w2 = (is_top_left(d0, d1, is_clockwise) ? 0 : -1);
if (is_uniform) {
Uint32 color;
if (tmp) {
color = SDL_MapSurfaceRGBA(tmp, c0.r, c0.g, c0.b, c0.a);
} else {
color = SDL_MapSurfaceRGBA(dst, c0.r, c0.g, c0.b, c0.a);
}
if (dstbpp == 4) {
TRIANGLE_BEGIN_LOOP
{
*(Uint32 *)dptr = color;
}
TRIANGLE_END_LOOP
} else if (dstbpp == 3) {
TRIANGLE_BEGIN_LOOP
{
Uint8 *s = (Uint8 *)&color;
dptr[0] = s[0];
dptr[1] = s[1];
dptr[2] = s[2];
}
TRIANGLE_END_LOOP
} else if (dstbpp == 2) {
TRIANGLE_BEGIN_LOOP
{
*(Uint16 *)dptr = (Uint16)color;
}
TRIANGLE_END_LOOP
} else if (dstbpp == 1) {
TRIANGLE_BEGIN_LOOP
{
*dptr = (Uint8)color;
}
TRIANGLE_END_LOOP
}
} else {
const SDL_PixelFormatDetails *format;
SDL_Palette *palette;
if (tmp) {
format = tmp->fmt;
palette = tmp->palette;
} else {
format = dst->fmt;
palette = dst->palette;
}
if (dstbpp == 4) {
TRIANGLE_BEGIN_LOOP
{
TRIANGLE_GET_MAPPED_COLOR
*(Uint32 *)dptr = color;
}
TRIANGLE_END_LOOP
} else if (dstbpp == 3) {
TRIANGLE_BEGIN_LOOP
{
TRIANGLE_GET_MAPPED_COLOR
Uint8 *s = (Uint8 *)&color;
dptr[0] = s[0];
dptr[1] = s[1];
dptr[2] = s[2];
}
TRIANGLE_END_LOOP
} else if (dstbpp == 2) {
TRIANGLE_BEGIN_LOOP
{
TRIANGLE_GET_MAPPED_COLOR
*(Uint16 *)dptr = (Uint16)color;
}
TRIANGLE_END_LOOP
} else if (dstbpp == 1) {
TRIANGLE_BEGIN_LOOP
{
TRIANGLE_GET_MAPPED_COLOR
*dptr = (Uint8)color;
}
TRIANGLE_END_LOOP
}
}
if (tmp) {
SDL_BlitSurface(tmp, NULL, dst, &dstrect);
SDL_DestroySurface(tmp);
}
end:
if (dst_locked) {
SDL_UnlockSurface(dst);
}
return result;
}
bool SDL_SW_BlitTriangle(
SDL_Surface *src,
SDL_Point *s0, SDL_Point *s1, SDL_Point *s2,
SDL_Surface *dst,
SDL_Point *d0, SDL_Point *d1, SDL_Point *d2,
SDL_Color c0, SDL_Color c1, SDL_Color c2,
SDL_TextureAddressMode texture_address_mode_u,
SDL_TextureAddressMode texture_address_mode_v)
{
bool result = true;
SDL_Surface *src_surface = src;
int src_locked = 0;
int dst_locked = 0;
SDL_BlendMode blend;
SDL_Rect dstrect;
SDL_Point s2_x_area;
int dstbpp;
Uint8 *dst_ptr;
int dst_pitch;
const int *src_ptr;
int src_pitch;
Sint64 area, tmp64;
int is_clockwise;
int d2d1_y, d1d2_x, d0d2_y, d2d0_x, d1d0_y, d0d1_x;
int s2s0_x, s2s1_x, s2s0_y, s2s1_y;
Sint64 w0_row, w1_row, w2_row;
int bias_w0, bias_w1, bias_w2;
bool is_uniform;
bool has_modulation;
if (!SDL_SurfaceValid(src)) {
return SDL_InvalidParamError("src");
}
if (!SDL_SurfaceValid(dst)) {
return SDL_InvalidParamError("dst");
}
area = cross_product(d0, d1, d2->x, d2->y);
// Flat triangle
if (area == 0) {
return true;
}
// Lock the destination, if needed
if (SDL_MUSTLOCK(dst)) {
if (!SDL_LockSurface(dst)) {
result = false;
goto end;
} else {
dst_locked = 1;
}
}
// Lock the source, if needed
if (SDL_MUSTLOCK(src)) {
if (!SDL_LockSurface(src)) {
result = false;
goto end;
} else {
src_locked = 1;
}
}
is_uniform = COLOR_EQ(c0, c1) && COLOR_EQ(c1, c2);
bounding_rect_fixedpoint(d0, d1, d2, &dstrect);
SDL_GetSurfaceBlendMode(src, &blend);
// TRIANGLE_GET_TEXTCOORD interpolates up to the max values included, so reduce by 1
if (texture_address_mode_u == SDL_TEXTURE_ADDRESS_CLAMP ||
texture_address_mode_v == SDL_TEXTURE_ADDRESS_CLAMP) {
SDL_Rect srcrect;
bounding_rect(s0, s1, s2, &srcrect);
if (texture_address_mode_u == SDL_TEXTURE_ADDRESS_CLAMP) {
int maxx = srcrect.x + srcrect.w;
if (srcrect.w > 0) {
if (s0->x == maxx) {
s0->x--;
}
if (s1->x == maxx) {
s1->x--;
}
if (s2->x == maxx) {
s2->x--;
}
}
}
if (texture_address_mode_v == SDL_TEXTURE_ADDRESS_CLAMP) {
int maxy = srcrect.y + srcrect.h;
if (srcrect.h > 0) {
if (s0->y == maxy) {
s0->y--;
}
if (s1->y == maxy) {
s1->y--;
}
if (s2->y == maxy) {
s2->y--;
}
}
}
}
if (is_uniform) {
// SDL_GetSurfaceColorMod(src, &r, &g, &b);
has_modulation = c0.r != 255 || c0.g != 255 || c0.b != 255 || c0.a != 255;
} else {
has_modulation = true;
}
{
// Clip triangle with surface clip rect
SDL_Rect rect;
SDL_GetSurfaceClipRect(dst, &rect);
SDL_GetRectIntersection(&dstrect, &rect, &dstrect);
}
// Set destination pointer
dstbpp = dst->fmt->bytes_per_pixel;
dst_ptr = (Uint8 *)dst->pixels + dstrect.x * dstbpp + dstrect.y * dst->pitch;
dst_pitch = dst->pitch;
// Set source pointer
src_ptr = (const int *)src->pixels;
src_pitch = src->pitch;
is_clockwise = area > 0;
if (area < 0) {
area = -area;
}
{
int val;
PRECOMP(d2d1_y, d1->y - d2->y)
PRECOMP(d0d2_y, d2->y - d0->y)
PRECOMP(d1d0_y, d0->y - d1->y)
PRECOMP(d1d2_x, d2->x - d1->x)
PRECOMP(d2d0_x, d0->x - d2->x)
PRECOMP(d0d1_x, d1->x - d0->x)
}
s2s0_x = s0->x - s2->x;
s2s1_x = s1->x - s2->x;
s2s0_y = s0->y - s2->y;
s2s1_y = s1->y - s2->y;
// Starting point for rendering, at the middle of a pixel
{
SDL_Point p;
p.x = dstrect.x;
p.y = dstrect.y;
trianglepoint_2_fixedpoint(&p);
p.x += (1 << FP_BITS) / 2;
p.y += (1 << FP_BITS) / 2;
w0_row = cross_product(d1, d2, p.x, p.y);
w1_row = cross_product(d2, d0, p.x, p.y);
w2_row = cross_product(d0, d1, p.x, p.y);
}
// Handle anti-clockwise triangles
if (!is_clockwise) {
d2d1_y *= -1;
d0d2_y *= -1;
d1d0_y *= -1;
d1d2_x *= -1;
d2d0_x *= -1;
d0d1_x *= -1;
w0_row *= -1;
w1_row *= -1;
w2_row *= -1;
}
// Add a bias to respect top-left rasterization rule
bias_w0 = (is_top_left(d1, d2, is_clockwise) ? 0 : -1);
bias_w1 = (is_top_left(d2, d0, is_clockwise) ? 0 : -1);
bias_w2 = (is_top_left(d0, d1, is_clockwise) ? 0 : -1);
/* precompute constant 's2->x * area' used in TRIANGLE_GET_TEXTCOORD */
tmp64 = s2->x * area;
if (tmp64 >= INT_MIN && tmp64 <= INT_MAX) {
s2_x_area.x = (int)tmp64;
} else {
result = SDL_SetError("triangle area overflow");
goto end;
}
tmp64 = s2->y * area;
if (tmp64 >= INT_MIN && tmp64 <= INT_MAX) {
s2_x_area.y = (int)tmp64;
} else {
result = SDL_SetError("triangle area overflow");
goto end;
}
if (blend != SDL_BLENDMODE_NONE || src->format != dst->format || has_modulation || !is_uniform) {
// Use SDL_BlitTriangle_Slow
SDL_BlitInfo *info = &src->map.info;
SDL_BlitInfo tmp_info;
SDL_zero(tmp_info);
tmp_info.src_fmt = src->fmt;
tmp_info.dst_fmt = dst->fmt;
tmp_info.flags = info->flags;
/*
tmp_info.r = info->r;
tmp_info.g = info->g;
tmp_info.b = info->b;
tmp_info.a = info->a;
*/
tmp_info.r = c0.r;
tmp_info.g = c0.g;
tmp_info.b = c0.b;
tmp_info.a = c0.a;
tmp_info.flags &= ~(SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA);
if (c0.r != 255 || c1.r != 255 || c2.r != 255 ||
c0.g != 255 || c1.g != 255 || c2.g != 255 ||
c0.b != 255 || c1.b != 255 || c2.b != 255) {
tmp_info.flags |= SDL_COPY_MODULATE_COLOR;
}
if (c0.a != 255 || c1.a != 255 || c2.a != 255) {
tmp_info.flags |= SDL_COPY_MODULATE_ALPHA;
}
tmp_info.colorkey = info->colorkey;
// src
tmp_info.src_surface = src_surface;
tmp_info.src = (Uint8 *)src_ptr;
tmp_info.src_pitch = src_pitch;
// dst
tmp_info.dst = dst_ptr;
tmp_info.dst_pitch = dst_pitch;
#define CHECK_INT_RANGE(X) \
if ((X) < INT_MIN || (X) > INT_MAX) { \
result = SDL_SetError("integer overflow (%s = %" SDL_PRIs64 ")", #X, X); \
goto end; \
}
CHECK_INT_RANGE(area);
CHECK_INT_RANGE(w0_row);
CHECK_INT_RANGE(w1_row);
CHECK_INT_RANGE(w2_row);
SDL_BlitTriangle_Slow(&tmp_info, s2_x_area, dstrect, (int)area, bias_w0, bias_w1, bias_w2,
d2d1_y, d1d2_x, d0d2_y, d2d0_x, d1d0_y, d0d1_x,
s2s0_x, s2s1_x, s2s0_y, s2s1_y, (int)w0_row, (int)w1_row, (int)w2_row,
c0, c1, c2, is_uniform, texture_address_mode_u, texture_address_mode_v);
goto end;
}
if (dstbpp == 4) {
TRIANGLE_BEGIN_LOOP
{
TRIANGLE_GET_TEXTCOORD
Uint32 *sptr = (Uint32 *)((Uint8 *)src_ptr + srcy * src_pitch);
*(Uint32 *)dptr = sptr[srcx];
}
TRIANGLE_END_LOOP
} else if (dstbpp == 3) {
TRIANGLE_BEGIN_LOOP
{
TRIANGLE_GET_TEXTCOORD
Uint8 *sptr = (Uint8 *)src_ptr + srcy * src_pitch;
dptr[0] = sptr[3 * srcx];
dptr[1] = sptr[3 * srcx + 1];
dptr[2] = sptr[3 * srcx + 2];
}
TRIANGLE_END_LOOP
} else if (dstbpp == 2) {
TRIANGLE_BEGIN_LOOP
{
TRIANGLE_GET_TEXTCOORD
Uint16 *sptr = (Uint16 *)((Uint8 *)src_ptr + srcy * src_pitch);
*(Uint16 *)dptr = sptr[srcx];
}
TRIANGLE_END_LOOP
} else if (dstbpp == 1) {
TRIANGLE_BEGIN_LOOP
{
TRIANGLE_GET_TEXTCOORD
Uint8 *sptr = (Uint8 *)src_ptr + srcy * src_pitch;
*dptr = sptr[srcx];
}
TRIANGLE_END_LOOP
}
end:
if (dst_locked) {
SDL_UnlockSurface(dst);
}
if (src_locked) {
SDL_UnlockSurface(src);
}
return result;
}
#define FORMAT_ALPHA 0
#define FORMAT_NO_ALPHA -1
#define FORMAT_2101010 1
#define FORMAT_HAS_ALPHA(format) format == 0
#define FORMAT_HAS_NO_ALPHA(format) format < 0
static int detect_format(const SDL_PixelFormatDetails *pf)
{
if (pf->format == SDL_PIXELFORMAT_ARGB2101010) {
return FORMAT_2101010;
} else if (pf->Amask) {
return FORMAT_ALPHA;
} else {
return FORMAT_NO_ALPHA;
}
}
static void SDL_BlitTriangle_Slow(SDL_BlitInfo *info,
SDL_Point s2_x_area, SDL_Rect dstrect, int area, int bias_w0, int bias_w1, int bias_w2,
int d2d1_y, int d1d2_x, int d0d2_y, int d2d0_x, int d1d0_y, int d0d1_x,
int s2s0_x, int s2s1_x, int s2s0_y, int s2s1_y, int w0_row, int w1_row, int w2_row,
SDL_Color c0, SDL_Color c1, SDL_Color c2, bool is_uniform,
SDL_TextureAddressMode texture_address_mode_u,
SDL_TextureAddressMode texture_address_mode_v)
{
SDL_Surface *src_surface = info->src_surface;
const int flags = info->flags;
Uint32 modulateR = info->r;
Uint32 modulateG = info->g;
Uint32 modulateB = info->b;
Uint32 modulateA = info->a;
Uint32 srcpixel;
Uint32 srcR, srcG, srcB, srcA;
Uint32 dstpixel;
Uint32 dstR, dstG, dstB, dstA;
const SDL_PixelFormatDetails *src_fmt = info->src_fmt;
const SDL_PixelFormatDetails *dst_fmt = info->dst_fmt;
int srcbpp = src_fmt->bytes_per_pixel;
int dstbpp = dst_fmt->bytes_per_pixel;
int srcfmt_val;
int dstfmt_val;
Uint32 rgbmask = ~src_fmt->Amask;
Uint32 ckey = info->colorkey & rgbmask;
Uint8 *dst_ptr = info->dst;
int dst_pitch = info->dst_pitch;
srcfmt_val = detect_format(src_fmt);
dstfmt_val = detect_format(dst_fmt);
TRIANGLE_BEGIN_LOOP
{
Uint8 *src;
Uint8 *dst = dptr;
TRIANGLE_GET_TEXTCOORD
src = (info->src + (srcy * info->src_pitch) + (srcx * srcbpp));
if (FORMAT_HAS_ALPHA(srcfmt_val)) {
DISEMBLE_RGBA(src, srcbpp, src_fmt, srcpixel, srcR, srcG, srcB, srcA);
} else if (FORMAT_HAS_NO_ALPHA(srcfmt_val)) {
DISEMBLE_RGB(src, srcbpp, src_fmt, srcpixel, srcR, srcG, srcB);
srcA = 0xFF;
} else {
// SDL_PIXELFORMAT_ARGB2101010
srcpixel = *((Uint32 *)(src));
RGBA_FROM_ARGB2101010(srcpixel, srcR, srcG, srcB, srcA);
}
if (flags & SDL_COPY_COLORKEY) {
// srcpixel isn't set for 24 bpp
if (srcbpp == 3) {
srcpixel = (srcR << src_fmt->Rshift) |
(srcG << src_fmt->Gshift) | (srcB << src_fmt->Bshift);
}
if ((srcpixel & rgbmask) == ckey) {
continue;
}
}
if ((flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL))) {
if (FORMAT_HAS_ALPHA(dstfmt_val)) {
DISEMBLE_RGBA(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB, dstA);
} else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) {
DISEMBLE_RGB(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB);
dstA = 0xFF;
} else {
// SDL_PIXELFORMAT_ARGB2101010
dstpixel = *((Uint32 *) (dst));
RGBA_FROM_ARGB2101010(dstpixel, dstR, dstG, dstB, dstA);
}
} else {
// don't care
dstR = dstG = dstB = dstA = 0;
}
if (!is_uniform) {
TRIANGLE_GET_COLOR
modulateR = r;
modulateG = g;
modulateB = b;
modulateA = a;
}
if (flags & SDL_COPY_MODULATE_COLOR) {
srcR = (srcR * modulateR) / 255;
srcG = (srcG * modulateG) / 255;
srcB = (srcB * modulateB) / 255;
}
if (flags & SDL_COPY_MODULATE_ALPHA) {
srcA = (srcA * modulateA) / 255;
}
if (flags & (SDL_COPY_BLEND | SDL_COPY_ADD)) {
// This goes away if we ever use premultiplied alpha
if (srcA < 255) {
srcR = (srcR * srcA) / 255;
srcG = (srcG * srcA) / 255;
srcB = (srcB * srcA) / 255;
}
}
switch (flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL)) {
case 0:
dstR = srcR;
dstG = srcG;
dstB = srcB;
dstA = srcA;
break;
case SDL_COPY_BLEND:
dstR = srcR + ((255 - srcA) * dstR) / 255;
dstG = srcG + ((255 - srcA) * dstG) / 255;
dstB = srcB + ((255 - srcA) * dstB) / 255;
dstA = srcA + ((255 - srcA) * dstA) / 255;
break;
case SDL_COPY_ADD:
dstR = srcR + dstR;
if (dstR > 255) {
dstR = 255;
}
dstG = srcG + dstG;
if (dstG > 255) {
dstG = 255;
}
dstB = srcB + dstB;
if (dstB > 255) {
dstB = 255;
}
break;
case SDL_COPY_MOD:
dstR = (srcR * dstR) / 255;
dstG = (srcG * dstG) / 255;
dstB = (srcB * dstB) / 255;
break;
case SDL_COPY_MUL:
dstR = ((srcR * dstR) + (dstR * (255 - srcA))) / 255;
if (dstR > 255) {
dstR = 255;
}
dstG = ((srcG * dstG) + (dstG * (255 - srcA))) / 255;
if (dstG > 255) {
dstG = 255;
}
dstB = ((srcB * dstB) + (dstB * (255 - srcA))) / 255;
if (dstB > 255) {
dstB = 255;
}
break;
}
if (FORMAT_HAS_ALPHA(dstfmt_val)) {
ASSEMBLE_RGBA(dst, dstbpp, dst_fmt, dstR, dstG, dstB, dstA);
} else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) {
ASSEMBLE_RGB(dst, dstbpp, dst_fmt, dstR, dstG, dstB);
} else {
// SDL_PIXELFORMAT_ARGB2101010
Uint32 pixelvalue;
ARGB2101010_FROM_RGBA(pixelvalue, dstR, dstG, dstB, dstA);
*(Uint32 *)dst = pixelvalue;
}
}
TRIANGLE_END_LOOP
}
#endif // SDL_VIDEO_RENDER_SW
@@ -0,0 +1,41 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
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 bool SDL_SW_FillTriangle(SDL_Surface *dst,
SDL_Point *d0, SDL_Point *d1, SDL_Point *d2,
SDL_BlendMode blend, SDL_Color c0, SDL_Color c1, SDL_Color c2);
extern bool SDL_SW_BlitTriangle(SDL_Surface *src,
SDL_Point *s0, SDL_Point *s1, SDL_Point *s2,
SDL_Surface *dst,
SDL_Point *d0, SDL_Point *d1, SDL_Point *d2,
SDL_Color c0, SDL_Color c1, SDL_Color c2,
SDL_TextureAddressMode texture_address_mode_u,
SDL_TextureAddressMode texture_address_mode_v);
extern void trianglepoint_2_fixedpoint(SDL_Point *a);
#endif // SDL_triangle_h_