update SDL3 from 3.2.20 to 3.4.2

This commit is contained in:
Sven Balzer
2026-04-01 18:25:03 +02:00
parent 1daf4d79f1
commit 05b19704f8
1626 changed files with 124218 additions and 191491 deletions
+37 -218
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -89,6 +89,7 @@
#include "SDL_sysvideo.h"
#include "SDL_surface_c.h"
#include "SDL_pixels_c.h"
#include "SDL_RLEaccel_c.h"
#define PIXEL_COPY(to, from, len, bpp) \
@@ -169,13 +170,24 @@
/*
* The general slow catch-all function, for remaining depths and formats
*/
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
#define SET_RGB24(dst, d) \
dst[0] = (Uint8)(d >> 16); \
dst[1] = (Uint8)(d >> 8); \
dst[2] = (Uint8)(d);
#else
#define SET_RGB24(dst, d) \
dst[0] = (Uint8)(d); \
dst[1] = (Uint8)(d >> 8); \
dst[2] = (Uint8)(d >> 16);
#endif
#define ALPHA_BLIT_ANY(to, from, length, bpp, alpha) \
do { \
int i; \
Uint8 *src = from; \
Uint8 *dst = to; \
for (i = 0; i < (int)(length); i++) { \
Uint32 s = 0, d = 0; \
Uint32 s = 0, d = 0; \
unsigned rs, gs, bs, rd, gd, bd; \
switch (bpp) { \
case 2: \
@@ -183,13 +195,8 @@
d = *(Uint16 *)dst; \
break; \
case 3: \
if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { \
s = (src[0] << 16) | (src[1] << 8) | src[2]; \
d = (dst[0] << 16) | (dst[1] << 8) | dst[2]; \
} else { \
s = (src[2] << 16) | (src[1] << 8) | src[0]; \
d = (dst[2] << 16) | (dst[1] << 8) | dst[0]; \
} \
s = GET_RGB24(src); \
d = GET_RGB24(dst); \
break; \
case 4: \
s = *(Uint32 *)src; \
@@ -207,15 +214,7 @@
*(Uint16 *)dst = (Uint16)d; \
break; \
case 3: \
if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { \
dst[0] = (Uint8)(d >> 16); \
dst[1] = (Uint8)(d >> 8); \
dst[2] = (Uint8)(d); \
} else { \
dst[0] = (Uint8)d; \
dst[1] = (Uint8)(d >> 8); \
dst[2] = (Uint8)(d >> 16); \
} \
SET_RGB24(dst, d); \
break; \
case 4: \
*(Uint32 *)dst = d; \
@@ -648,7 +647,8 @@ static void RLEAlphaClipBlit(int w, Uint8 *srcbuf, SDL_Surface *surf_dst,
return; \
} while (ofs < w); \
/* skip padding if necessary */ \
if (sizeof(Ptype) == 2) \
const size_t psize = sizeof(Ptype); \
if (psize == 2) \
srcbuf += (uintptr_t)srcbuf & 2; \
/* blit translucent pixels on the same line */ \
ofs = 0; \
@@ -805,7 +805,8 @@ static bool SDLCALL SDL_RLEAlphaBlit(SDL_Surface *surf_src, const SDL_Rect *srcr
goto done; \
} while (ofs < w); \
/* skip padding if necessary */ \
if (sizeof(Ptype) == 2) \
const size_t psize = sizeof(Ptype); \
if (psize == 2) \
srcbuf += (uintptr_t)srcbuf & 2; \
/* blit translucent pixels on the same line */ \
ofs = 0; \
@@ -878,23 +879,6 @@ static int copy_opaque_16(void *dst, const Uint32 *src, int n,
return n * 2;
}
// decode opaque pixels from 16bpp to 32bpp rgb + a
static int uncopy_opaque_16(Uint32 *dst, const void *src, int n,
const SDL_PixelFormatDetails *sfmt, const SDL_PixelFormatDetails *dfmt)
{
int i;
const Uint16 *s = (const Uint16 *)src;
unsigned alpha = dfmt->Amask ? 255 : 0;
for (i = 0; i < n; i++) {
unsigned r, g, b;
RGB_FROM_PIXEL(*s, sfmt, r, g, b);
PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, alpha);
s++;
dst++;
}
return n * 2;
}
// encode 32bpp rgb + a into 32bpp G0RAB format for blitting into 565
static int copy_transl_565(void *dst, const Uint32 *src, int n,
const SDL_PixelFormatDetails *sfmt, const SDL_PixelFormatDetails *dfmt)
@@ -931,24 +915,6 @@ static int copy_transl_555(void *dst, const Uint32 *src, int n,
return n * 4;
}
// decode translucent pixels from 32bpp GORAB to 32bpp rgb + a
static int uncopy_transl_16(Uint32 *dst, const void *src, int n,
const SDL_PixelFormatDetails *sfmt, const SDL_PixelFormatDetails *dfmt)
{
int i;
const Uint32 *s = (const Uint32 *)src;
for (i = 0; i < n; i++) {
unsigned r, g, b, a;
Uint32 pix = *s++;
a = (pix & 0x3e0) >> 2;
pix = (pix & ~0x3e0) | pix >> 16;
RGB_FROM_PIXEL(pix, sfmt, r, g, b);
PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, a);
dst++;
}
return n * 4;
}
// encode 32bpp rgba into 32bpp rgba, keeping alpha (dual purpose)
static int copy_32(void *dst, const Uint32 *src, int n,
const SDL_PixelFormatDetails *sfmt, const SDL_PixelFormatDetails *dfmt)
@@ -965,23 +931,6 @@ static int copy_32(void *dst, const Uint32 *src, int n,
return n * 4;
}
// decode 32bpp rgba into 32bpp rgba, keeping alpha (dual purpose)
static int uncopy_32(Uint32 *dst, const void *src, int n,
const SDL_PixelFormatDetails *sfmt, const SDL_PixelFormatDetails *dfmt)
{
int i;
const Uint32 *s = (const Uint32 *)src;
for (i = 0; i < n; i++) {
unsigned r, g, b, a;
Uint32 pixel = *s++;
RGB_FROM_PIXEL(pixel, sfmt, r, g, b);
a = pixel >> 24;
PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, a);
dst++;
}
return n * 4;
}
#define ISOPAQUE(pixel, fmt) ((((pixel)&fmt->Amask) >> fmt->Ashift) == 255)
#define ISTRANSL(pixel, fmt) \
@@ -1177,17 +1126,6 @@ static bool RLEAlphaSurface(SDL_Surface *surface)
#undef ADD_OPAQUE_COUNTS
#undef ADD_TRANSL_COUNTS
// Now that we have it encoded, release the original pixels
if (!(surface->flags & SDL_SURFACE_PREALLOCATED)) {
if (surface->flags & SDL_SURFACE_SIMD_ALIGNED) {
SDL_aligned_free(surface->pixels);
surface->flags &= ~SDL_SURFACE_SIMD_ALIGNED;
} else {
SDL_free(surface->pixels);
}
surface->pixels = NULL;
}
// reallocate the buffer to release unused memory
{
Uint8 *p = (Uint8 *)SDL_realloc(rlebuf, dst - rlebuf);
@@ -1353,17 +1291,6 @@ static bool RLEColorkeySurface(SDL_Surface *surface)
#undef ADD_COUNTS
// Now that we have it encoded, release the original pixels
if (!(surface->flags & SDL_SURFACE_PREALLOCATED)) {
if (surface->flags & SDL_SURFACE_SIMD_ALIGNED) {
SDL_aligned_free(surface->pixels);
surface->flags &= ~SDL_SURFACE_SIMD_ALIGNED;
} else {
SDL_free(surface->pixels);
}
surface->pixels = NULL;
}
// reallocate the buffer to release unused memory
{
// If SDL_realloc returns NULL, the original block is left intact
@@ -1383,7 +1310,7 @@ bool SDL_RLESurface(SDL_Surface *surface)
// Clear any previous RLE conversion
if (surface->internal_flags & SDL_INTERNAL_SURFACE_RLEACCEL) {
SDL_UnRLESurface(surface, true);
SDL_UnRLESurface(surface);
}
// We don't support RLE encoding of bitmaps
@@ -1432,144 +1359,36 @@ bool SDL_RLESurface(SDL_Surface *surface)
surface->map.info.flags |= SDL_COPY_RLE_ALPHAKEY;
}
if (!(surface->flags & SDL_SURFACE_PREALLOCATED)) {
surface->saved_pixels = surface->pixels;
surface->pixels = NULL;
}
// The surface is now accelerated
surface->internal_flags |= SDL_INTERNAL_SURFACE_RLEACCEL;
SDL_UpdateSurfaceLockFlag(surface);
return true;
}
/*
* Un-RLE a surface with pixel alpha
* This may not give back exactly the image before RLE-encoding; all
* completely transparent pixels will be lost, and color and alpha depth
* may have been reduced (when encoding for 16bpp targets).
*/
static bool UnRLEAlpha(SDL_Surface *surface)
{
Uint8 *srcbuf;
Uint32 *dst;
const SDL_PixelFormatDetails *sf = surface->fmt;
const SDL_PixelFormatDetails *df = SDL_GetPixelFormatDetails(*(SDL_PixelFormat *)surface->map.data);
int (*uncopy_opaque)(Uint32 *, const void *, int,
const SDL_PixelFormatDetails *, const SDL_PixelFormatDetails *);
int (*uncopy_transl)(Uint32 *, const void *, int,
const SDL_PixelFormatDetails *, const SDL_PixelFormatDetails *);
int w = surface->w;
int bpp = df->bytes_per_pixel;
size_t size;
if (bpp == 2) {
uncopy_opaque = uncopy_opaque_16;
uncopy_transl = uncopy_transl_16;
} else {
uncopy_opaque = uncopy_transl = uncopy_32;
}
if (!SDL_size_mul_check_overflow(surface->h, surface->pitch, &size)) {
return false;
}
surface->pixels = SDL_aligned_alloc(SDL_GetSIMDAlignment(), size);
if (!surface->pixels) {
return false;
}
surface->flags |= SDL_SURFACE_SIMD_ALIGNED;
// fill background with transparent pixels
SDL_memset(surface->pixels, 0, (size_t)surface->h * surface->pitch);
dst = (Uint32 *)surface->pixels;
srcbuf = (Uint8 *)surface->map.data + sizeof(SDL_PixelFormat);
for (;;) {
// copy opaque pixels
int ofs = 0;
do {
unsigned run;
if (bpp == 2) {
ofs += srcbuf[0];
run = srcbuf[1];
srcbuf += 2;
} else {
ofs += ((Uint16 *)srcbuf)[0];
run = ((Uint16 *)srcbuf)[1];
srcbuf += 4;
}
if (run) {
srcbuf += uncopy_opaque(dst + ofs, srcbuf, run, df, sf);
ofs += run;
} else if (!ofs) {
goto end_function;
}
} while (ofs < w);
// skip padding if needed
if (bpp == 2) {
srcbuf += (uintptr_t)srcbuf & 2;
}
// copy translucent pixels
ofs = 0;
do {
unsigned run;
ofs += ((Uint16 *)srcbuf)[0];
run = ((Uint16 *)srcbuf)[1];
srcbuf += 4;
if (run) {
srcbuf += uncopy_transl(dst + ofs, srcbuf, run, df, sf);
ofs += run;
}
} while (ofs < w);
dst += surface->pitch >> 2;
}
end_function:
return true;
}
void SDL_UnRLESurface(SDL_Surface *surface, bool recode)
void SDL_UnRLESurface(SDL_Surface *surface)
{
if (surface->internal_flags & SDL_INTERNAL_SURFACE_RLEACCEL) {
surface->internal_flags &= ~SDL_INTERNAL_SURFACE_RLEACCEL;
if (recode && !(surface->flags & SDL_SURFACE_PREALLOCATED)) {
if (surface->map.info.flags & SDL_COPY_RLE_COLORKEY) {
SDL_Rect full;
size_t size;
surface->map.info.flags &= ~(SDL_COPY_RLE_COLORKEY | SDL_COPY_RLE_ALPHAKEY);
// re-create the original surface
if (!SDL_size_mul_check_overflow(surface->h, surface->pitch, &size)) {
// Memory corruption?
surface->internal_flags |= SDL_INTERNAL_SURFACE_RLEACCEL;
return;
}
surface->pixels = SDL_aligned_alloc(SDL_GetSIMDAlignment(), size);
if (!surface->pixels) {
// Oh crap...
surface->internal_flags |= SDL_INTERNAL_SURFACE_RLEACCEL;
return;
}
surface->flags |= SDL_SURFACE_SIMD_ALIGNED;
// fill it with the background color
SDL_FillSurfaceRect(surface, NULL, surface->map.info.colorkey);
// now render the encoded surface
full.x = full.y = 0;
full.w = surface->w;
full.h = surface->h;
SDL_RLEBlit(surface, &full, surface, &full);
} else {
if (!UnRLEAlpha(surface)) {
// Oh crap...
surface->internal_flags |= SDL_INTERNAL_SURFACE_RLEACCEL;
return;
}
}
if (!(surface->flags & SDL_SURFACE_PREALLOCATED)) {
surface->pixels = surface->saved_pixels;
surface->saved_pixels = NULL;
}
surface->map.info.flags &=
~(SDL_COPY_RLE_COLORKEY | SDL_COPY_RLE_ALPHAKEY);
SDL_free(surface->map.data);
surface->map.data = NULL;
SDL_InvalidateMap(&surface->map);
SDL_UpdateSurfaceLockFlag(surface);
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -27,6 +27,6 @@
// Useful functions and variables from SDL_RLEaccel.c
extern bool SDL_RLESurface(SDL_Surface *surface);
extern void SDL_UnRLESurface(SDL_Surface *surface, bool recode);
extern void SDL_UnRLESurface(SDL_Surface *surface);
#endif // SDL_RLEaccel_c_h_
+18 -13
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -64,17 +64,26 @@ static bool SDLCALL SDL_SoftBlit(SDL_Surface *src, const SDL_Rect *srcrect,
SDL_BlitInfo *info = &src->map.info;
// Set up the blit information
info->src = (Uint8 *)src->pixels +
(Uint16)srcrect->y * src->pitch +
(Uint16)srcrect->x * info->src_fmt->bytes_per_pixel;
if (info->src_fmt->bits_per_pixel >= 8) {
info->src = (Uint8 *)src->pixels +
srcrect->y * src->pitch +
srcrect->x * info->src_fmt->bytes_per_pixel;
} else {
info->src = (Uint8 *)src->pixels +
srcrect->y * src->pitch +
(srcrect->x * info->src_fmt->bits_per_pixel) / 8;
info->leading_skip =
((srcrect->x * info->src_fmt->bits_per_pixel) % 8) /
info->src_fmt->bits_per_pixel;
}
info->src_w = srcrect->w;
info->src_h = srcrect->h;
info->src_pitch = src->pitch;
info->src_skip =
info->src_pitch - info->src_w * info->src_fmt->bytes_per_pixel;
info->dst =
(Uint8 *)dst->pixels + (Uint16)dstrect->y * dst->pitch +
(Uint16)dstrect->x * info->dst_fmt->bytes_per_pixel;
info->dst = (Uint8 *)dst->pixels +
dstrect->y * dst->pitch +
dstrect->x * info->dst_fmt->bytes_per_pixel;
info->dst_w = dstrect->w;
info->dst_h = dstrect->h;
info->dst_pitch = dst->pitch;
@@ -189,12 +198,8 @@ bool SDL_CalculateBlit(SDL_Surface *surface, SDL_Surface *dst)
return SDL_SetError("Blit combination not supported");
}
#ifdef SDL_HAVE_RLE
// Clean everything out to start
if (surface->flags & SDL_INTERNAL_SURFACE_RLEACCEL) {
SDL_UnRLESurface(surface, true);
}
#endif
// We should have cleared out RLE at this point
SDL_assert(!(surface->internal_flags & SDL_INTERNAL_SURFACE_RLEACCEL));
map->blit = SDL_SoftBlit;
map->info.src_surface = surface;
+116 -133
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -60,6 +60,7 @@ typedef struct
int src_w, src_h;
int src_pitch;
int src_skip;
int leading_skip;
SDL_Surface *dst_surface;
Uint8 *dst;
int dst_w, dst_h;
@@ -149,6 +150,11 @@ extern SDL_BlitFunc SDL_CalculateBlitA(SDL_Surface *surface);
g = ((Pixel & 0xFF00) >> 8); \
b = (Pixel & 0xFF); \
}
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
#define GET_RGB24(B) (B[2] << 16) | (B[1] << 8) | B[0]
#else
#define GET_RGB24(B) (B[0] << 16) | (B[1] << 8) | B[2]
#endif
#define RETRIEVE_RGB_PIXEL(buf, bpp, Pixel) \
do { \
switch (bpp) { \
@@ -163,11 +169,7 @@ extern SDL_BlitFunc SDL_CalculateBlitA(SDL_Surface *surface);
case 3: \
{ \
Uint8 *B = (Uint8 *)(buf); \
if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
Pixel = B[0] + (B[1] << 8) + (B[2] << 16); \
} else { \
Pixel = (B[0] << 16) + (B[1] << 8) + B[2]; \
} \
Pixel = GET_RGB24(B); \
} break; \
\
case 4: \
@@ -180,44 +182,43 @@ extern SDL_BlitFunc SDL_CalculateBlitA(SDL_Surface *surface);
} \
} while (0)
#define DISEMBLE_RGB(buf, bpp, fmt, Pixel, r, g, b) \
do { \
switch (bpp) { \
case 1: \
Pixel = *((Uint8 *)(buf)); \
RGB_FROM_PIXEL(Pixel, fmt, r, g, b); \
break; \
\
case 2: \
Pixel = *((Uint16 *)(buf)); \
RGB_FROM_PIXEL(Pixel, fmt, r, g, b); \
break; \
\
case 3: \
{ \
Pixel = 0; \
if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
r = *((buf) + fmt->Rshift / 8); \
g = *((buf) + fmt->Gshift / 8); \
b = *((buf) + fmt->Bshift / 8); \
} else { \
r = *((buf) + 2 - fmt->Rshift / 8); \
g = *((buf) + 2 - fmt->Gshift / 8); \
b = *((buf) + 2 - fmt->Bshift / 8); \
} \
} break; \
\
case 4: \
Pixel = *((Uint32 *)(buf)); \
RGB_FROM_PIXEL(Pixel, fmt, r, g, b); \
break; \
\
default: \
/* stop gcc complaints */ \
Pixel = 0; \
r = g = b = 0; \
break; \
} \
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
#define GET_RGB24_COMPONENT(buf, fmt, shift) *((buf) + fmt->shift / 8)
#else
#define GET_RGB24_COMPONENT(buf, fmt, shift) *((buf) + 2 - fmt->shift / 8)
#endif
#define DISEMBLE_RGB(buf, bpp, fmt, Pixel, r, g, b) \
do { \
switch (bpp) { \
case 1: \
Pixel = *((Uint8 *)(buf)); \
RGB_FROM_PIXEL(Pixel, fmt, r, g, b); \
break; \
\
case 2: \
Pixel = *((Uint16 *)(buf)); \
RGB_FROM_PIXEL(Pixel, fmt, r, g, b); \
break; \
\
case 3: \
{ \
Pixel = 0; \
r = GET_RGB24_COMPONENT(buf, fmt, Rshift); \
g = GET_RGB24_COMPONENT(buf, fmt, Gshift); \
b = GET_RGB24_COMPONENT(buf, fmt, Bshift); \
} break; \
\
case 4: \
Pixel = *((Uint32 *)(buf)); \
RGB_FROM_PIXEL(Pixel, fmt, r, g, b); \
break; \
\
default: \
/* stop gcc complaints */ \
Pixel = 0; \
r = g = b = 0; \
break; \
} \
} while (0)
// Assemble R-G-B values into a specified pixel format and store them
@@ -298,46 +299,40 @@ extern SDL_BlitFunc SDL_CalculateBlitA(SDL_Surface *surface);
(((Uint32)SDL_roundf(g)) << 10) | \
(Uint32)SDL_roundf(r); \
}
#define ASSEMBLE_RGB(buf, bpp, fmt, r, g, b) \
{ \
switch (bpp) { \
case 1: \
{ \
Uint8 _pixel; \
\
PIXEL_FROM_RGB(_pixel, fmt, r, g, b); \
*((Uint8 *)(buf)) = _pixel; \
} break; \
\
case 2: \
{ \
Uint16 _pixel; \
\
PIXEL_FROM_RGB(_pixel, fmt, r, g, b); \
*((Uint16 *)(buf)) = _pixel; \
} break; \
\
case 3: \
{ \
if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
*((buf) + fmt->Rshift / 8) = r; \
*((buf) + fmt->Gshift / 8) = g; \
*((buf) + fmt->Bshift / 8) = b; \
} else { \
*((buf) + 2 - fmt->Rshift / 8) = r; \
*((buf) + 2 - fmt->Gshift / 8) = g; \
*((buf) + 2 - fmt->Bshift / 8) = b; \
} \
} break; \
\
case 4: \
{ \
Uint32 _pixel; \
\
PIXEL_FROM_RGB(_pixel, fmt, r, g, b); \
*((Uint32 *)(buf)) = _pixel; \
} break; \
} \
#define ASSEMBLE_RGB(buf, bpp, fmt, r, g, b) \
{ \
switch (bpp) { \
case 1: \
{ \
Uint8 _pixel; \
\
PIXEL_FROM_RGB(_pixel, fmt, r, g, b); \
*((Uint8 *)(buf)) = _pixel; \
} break; \
\
case 2: \
{ \
Uint16 _pixel; \
\
PIXEL_FROM_RGB(_pixel, fmt, r, g, b); \
*((Uint16 *)(buf)) = _pixel; \
} break; \
\
case 3: \
{ \
GET_RGB24_COMPONENT(buf, fmt, Rshift) = r; \
GET_RGB24_COMPONENT(buf, fmt, Gshift) = g; \
GET_RGB24_COMPONENT(buf, fmt, Bshift) = b; \
} break; \
\
case 4: \
{ \
Uint32 _pixel; \
\
PIXEL_FROM_RGB(_pixel, fmt, r, g, b); \
*((Uint32 *)(buf)) = _pixel; \
} break; \
} \
}
// FIXME: Should we rescale alpha into 0..255 here?
@@ -427,15 +422,9 @@ extern SDL_BlitFunc SDL_CalculateBlitA(SDL_Surface *surface);
case 3: \
{ \
Pixel = 0; \
if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
r = *((buf) + fmt->Rshift / 8); \
g = *((buf) + fmt->Gshift / 8); \
b = *((buf) + fmt->Bshift / 8); \
} else { \
r = *((buf) + 2 - fmt->Rshift / 8); \
g = *((buf) + 2 - fmt->Gshift / 8); \
b = *((buf) + 2 - fmt->Bshift / 8); \
} \
r = GET_RGB24_COMPONENT(buf, fmt, Rshift); \
g = GET_RGB24_COMPONENT(buf, fmt, Gshift); \
b = GET_RGB24_COMPONENT(buf, fmt, Bshift); \
a = 0xFF; \
} break; \
\
@@ -460,46 +449,40 @@ extern SDL_BlitFunc SDL_CalculateBlitA(SDL_Surface *surface);
((b >> (8 - fmt->Bbits)) << fmt->Bshift) | \
((a >> (8 - fmt->Abits)) << fmt->Ashift); \
}
#define ASSEMBLE_RGBA(buf, bpp, fmt, r, g, b, a) \
{ \
switch (bpp) { \
case 1: \
{ \
Uint8 _pixel; \
\
PIXEL_FROM_RGBA(_pixel, fmt, r, g, b, a); \
*((Uint8 *)(buf)) = _pixel; \
} break; \
\
case 2: \
{ \
Uint16 _pixel; \
\
PIXEL_FROM_RGBA(_pixel, fmt, r, g, b, a); \
*((Uint16 *)(buf)) = _pixel; \
} break; \
\
case 3: \
{ \
if (SDL_BYTEORDER == SDL_LIL_ENDIAN) { \
*((buf) + fmt->Rshift / 8) = r; \
*((buf) + fmt->Gshift / 8) = g; \
*((buf) + fmt->Bshift / 8) = b; \
} else { \
*((buf) + 2 - fmt->Rshift / 8) = r; \
*((buf) + 2 - fmt->Gshift / 8) = g; \
*((buf) + 2 - fmt->Bshift / 8) = b; \
} \
} break; \
\
case 4: \
{ \
Uint32 _pixel; \
\
PIXEL_FROM_RGBA(_pixel, fmt, r, g, b, a); \
*((Uint32 *)(buf)) = _pixel; \
} break; \
} \
#define ASSEMBLE_RGBA(buf, bpp, fmt, r, g, b, a) \
{ \
switch (bpp) { \
case 1: \
{ \
Uint8 _pixel; \
\
PIXEL_FROM_RGBA(_pixel, fmt, r, g, b, a); \
*((Uint8 *)(buf)) = _pixel; \
} break; \
\
case 2: \
{ \
Uint16 _pixel; \
\
PIXEL_FROM_RGBA(_pixel, fmt, r, g, b, a); \
*((Uint16 *)(buf)) = _pixel; \
} break; \
\
case 3: \
{ \
GET_RGB24_COMPONENT(buf, fmt, Rshift) = r; \
GET_RGB24_COMPONENT(buf, fmt, Gshift) = g; \
GET_RGB24_COMPONENT(buf, fmt, Bshift) = b; \
} break; \
\
case 4: \
{ \
Uint32 _pixel; \
\
PIXEL_FROM_RGBA(_pixel, fmt, r, g, b, a); \
*((Uint32 *)(buf)) = _pixel; \
} break; \
} \
}
// Convert any 32-bit 4-bpp pixel to ARGB format
+195 -37
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -45,6 +45,8 @@ SDL_FORCE_INLINE void BlitBto1(SDL_BlitInfo *info, const Uint32 srcbpp)
dstskip = info->dst_skip;
map = info->table;
width += info->leading_skip;
if (srcbpp == 4)
srcskip += width - (width + 1) / 2;
else if (srcbpp == 2)
@@ -56,7 +58,13 @@ SDL_FORCE_INLINE void BlitBto1(SDL_BlitInfo *info, const Uint32 srcbpp)
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte >>= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -73,7 +81,13 @@ SDL_FORCE_INLINE void BlitBto1(SDL_BlitInfo *info, const Uint32 srcbpp)
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte <<= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -92,7 +106,13 @@ SDL_FORCE_INLINE void BlitBto1(SDL_BlitInfo *info, const Uint32 srcbpp)
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte >>= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -109,7 +129,13 @@ SDL_FORCE_INLINE void BlitBto1(SDL_BlitInfo *info, const Uint32 srcbpp)
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte <<= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -147,6 +173,8 @@ SDL_FORCE_INLINE void BlitBto2(SDL_BlitInfo *info, const Uint32 srcbpp)
dstskip = info->dst_skip / 2;
map = (Uint16 *)info->table;
width += info->leading_skip;
if (srcbpp == 4)
srcskip += width - (width + 1) / 2;
else if (srcbpp == 2)
@@ -157,7 +185,13 @@ SDL_FORCE_INLINE void BlitBto2(SDL_BlitInfo *info, const Uint32 srcbpp)
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte >>= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -174,7 +208,13 @@ SDL_FORCE_INLINE void BlitBto2(SDL_BlitInfo *info, const Uint32 srcbpp)
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte <<= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -210,6 +250,8 @@ SDL_FORCE_INLINE void BlitBto3(SDL_BlitInfo *info, const Uint32 srcbpp)
dstskip = info->dst_skip;
map = info->table;
width += info->leading_skip;
if (srcbpp == 4)
srcskip += width - (width + 1) / 2;
else if (srcbpp == 2)
@@ -220,7 +262,13 @@ SDL_FORCE_INLINE void BlitBto3(SDL_BlitInfo *info, const Uint32 srcbpp)
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte >>= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -240,7 +288,13 @@ SDL_FORCE_INLINE void BlitBto3(SDL_BlitInfo *info, const Uint32 srcbpp)
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte <<= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -280,6 +334,8 @@ SDL_FORCE_INLINE void BlitBto4(SDL_BlitInfo *info, const Uint32 srcbpp)
dstskip = info->dst_skip / 4;
map = (Uint32 *)info->table;
width += info->leading_skip;
if (srcbpp == 4)
srcskip += width - (width + 1) / 2;
else if (srcbpp == 2)
@@ -290,7 +346,13 @@ SDL_FORCE_INLINE void BlitBto4(SDL_BlitInfo *info, const Uint32 srcbpp)
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte >>= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -307,7 +369,13 @@ SDL_FORCE_INLINE void BlitBto4(SDL_BlitInfo *info, const Uint32 srcbpp)
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte <<= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -339,7 +407,8 @@ SDL_FORCE_INLINE void BlitBto1Key(SDL_BlitInfo *info, const Uint32 srcbpp)
Uint8 *palmap = info->table;
int c;
// Set up some basic variables
width += info->leading_skip;
if (srcbpp == 4)
srcskip += width - (width + 1) / 2;
else if (srcbpp == 2)
@@ -351,7 +420,13 @@ SDL_FORCE_INLINE void BlitBto1Key(SDL_BlitInfo *info, const Uint32 srcbpp)
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte >>= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -368,7 +443,13 @@ SDL_FORCE_INLINE void BlitBto1Key(SDL_BlitInfo *info, const Uint32 srcbpp)
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte <<= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -387,7 +468,13 @@ SDL_FORCE_INLINE void BlitBto1Key(SDL_BlitInfo *info, const Uint32 srcbpp)
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte >>= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -404,7 +491,13 @@ SDL_FORCE_INLINE void BlitBto1Key(SDL_BlitInfo *info, const Uint32 srcbpp)
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte <<= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -437,7 +530,8 @@ SDL_FORCE_INLINE void BlitBto2Key(SDL_BlitInfo *info, const Uint32 srcbpp)
Uint8 *palmap = info->table;
int c;
// Set up some basic variables
width += info->leading_skip;
if (srcbpp == 4)
srcskip += width - (width + 1) / 2;
else if (srcbpp == 2)
@@ -449,7 +543,13 @@ SDL_FORCE_INLINE void BlitBto2Key(SDL_BlitInfo *info, const Uint32 srcbpp)
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte >>= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -466,7 +566,13 @@ SDL_FORCE_INLINE void BlitBto2Key(SDL_BlitInfo *info, const Uint32 srcbpp)
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte <<= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -498,7 +604,8 @@ SDL_FORCE_INLINE void BlitBto3Key(SDL_BlitInfo *info, const Uint32 srcbpp)
Uint8 *palmap = info->table;
int c;
// Set up some basic variables
width += info->leading_skip;
if (srcbpp == 4)
srcskip += width - (width + 1) / 2;
else if (srcbpp == 2)
@@ -509,7 +616,13 @@ SDL_FORCE_INLINE void BlitBto3Key(SDL_BlitInfo *info, const Uint32 srcbpp)
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte >>= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -526,7 +639,13 @@ SDL_FORCE_INLINE void BlitBto3Key(SDL_BlitInfo *info, const Uint32 srcbpp)
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte <<= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -558,7 +677,8 @@ SDL_FORCE_INLINE void BlitBto4Key(SDL_BlitInfo *info, const Uint32 srcbpp)
Uint8 *palmap = info->table;
int c;
// Set up some basic variables
width += info->leading_skip;
if (srcbpp == 4)
srcskip += width - (width + 1) / 2;
else if (srcbpp == 2)
@@ -570,7 +690,13 @@ SDL_FORCE_INLINE void BlitBto4Key(SDL_BlitInfo *info, const Uint32 srcbpp)
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte >>= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -587,7 +713,13 @@ SDL_FORCE_INLINE void BlitBto4Key(SDL_BlitInfo *info, const Uint32 srcbpp)
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte <<= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -617,12 +749,13 @@ static void BlitBtoNAlpha(SDL_BlitInfo *info)
const SDL_PixelFormatDetails *dstfmt = info->dst_fmt;
int srcbpp, dstbpp;
int c;
Uint32 pixel, mask, align;
Uint32 pixelvalue, mask, align;
unsigned sR, sG, sB;
unsigned dR, dG, dB, dA;
const unsigned A = info->a;
// Set up some basic variables
width += info->leading_skip;
srcbpp = srcfmt->bytes_per_pixel;
dstbpp = dstfmt->bytes_per_pixel;
if (srcbpp == 4)
@@ -637,7 +770,13 @@ static void BlitBtoNAlpha(SDL_BlitInfo *info)
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte >>= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -646,7 +785,7 @@ static void BlitBtoNAlpha(SDL_BlitInfo *info)
sR = srcpal[bit].r;
sG = srcpal[bit].g;
sB = srcpal[bit].b;
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA);
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixelvalue, dR, dG, dB, dA);
ALPHA_BLEND_RGBA(sR, sG, sB, A, dR, dG, dB, dA);
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
}
@@ -659,7 +798,13 @@ static void BlitBtoNAlpha(SDL_BlitInfo *info)
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte <<= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -668,7 +813,7 @@ static void BlitBtoNAlpha(SDL_BlitInfo *info)
sR = srcpal[bit].r;
sG = srcpal[bit].g;
sB = srcpal[bit].b;
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA);
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixelvalue, dR, dG, dB, dA);
ALPHA_BLEND_RGBA(sR, sG, sB, A, dR, dG, dB, dA);
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
}
@@ -694,13 +839,14 @@ static void BlitBtoNAlphaKey(SDL_BlitInfo *info)
const SDL_Color *srcpal = info->src_pal->colors;
int srcbpp, dstbpp;
int c;
Uint32 pixel, mask, align;
Uint32 pixelvalue, mask, align;
unsigned sR, sG, sB;
unsigned dR, dG, dB, dA;
const unsigned A = info->a;
Uint32 ckey = info->colorkey;
// Set up some basic variables
width += info->leading_skip;
srcbpp = srcfmt->bytes_per_pixel;
dstbpp = dstfmt->bytes_per_pixel;
if (srcbpp == 4)
@@ -715,7 +861,13 @@ static void BlitBtoNAlphaKey(SDL_BlitInfo *info)
if (SDL_PIXELORDER(info->src_fmt->format) == SDL_BITMAPORDER_4321) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte >>= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -724,7 +876,7 @@ static void BlitBtoNAlphaKey(SDL_BlitInfo *info)
sR = srcpal[bit].r;
sG = srcpal[bit].g;
sB = srcpal[bit].b;
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA);
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixelvalue, dR, dG, dB, dA);
ALPHA_BLEND_RGBA(sR, sG, sB, A, dR, dG, dB, dA);
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
}
@@ -737,7 +889,13 @@ static void BlitBtoNAlphaKey(SDL_BlitInfo *info)
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
for (c = 0; c < info->leading_skip; ++c) {
if (!(c & align)) {
byte = *src++;
}
byte <<= srcbpp;
}
for (; c < width; ++c) {
if (!(c & align)) {
byte = *src++;
}
@@ -746,7 +904,7 @@ static void BlitBtoNAlphaKey(SDL_BlitInfo *info)
sR = srcpal[bit].r;
sG = srcpal[bit].g;
sB = srcpal[bit].b;
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA);
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixelvalue, dR, dG, dB, dA);
ALPHA_BLEND_RGBA(sR, sG, sB, A, dR, dG, dB, dA);
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
}
+5 -5
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -434,7 +434,7 @@ static void Blit1toNAlpha(SDL_BlitInfo *info)
const SDL_PixelFormatDetails *dstfmt = info->dst_fmt;
const SDL_Color *srcpal = info->src_pal->colors;
int dstbpp;
Uint32 pixel;
Uint32 pixelvalue;
unsigned sR, sG, sB, sA;
unsigned dR, dG, dB, dA;
const unsigned A = info->a;
@@ -450,7 +450,7 @@ static void Blit1toNAlpha(SDL_BlitInfo *info)
sG = srcpal[*src].g;
sB = srcpal[*src].b;
sA = (srcpal[*src].a * A) / 255;
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA);
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixelvalue, dR, dG, dB, dA);
ALPHA_BLEND_RGBA(sR, sG, sB, sA, dR, dG, dB, dA);
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
src++;
@@ -475,7 +475,7 @@ static void Blit1toNAlphaKey(SDL_BlitInfo *info)
const SDL_Color *srcpal = info->src_pal->colors;
Uint32 ckey = info->colorkey;
int dstbpp;
Uint32 pixel;
Uint32 pixelvalue;
unsigned sR, sG, sB, sA;
unsigned dR, dG, dB, dA;
const unsigned A = info->a;
@@ -492,7 +492,7 @@ static void Blit1toNAlphaKey(SDL_BlitInfo *info)
sG = srcpal[*src].g;
sB = srcpal[*src].b;
sA = (srcpal[*src].a * A) / 255;
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA);
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixelvalue, dR, dG, dB, dA);
ALPHA_BLEND_RGBA(sR, sG, sB, sA, dR, dG, dB, dA);
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
}
+118 -16
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -242,6 +242,103 @@ static void SDL_TARGETING("sse2") Blit888to888SurfaceAlphaSSE2(SDL_BlitInfo *inf
#endif
#ifdef SDL_LSX_INTRINSICS
static void SDL_TARGETING("lsx") Blit8888to8888PixelAlphaSwizzleLSX(SDL_BlitInfo *info)
{
int width = info->dst_w;
int height = info->dst_h;
Uint8 *src = info->src;
int srcskip = info->src_skip;
Uint8 *dst = info->dst;
int dstskip = info->dst_skip;
const SDL_PixelFormatDetails *srcfmt = info->src_fmt;
const SDL_PixelFormatDetails *dstfmt = info->dst_fmt;
bool fill_alpha = !dstfmt->Amask;
Uint32 dstAmask, dstAshift;
const Uint8 offsets[] = {0, 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12};
SDL_Get8888AlphaMaskAndShift(dstfmt, &dstAmask, &dstAshift);
const __m128i const_0xff00 = __lsx_vreplgr2vr_h(0xff00);
const __m128i const_128 = __lsx_vreplgr2vr_b((Uint8)128);
const __m128i const_32641 = __lsx_vreplgr2vr_h(32641);
const __m128i const_257 = __lsx_vreplgr2vr_h(257);
// The byte offsets for the start of each pixel
const __m128i mask_offsets = __lsx_vld(offsets, 0);
const __m128i convert_mask = __lsx_vadd_w(
__lsx_vreplgr2vr_w(
((srcfmt->Rshift >> 3) << dstfmt->Rshift) |
((srcfmt->Gshift >> 3) << dstfmt->Gshift) |
((srcfmt->Bshift >> 3) << dstfmt->Bshift)),
mask_offsets);
const __m128i alpha_splat_mask = __lsx_vadd_b(__lsx_vreplgr2vr_b(srcfmt->Ashift >> 3), mask_offsets);
const __m128i alpha_fill_mask = __lsx_vreplgr2vr_w((int)dstAmask);
while (height--) {
int i = 0;
for (; i + 4 <= width; i += 4) {
__m128i src128 = __lsx_vld(src, 0);
__m128i dst128 = __lsx_vld(dst, 0);
__m128i srcA = __lsx_vshuf_b(src128, src128, alpha_splat_mask);
src128 = __lsx_vshuf_b(src128, src128, convert_mask);
src128 = __lsx_vor_v(src128, alpha_fill_mask);
__m128i srca_lo = __lsx_vilvl_b(srcA, srcA);
__m128i srca_hi = __lsx_vilvh_b(srcA, srcA);
srca_lo = __lsx_vxor_v(srca_lo, const_0xff00);
srca_hi = __lsx_vxor_v(srca_hi, const_0xff00);
src128 = __lsx_vsub_b(src128, const_128);
dst128 = __lsx_vsub_b(dst128, const_128);
__m128i tmp = __lsx_vilvl_b(dst128, src128);
__m128i dst_lo = __lsx_vsadd_h(__lsx_vmulwev_h_bu_b(srca_lo, tmp), __lsx_vmulwod_h_bu_b(srca_lo, tmp));
tmp = __lsx_vilvh_b(dst128, src128);
__m128i dst_hi = __lsx_vsadd_h(__lsx_vmulwev_h_bu_b(srca_hi, tmp), __lsx_vmulwod_h_bu_b(srca_hi, tmp));
dst_lo = __lsx_vadd_h(dst_lo, const_32641);
dst_hi = __lsx_vadd_h(dst_hi, const_32641);
dst_lo = __lsx_vmuh_hu(dst_lo, const_257);
dst_hi = __lsx_vmuh_hu(dst_hi, const_257);
dst128 = __lsx_vssrarni_bu_h(dst_hi, dst_lo, 0);
if (fill_alpha) {
dst128 = __lsx_vor_v(dst128, alpha_fill_mask);
}
__lsx_vst(dst128, dst, 0);
src += 16;
dst += 16;
}
for (; i < width; ++i) {
Uint32 src32 = *(Uint32 *)src;
Uint32 dst32 = *(Uint32 *)dst;
ALPHA_BLEND_SWIZZLE_8888(src32, dst32, srcfmt, dstfmt);
if (fill_alpha) {
dst32 |= dstAmask;
}
*(Uint32 *)dst = dst32;
src += 4;
dst += 4;
}
src += srcskip;
dst += dstskip;
}
}
#endif
// fast RGB888->(A)RGB888 blending with surface alpha=128 special case
static void BlitRGBtoRGBSurfaceAlpha128(SDL_BlitInfo *info)
{
@@ -486,8 +583,8 @@ static void SDL_TARGETING("mmx") Blit565to565SurfaceAlphaMMX(SDL_BlitInfo *info)
d &= 0x07e0f81f;
*dstp++ = (Uint16)(d | d >> 16);
},{
src1 = *(__m64*)srcp; // 4 src pixels -> src1
dst1 = *(__m64*)dstp; // 4 dst pixels -> dst1
src1 = *(__m64 *)srcp; // 4 src pixels -> src1
dst1 = *(__m64 *)dstp; // 4 dst pixels -> dst1
// red
src2 = src1;
@@ -536,7 +633,7 @@ static void SDL_TARGETING("mmx") Blit565to565SurfaceAlphaMMX(SDL_BlitInfo *info)
mm_res = _mm_or_si64(mm_res, dst2); // RED | GREEN | BLUE -> mm_res
*(__m64*)dstp = mm_res; // mm_res -> 4 dst pixels
*(__m64 *)dstp = mm_res; // mm_res -> 4 dst pixels
srcp += 4;
dstp += 4;
@@ -624,8 +721,8 @@ static void SDL_TARGETING("mmx") Blit555to555SurfaceAlphaMMX(SDL_BlitInfo *info)
d &= 0x03e07c1f;
*dstp++ = (Uint16)(d | d >> 16);
},{
src1 = *(__m64*)srcp; // 4 src pixels -> src1
dst1 = *(__m64*)dstp; // 4 dst pixels -> dst1
src1 = *(__m64 *)srcp; // 4 src pixels -> src1
dst1 = *(__m64 *)dstp; // 4 dst pixels -> dst1
// red -- process the bits in place
src2 = src1;
@@ -674,7 +771,7 @@ static void SDL_TARGETING("mmx") Blit555to555SurfaceAlphaMMX(SDL_BlitInfo *info)
mm_res = _mm_or_si64(mm_res, dst2); // RED | GREEN | BLUE -> mm_res
*(__m64*)dstp = mm_res; // mm_res -> 4 dst pixels
*(__m64 *)dstp = mm_res; // mm_res -> 4 dst pixels
srcp += 4;
dstp += 4;
@@ -1061,8 +1158,8 @@ static void SDL_TARGETING("sse4.1") Blit8888to8888PixelAlphaSwizzleSSE41(SDL_Bli
__m128i dst_hi = _mm_maddubs_epi16(srca_hi, _mm_unpackhi_epi8(src128, dst128));
// dst += 0x1U (use 0x80 to round instead of floor) + 128*255 (to fix maddubs result)
dst_lo = _mm_add_epi16(dst_lo, _mm_set1_epi16(1 + 128*255));
dst_hi = _mm_add_epi16(dst_hi, _mm_set1_epi16(1 + 128*255));
dst_lo = _mm_add_epi16(dst_lo, _mm_set1_epi16(1 + 128 * 255));
dst_hi = _mm_add_epi16(dst_hi, _mm_set1_epi16(1 + 128 * 255));
// dst = (dst + (dst >> 8)) >> 8 = (dst * 257) >> 16
dst_lo = _mm_mulhi_epu16(dst_lo, _mm_set1_epi16(257));
@@ -1165,8 +1262,8 @@ static void SDL_TARGETING("avx2") Blit8888to8888PixelAlphaSwizzleAVX2(SDL_BlitIn
__m256i dst_hi = _mm256_maddubs_epi16(alpha_hi, _mm256_unpackhi_epi8(src256, dst256));
// dst += 0x1U (use 0x80 to round instead of floor) + 128*255 (to fix maddubs result)
dst_lo = _mm256_add_epi16(dst_lo, _mm256_set1_epi16(1 + 128*255));
dst_hi = _mm256_add_epi16(dst_hi, _mm256_set1_epi16(1 + 128*255));
dst_lo = _mm256_add_epi16(dst_lo, _mm256_set1_epi16(1 + 128 * 255));
dst_hi = _mm256_add_epi16(dst_hi, _mm256_set1_epi16(1 + 128 * 255));
// dst = (dst + (dst >> 8)) >> 8 = (dst * 257) >> 16
dst_lo = _mm256_mulhi_epu16(dst_lo, _mm256_set1_epi16(257));
@@ -1202,7 +1299,7 @@ static void SDL_TARGETING("avx2") Blit8888to8888PixelAlphaSwizzleAVX2(SDL_BlitIn
#endif
#if defined(SDL_NEON_INTRINSICS) && (__ARM_ARCH >= 8)
#if defined(SDL_NEON_INTRINSICS) && (__ARM_ARCH >= 8) && (defined(__aarch64__) || defined(_M_ARM64))
static void Blit8888to8888PixelAlphaSwizzleNEON(SDL_BlitInfo *info)
{
@@ -1290,8 +1387,8 @@ static void Blit8888to8888PixelAlphaSwizzleNEON(SDL_BlitInfo *info)
// Process 1 pixel per iteration, max 3 iterations, same calculations as above
for (; i < width; ++i) {
// Top 32-bits will be not used in src32 & dst32
uint8x8_t src32 = vreinterpret_u8_u32(vld1_dup_u32((Uint32*)src));
uint8x8_t dst32 = vreinterpret_u8_u32(vld1_dup_u32((Uint32*)dst));
uint8x8_t src32 = vreinterpret_u8_u32(vld1_dup_u32((Uint32 *)src));
uint8x8_t dst32 = vreinterpret_u8_u32(vld1_dup_u32((Uint32 *)dst));
uint8x8_t srcA = vtbl1_u8(src32, vget_low_u8(alpha_splat_mask));
src32 = vtbl1_u8(src32, vget_low_u8(convert_mask));
@@ -1309,7 +1406,7 @@ static void Blit8888to8888PixelAlphaSwizzleNEON(SDL_BlitInfo *info)
}
// Save the result, only low 32-bits
vst1_lane_u32((Uint32*)dst, vreinterpret_u32_u8(dst32), 0);
vst1_lane_u32((Uint32 *)dst, vreinterpret_u32_u8(dst32), 0);
src += 4;
dst += 4;
@@ -1402,7 +1499,12 @@ SDL_BlitFunc SDL_CalculateBlitA(SDL_Surface *surface)
return Blit8888to8888PixelAlphaSwizzleSSE41;
}
#endif
#if defined(SDL_NEON_INTRINSICS) && (__ARM_ARCH >= 8)
#ifdef SDL_LSX_INTRINSICS
if (SDL_HasLSX()) {
return Blit8888to8888PixelAlphaSwizzleLSX;
}
#endif
#if defined(SDL_NEON_INTRINSICS) && (__ARM_ARCH >= 8) && (defined(__aarch64__) || defined(_M_ARM64))
// To prevent "unused function" compiler warnings/errors
(void)Blit8888to8888PixelAlpha;
(void)Blit8888to8888PixelAlphaSwizzle;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,7 +1,7 @@
// DO NOT EDIT! This file is generated by sdlgenblit.pl
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+28 -28
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -85,12 +85,12 @@ void SDL_Blit_Slow(SDL_BlitInfo *info)
last_index = SDL_LookupRGBAColor(palette_map, last_pixel, dst_pal);
}
incy = ((Uint64)info->src_h << 16) / info->dst_h;
incx = ((Uint64)info->src_w << 16) / info->dst_w;
incy = info->dst_h ? ((Uint64)info->src_h << 16) / info->dst_h : 0;
incx = info->dst_w ? ((Uint64)info->src_w << 16) / info->dst_w : 0;
posy = incy / 2; // start at the middle of pixel
while (info->dst_h--) {
Uint8 *src = 0;
Uint8 *src = NULL;
Uint8 *dst = info->dst;
int n = info->dst_w;
posx = incx / 2; // start at the middle of pixel
@@ -296,25 +296,25 @@ void SDL_Blit_Slow(SDL_BlitInfo *info)
break;
case SlowBlitPixelAccess_10Bit:
{
Uint32 pixel;
Uint32 pixelvalue;
switch (dst_fmt->format) {
case SDL_PIXELFORMAT_XRGB2101010:
dstA = 0xFF;
SDL_FALLTHROUGH;
case SDL_PIXELFORMAT_ARGB2101010:
ARGB2101010_FROM_RGBA(pixel, dstR, dstG, dstB, dstA);
ARGB2101010_FROM_RGBA(pixelvalue, dstR, dstG, dstB, dstA);
break;
case SDL_PIXELFORMAT_XBGR2101010:
dstA = 0xFF;
SDL_FALLTHROUGH;
case SDL_PIXELFORMAT_ABGR2101010:
ABGR2101010_FROM_RGBA(pixel, dstR, dstG, dstB, dstA);
ABGR2101010_FROM_RGBA(pixelvalue, dstR, dstG, dstB, dstA);
break;
default:
pixel = 0;
pixelvalue = 0;
break;
}
*(Uint32 *)dst = pixel;
*(Uint32 *)dst = pixelvalue;
break;
}
case SlowBlitPixelAccess_Large:
@@ -424,49 +424,49 @@ static Uint16 float_to_half(float a)
static void ReadFloatPixel(Uint8 *pixels, SlowBlitPixelAccess access, const SDL_PixelFormatDetails *fmt, const SDL_Palette *pal, SDL_Colorspace colorspace, float SDR_white_point,
float *outR, float *outG, float *outB, float *outA)
{
Uint32 pixel;
Uint32 pixelvalue;
Uint32 R, G, B, A;
float fR = 0.0f, fG = 0.0f, fB = 0.0f, fA = 0.0f;
float v[4];
switch (access) {
case SlowBlitPixelAccess_Index8:
pixel = *pixels;
fR = (float)pal->colors[pixel].r / 255.0f;
fG = (float)pal->colors[pixel].g / 255.0f;
fB = (float)pal->colors[pixel].b / 255.0f;
fA = (float)pal->colors[pixel].a / 255.0f;
pixelvalue = *pixels;
fR = (float)pal->colors[pixelvalue].r / 255.0f;
fG = (float)pal->colors[pixelvalue].g / 255.0f;
fB = (float)pal->colors[pixelvalue].b / 255.0f;
fA = (float)pal->colors[pixelvalue].a / 255.0f;
break;
case SlowBlitPixelAccess_RGB:
DISEMBLE_RGB(pixels, fmt->bytes_per_pixel, fmt, pixel, R, G, B);
DISEMBLE_RGB(pixels, fmt->bytes_per_pixel, fmt, pixelvalue, R, G, B);
fR = (float)R / 255.0f;
fG = (float)G / 255.0f;
fB = (float)B / 255.0f;
fA = 1.0f;
break;
case SlowBlitPixelAccess_RGBA:
DISEMBLE_RGBA(pixels, fmt->bytes_per_pixel, fmt, pixel, R, G, B, A);
DISEMBLE_RGBA(pixels, fmt->bytes_per_pixel, fmt, pixelvalue, R, G, B, A);
fR = (float)R / 255.0f;
fG = (float)G / 255.0f;
fB = (float)B / 255.0f;
fA = (float)A / 255.0f;
break;
case SlowBlitPixelAccess_10Bit:
pixel = *((Uint32 *)pixels);
pixelvalue = *((Uint32 *)pixels);
switch (fmt->format) {
case SDL_PIXELFORMAT_XRGB2101010:
RGBAFLOAT_FROM_ARGB2101010(pixel, fR, fG, fB, fA);
RGBAFLOAT_FROM_ARGB2101010(pixelvalue, fR, fG, fB, fA);
fA = 1.0f;
break;
case SDL_PIXELFORMAT_XBGR2101010:
RGBAFLOAT_FROM_ABGR2101010(pixel, fR, fG, fB, fA);
RGBAFLOAT_FROM_ABGR2101010(pixelvalue, fR, fG, fB, fA);
fA = 1.0f;
break;
case SDL_PIXELFORMAT_ARGB2101010:
RGBAFLOAT_FROM_ARGB2101010(pixel, fR, fG, fB, fA);
RGBAFLOAT_FROM_ARGB2101010(pixelvalue, fR, fG, fB, fA);
break;
case SDL_PIXELFORMAT_ABGR2101010:
RGBAFLOAT_FROM_ABGR2101010(pixel, fR, fG, fB, fA);
RGBAFLOAT_FROM_ABGR2101010(pixelvalue, fR, fG, fB, fA);
break;
default:
fR = fG = fB = fA = 0.0f;
@@ -587,7 +587,7 @@ static void WriteFloatPixel(Uint8 *pixels, SlowBlitPixelAccess access, const SDL
float fR, float fG, float fB, float fA)
{
Uint32 R, G, B, A;
Uint32 pixel;
Uint32 pixelvalue;
float v[4];
// We converted to nits so src and dst are guaranteed to be linear and in the same units
@@ -637,19 +637,19 @@ static void WriteFloatPixel(Uint8 *pixels, SlowBlitPixelAccess access, const SDL
fA = 1.0f;
SDL_FALLTHROUGH;
case SDL_PIXELFORMAT_ARGB2101010:
ARGB2101010_FROM_RGBAFLOAT(pixel, fR, fG, fB, fA);
ARGB2101010_FROM_RGBAFLOAT(pixelvalue, fR, fG, fB, fA);
break;
case SDL_PIXELFORMAT_XBGR2101010:
fA = 1.0f;
SDL_FALLTHROUGH;
case SDL_PIXELFORMAT_ABGR2101010:
ABGR2101010_FROM_RGBAFLOAT(pixel, fR, fG, fB, fA);
ABGR2101010_FROM_RGBAFLOAT(pixelvalue, fR, fG, fB, fA);
break;
default:
pixel = 0;
pixelvalue = 0;
break;
}
*(Uint32 *)pixels = pixel;
*(Uint32 *)pixels = pixelvalue;
break;
}
case SlowBlitPixelAccess_Large:
@@ -897,7 +897,7 @@ void SDL_Blit_Slow_Float(SDL_BlitInfo *info)
posy = incy / 2; // start at the middle of pixel
while (info->dst_h--) {
Uint8 *src = 0;
Uint8 *src = NULL;
Uint8 *dst = info->dst;
int n = info->dst_w;
posx = incx / 2; // start at the middle of pixel
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+148 -92
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -92,13 +92,13 @@ static bool readRlePixels(SDL_Surface *surface, SDL_IOStream *src, int isRle8)
| with two colour indexes to alternate between for the run
*/
if (ch) {
Uint8 pixel;
if (!SDL_ReadU8(src, &pixel)) {
Uint8 pixelvalue;
if (!SDL_ReadU8(src, &pixelvalue)) {
return false;
}
ch /= pixels_per_byte;
do {
COPY_PIXEL(pixel);
COPY_PIXEL(pixelvalue);
} while (--ch);
} else {
/*
@@ -131,11 +131,11 @@ static bool readRlePixels(SDL_Surface *surface, SDL_IOStream *src, int isRle8)
ch /= pixels_per_byte;
needsPad = (ch & 1);
do {
Uint8 pixel;
if (!SDL_ReadU8(src, &pixel)) {
Uint8 pixelvalue;
if (!SDL_ReadU8(src, &pixelvalue)) {
return false;
}
COPY_PIXEL(pixel);
COPY_PIXEL(pixelvalue);
} while (--ch);
// pad at even boundary
@@ -177,6 +177,26 @@ static void CorrectAlphaChannel(SDL_Surface *surface)
}
}
bool SDL_IsBMP(SDL_IOStream *src)
{
Sint64 start;
Uint8 magic[2];
bool is_BMP;
is_BMP = false;
start = SDL_TellIO(src);
if (start >= 0) {
if (SDL_ReadIO(src, magic, sizeof(magic)) == sizeof(magic)) {
if (magic[0] == 'B' && magic[1] == 'M') {
is_BMP = true;
}
}
SDL_SeekIO(src, start, SDL_IO_SEEK_SET);
}
return is_BMP;
}
SDL_Surface *SDL_LoadBMP_IO(SDL_IOStream *src, bool closeio)
{
bool was_error = true;
@@ -195,7 +215,7 @@ SDL_Surface *SDL_LoadBMP_IO(SDL_IOStream *src, bool closeio)
bool correctAlpha = false;
// The Win32 BMP file header (14 bytes)
char magic[2];
// char magic[2];
// Uint32 bfSize;
// Uint16 bfReserved1;
// Uint16 bfReserved2;
@@ -216,7 +236,7 @@ SDL_Surface *SDL_LoadBMP_IO(SDL_IOStream *src, bool closeio)
// Make sure we are passed a valid data source
surface = NULL;
if (!src) {
CHECK_PARAM(!src) {
SDL_InvalidParamError("src");
goto done;
}
@@ -227,14 +247,12 @@ SDL_Surface *SDL_LoadBMP_IO(SDL_IOStream *src, bool closeio)
goto done;
}
SDL_ClearError();
if (SDL_ReadIO(src, magic, 2) != 2) {
goto done;
}
if (SDL_strncmp(magic, "BM", 2) != 0) {
if (!SDL_IsBMP(src)) {
SDL_SetError("File is not a Windows BMP file");
goto done;
}
if (!SDL_ReadU32LE(src, NULL /* bfSize */) ||
if (!SDL_ReadU16LE(src, NULL /* magic (already checked) */) ||
!SDL_ReadU32LE(src, NULL /* bfSize */) ||
!SDL_ReadU16LE(src, NULL /* bfReserved1 */) ||
!SDL_ReadU16LE(src, NULL /* bfReserved2 */) ||
!SDL_ReadU32LE(src, &bfOffBits)) {
@@ -573,6 +591,78 @@ done:
return surface;
}
typedef struct {
SDL_Surface *surface;
SDL_Surface *intermediate_surface;
bool save32bit;
bool saveLegacyBMP;
} BMPSaveState;
static void FreeBMPSaveState(BMPSaveState *state)
{
if (state->intermediate_surface && state->intermediate_surface != state->surface) {
SDL_DestroySurface(state->intermediate_surface);
}
}
static bool InitBMPSaveState(BMPSaveState *state, SDL_Surface *surface)
{
state->surface = surface;
state->intermediate_surface = NULL;
state->save32bit = false;
state->saveLegacyBMP = false;
CHECK_PARAM(!SDL_SurfaceValid(surface)) {
return SDL_InvalidParamError("surface");
}
#ifdef SAVE_32BIT_BMP
// We can save alpha information in a 32-bit BMP
if (SDL_BITSPERPIXEL(surface->format) >= 8 &&
(SDL_ISPIXELFORMAT_ALPHA(surface->format) ||
(surface->map.info.flags & SDL_COPY_COLORKEY))) {
state->save32bit = true;
}
#endif // SAVE_32BIT_BMP
if (surface->palette && !state->save32bit) {
if (SDL_BITSPERPIXEL(surface->format) == 8) {
state->intermediate_surface = surface;
} else {
SDL_SetError("%u bpp BMP files not supported",
SDL_BITSPERPIXEL(surface->format));
goto error;
}
} else if ((surface->format == SDL_PIXELFORMAT_BGR24 && !state->save32bit) ||
(surface->format == SDL_PIXELFORMAT_BGRA32 && state->save32bit)) {
state->intermediate_surface = surface;
} else {
SDL_PixelFormat pixel_format;
/* If the surface has a colorkey or alpha channel we'll save a
32-bit BMP with alpha channel, otherwise save a 24-bit BMP. */
if (state->save32bit) {
pixel_format = SDL_PIXELFORMAT_BGRA32;
} else {
pixel_format = SDL_PIXELFORMAT_BGR24;
}
state->intermediate_surface = SDL_ConvertSurface(surface, pixel_format);
if (!state->intermediate_surface) {
SDL_SetError("Couldn't convert image to %d bpp",
(int)SDL_BITSPERPIXEL(pixel_format));
goto error;
}
}
if (state->save32bit) {
state->saveLegacyBMP = SDL_GetHintBoolean(SDL_HINT_BMP_SAVE_LEGACY_FORMAT, false);
}
return true;
error:
FreeBMPSaveState(state);
return false;
}
SDL_Surface *SDL_LoadBMP(const char *file)
{
SDL_IOStream *stream = SDL_IOFromFile(file, "rb");
@@ -581,16 +671,12 @@ SDL_Surface *SDL_LoadBMP(const char *file)
}
return SDL_LoadBMP_IO(stream, true);
}
bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
static bool SDL_SaveBMP_IO_Internal(BMPSaveState *state, SDL_IOStream *dst, bool closeio)
{
bool was_error = true;
Sint64 fp_offset, new_offset;
int i, pad;
SDL_Surface *intermediate_surface = NULL;
Uint8 *bits;
bool save32bit = false;
bool saveLegacyBMP = false;
// The Win32 BMP file header (14 bytes)
char magic[2] = { 'B', 'M' };
@@ -629,60 +715,8 @@ bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
Uint32 bV5ProfileSize = 0;
Uint32 bV5Reserved = 0;
// Make sure we have somewhere to save
if (!SDL_SurfaceValid(surface)) {
SDL_InvalidParamError("surface");
goto done;
}
if (!dst) {
SDL_InvalidParamError("dst");
goto done;
}
#ifdef SAVE_32BIT_BMP
// We can save alpha information in a 32-bit BMP
if (SDL_BITSPERPIXEL(surface->format) >= 8 &&
(SDL_ISPIXELFORMAT_ALPHA(surface->format) ||
surface->map.info.flags & SDL_COPY_COLORKEY)) {
save32bit = true;
}
#endif // SAVE_32BIT_BMP
if (surface->palette && !save32bit) {
if (SDL_BITSPERPIXEL(surface->format) == 8) {
intermediate_surface = surface;
} else {
SDL_SetError("%u bpp BMP files not supported",
SDL_BITSPERPIXEL(surface->format));
goto done;
}
} else if ((surface->format == SDL_PIXELFORMAT_BGR24 && !save32bit) ||
(surface->format == SDL_PIXELFORMAT_BGRA32 && save32bit)) {
intermediate_surface = surface;
} else {
SDL_PixelFormat pixel_format;
/* If the surface has a colorkey or alpha channel we'll save a
32-bit BMP with alpha channel, otherwise save a 24-bit BMP. */
if (save32bit) {
pixel_format = SDL_PIXELFORMAT_BGRA32;
} else {
pixel_format = SDL_PIXELFORMAT_BGR24;
}
intermediate_surface = SDL_ConvertSurface(surface, pixel_format);
if (!intermediate_surface) {
SDL_SetError("Couldn't convert image to %d bpp",
(int)SDL_BITSPERPIXEL(pixel_format));
goto done;
}
}
if (save32bit) {
saveLegacyBMP = SDL_GetHintBoolean(SDL_HINT_BMP_SAVE_LEGACY_FORMAT, false);
}
if (SDL_LockSurface(intermediate_surface)) {
const size_t bw = intermediate_surface->w * intermediate_surface->fmt->bytes_per_pixel;
if (SDL_LockSurface(state->intermediate_surface)) {
const size_t bw = state->intermediate_surface->w * state->intermediate_surface->fmt->bytes_per_pixel;
// Set the BMP file header values
bfSize = 0; // We'll write this when we're done
@@ -705,23 +739,23 @@ bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
// Set the BMP info values
biSize = 40;
biWidth = intermediate_surface->w;
biHeight = intermediate_surface->h;
biWidth = state->intermediate_surface->w;
biHeight = state->intermediate_surface->h;
biPlanes = 1;
biBitCount = intermediate_surface->fmt->bits_per_pixel;
biBitCount = state->intermediate_surface->fmt->bits_per_pixel;
biCompression = BI_RGB;
biSizeImage = intermediate_surface->h * intermediate_surface->pitch;
biSizeImage = state->intermediate_surface->h * state->intermediate_surface->pitch;
biXPelsPerMeter = 0;
biYPelsPerMeter = 0;
if (intermediate_surface->palette) {
biClrUsed = intermediate_surface->palette->ncolors;
if (state->intermediate_surface->palette) {
biClrUsed = state->intermediate_surface->palette->ncolors;
} else {
biClrUsed = 0;
}
biClrImportant = 0;
// Set the BMP info values
if (save32bit && !saveLegacyBMP) {
if (state->save32bit && !state->saveLegacyBMP) {
biSize = 124;
// Version 4 values
biCompression = BI_BITFIELDS;
@@ -757,7 +791,7 @@ bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
}
// Write the BMP info values
if (save32bit && !saveLegacyBMP) {
if (state->save32bit && !state->saveLegacyBMP) {
// Version 4 values
if (!SDL_WriteU32LE(dst, bV4RedMask) ||
!SDL_WriteU32LE(dst, bV4GreenMask) ||
@@ -786,12 +820,12 @@ bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
}
// Write the palette (in BGR color order)
if (intermediate_surface->palette) {
if (state->intermediate_surface->palette) {
SDL_Color *colors;
int ncolors;
colors = intermediate_surface->palette->colors;
ncolors = intermediate_surface->palette->ncolors;
colors = state->intermediate_surface->palette->colors;
ncolors = state->intermediate_surface->palette->ncolors;
for (i = 0; i < ncolors; ++i) {
if (!SDL_WriteU8(dst, colors[i].b) ||
!SDL_WriteU8(dst, colors[i].g) ||
@@ -815,10 +849,10 @@ bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
}
// Write the bitmap image upside down
bits = (Uint8 *)intermediate_surface->pixels + (intermediate_surface->h * intermediate_surface->pitch);
bits = (Uint8 *)state->intermediate_surface->pixels + (state->intermediate_surface->h * state->intermediate_surface->pitch);
pad = ((bw % 4) ? (4 - (bw % 4)) : 0);
while (bits > (Uint8 *)intermediate_surface->pixels) {
bits -= intermediate_surface->pitch;
while (bits > (Uint8 *)state->intermediate_surface->pixels) {
bits -= state->intermediate_surface->pitch;
if (SDL_WriteIO(dst, bits, bw) != bw) {
goto done;
}
@@ -849,15 +883,12 @@ bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
}
// Close it up..
SDL_UnlockSurface(intermediate_surface);
SDL_UnlockSurface(state->intermediate_surface);
was_error = false;
}
done:
if (intermediate_surface && intermediate_surface != surface) {
SDL_DestroySurface(intermediate_surface);
}
if (closeio && dst) {
if (!SDL_CloseIO(dst)) {
was_error = true;
@@ -869,11 +900,36 @@ done:
return true;
}
bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
{
bool result = true;
BMPSaveState state;
if (!InitBMPSaveState(&state, surface)) {
return false;
}
CHECK_PARAM(!dst) {
result = SDL_InvalidParamError("dst");
goto done;
}
result = SDL_SaveBMP_IO_Internal(&state, dst, closeio);
done:
FreeBMPSaveState(&state);
return result;
}
bool SDL_SaveBMP(SDL_Surface *surface, const char *file)
{
BMPSaveState state;
if (!InitBMPSaveState(&state, surface)) {
return false;
}
SDL_IOStream *stream = SDL_IOFromFile(file, "wb");
if (!stream) {
return false;
}
return SDL_SaveBMP_IO(surface, stream, true);
bool result = SDL_SaveBMP_IO_Internal(&state, stream, true);
FreeBMPSaveState(&state);
return result;
}
+14 -7
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -156,9 +156,9 @@ bool SDL_SetClipboardData(SDL_ClipboardDataCallback callback, SDL_ClipboardClean
}
char **mime_types_copy = SDL_CopyClipboardMimeTypes(mime_types, num_mime_types, true);
if (!mime_types_copy)
if (!mime_types_copy) {
return SDL_SetError("unable to copy current mime types");
}
SDL_SendClipboardUpdate(true, mime_types_copy, num_mime_types);
return true;
}
@@ -173,6 +173,11 @@ void *SDL_GetInternalClipboardData(SDL_VideoDevice *_this, const char *mime_type
void *data = NULL;
if (_this->clipboard_callback) {
if (!SDL_HasInternalClipboardData(_this, mime_type)) {
// The callback hasn't advertised that it can handle this mime type
return NULL;
}
const void *provided_data = _this->clipboard_callback(_this->clipboard_userdata, mime_type, size);
if (provided_data) {
// Make a copy of it for the caller and guarantee null termination
@@ -180,6 +185,8 @@ void *SDL_GetInternalClipboardData(SDL_VideoDevice *_this, const char *mime_type
if (data) {
SDL_memcpy(data, provided_data, *size);
SDL_memset((Uint8 *)data + *size, 0, sizeof(Uint32));
} else {
*size = 0;
}
}
}
@@ -196,7 +203,7 @@ void *SDL_GetClipboardData(const char *mime_type, size_t *size)
return NULL;
}
if (!mime_type) {
CHECK_PARAM(!mime_type) {
SDL_InvalidParamError("mime_type");
return NULL;
}
@@ -245,7 +252,7 @@ bool SDL_HasClipboardData(const char *mime_type)
return SDL_UninitializedVideo();
}
if (!mime_type) {
CHECK_PARAM(!mime_type) {
return SDL_InvalidParamError("mime_type");
}
@@ -432,9 +439,9 @@ bool SDL_SetPrimarySelectionText(const char *text)
}
char **mime_types = SDL_CopyClipboardMimeTypes((const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types, true);
if (!mime_types)
if (!mime_types) {
return SDL_SetError("unable to copy current mime types");
}
SDL_SendClipboardUpdate(true, mime_types, _this->num_clipboard_mime_types);
return true;
}
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+72 -25
View File
@@ -1,6 +1,6 @@
/*
* Simple DirectMedia Layer
* Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
* Copyright (C) 1997-2026 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
@@ -38,6 +38,7 @@
#include "SDL_sysvideo.h"
#include "SDL_egl_c.h"
#include "../SDL_hints_c.h"
#ifdef EGL_KHR_create_context
// EGL_OPENGL_ES3_BIT_KHR was added in version 13 of the extension.
@@ -51,7 +52,12 @@
#define EGL_COLOR_COMPONENT_TYPE_EXT 0x3339
#define EGL_COLOR_COMPONENT_TYPE_FIXED_EXT 0x333A
#define EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT 0x333B
#endif
#endif // EGL_EXT_pixel_format_float
#ifndef EGL_EXT_platform_device
#define EGL_EXT_platform_device 1
#define EGL_PLATFORM_DEVICE_EXT 0x313F
#endif // EGL_EXT_platform_device
#ifndef EGL_EXT_present_opaque
#define EGL_EXT_present_opaque 1
@@ -105,19 +111,43 @@
#define DEFAULT_OGL_ES2 "libGLESv2.so.2"
#define DEFAULT_OGL_ES_PVR "libGLES_CM.so.1"
#define DEFAULT_OGL_ES "libGLESv1_CM.so.1"
SDL_ELF_NOTE_DLOPEN(
"egl-opengl",
"Support for OpenGL",
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
DEFAULT_OGL, ALT_OGL
)
SDL_ELF_NOTE_DLOPEN(
"egl-egl",
"Support for EGL",
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
DEFAULT_EGL
)
SDL_ELF_NOTE_DLOPEN(
"egl-es2",
"Support for EGL ES2",
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
DEFAULT_OGL_ES2
)
SDL_ELF_NOTE_DLOPEN(
"egl-es-pvr",
"Support for EGL ES PVR",
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
DEFAULT_OGL_ES_PVR
)
SDL_ELF_NOTE_DLOPEN(
"egl-ogl-es",
"Support for OpenGL ES",
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
DEFAULT_OGL_ES
)
#endif // SDL_VIDEO_DRIVER_RPI
#if defined(SDL_VIDEO_OPENGL) && !defined(SDL_VIDEO_VITA_PVR_OGL)
#include <SDL3/SDL_opengl.h>
#endif
/** If we happen to not have this defined because of an older EGL version, just define it 0x0
as eglGetPlatformDisplayEXT will most likely be NULL if this is missing
*/
#ifndef EGL_PLATFORM_DEVICE_EXT
#define EGL_PLATFORM_DEVICE_EXT 0x0
#endif
#ifdef SDL_VIDEO_OPENGL
typedef void (APIENTRY* PFNGLGETINTEGERVPROC) (GLenum pname, GLint * params);
#endif
@@ -260,7 +290,7 @@ SDL_FunctionPointer SDL_EGL_GetProcAddressInternal(SDL_VideoDevice *_this, const
result = _this->egl_data->eglGetProcAddress(proc);
}
#if !defined(SDL_PLATFORM_EMSCRIPTEN) && !defined(SDL_VIDEO_DRIVER_VITA) // LoadFunction isn't needed on Emscripten and will call dlsym(), causing other problems.
#if !defined(SDL_VIDEO_DRIVER_VITA)
// Try SDL_LoadFunction() first for EGL <= 1.4, or as a fallback for >= 1.5.
if (!result) {
result = SDL_LoadFunction(_this->egl_data->opengl_dll_handle, proc);
@@ -716,7 +746,7 @@ static Attribute all_attributes[] = {
static void dumpconfig(SDL_VideoDevice *_this, EGLConfig config)
{
int attr;
for (attr = 0; attr < sizeof(all_attributes) / sizeof(Attribute); attr++) {
for (attr = 0; attr < SDL_arraysize(all_attributes); attr++) {
EGLint value;
_this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display, config, all_attributes[attr].attribute, &value);
SDL_Log("\t%-32s: %10d (0x%08x)", all_attributes[attr].name, value, value);
@@ -1036,7 +1066,7 @@ SDL_GLContext SDL_EGL_CreateContext(SDL_VideoDevice *_this, EGLSurface egl_surfa
#endif
if (_this->egl_contextattrib_callback) {
const int maxAttribs = sizeof(attribs) / sizeof(attribs[0]);
const int maxAttribs = SDL_arraysize(attribs);
EGLint *userAttribs, *userAttribP;
userAttribs = _this->egl_contextattrib_callback(_this->egl_attrib_callback_userdata, _this->egl_data->egl_display, _this->egl_data->egl_config);
if (!userAttribs) {
@@ -1078,6 +1108,7 @@ SDL_GLContext SDL_EGL_CreateContext(SDL_VideoDevice *_this, EGLSurface egl_surfa
return NULL;
}
// The default swap interval is 1, according to the spec, but SDL3's policy is to default vsync to off by default.
_this->egl_data->egl_swapinterval = 0;
if (!SDL_EGL_MakeCurrent(_this, egl_surface, (SDL_GLContext)egl_context)) {
@@ -1114,6 +1145,8 @@ SDL_GLContext SDL_EGL_CreateContext(SDL_VideoDevice *_this, EGLSurface egl_surfa
}
}
SDL_EGL_SetSwapInterval(_this, 0); // EGL tends to default to vsync=1. To make this consistent with the rest of SDL, we force it off at startup. Apps can explicitly enable it afterwards.
return (SDL_GLContext)egl_context;
}
@@ -1238,21 +1271,28 @@ EGLSurface SDL_EGL_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, Nat
ANativeWindow_setBuffersGeometry(nw, 0, 0, format_wanted);
#endif
if (_this->gl_config.framebuffer_srgb_capable) {
#ifdef EGL_KHR_gl_colorspace
if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_gl_colorspace")) {
if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_KHR_gl_colorspace")) {
const char *srgbhint = SDL_GetHint(SDL_HINT_OPENGL_FORCE_SRGB_FRAMEBUFFER);
if (srgbhint && *srgbhint) {
if (SDL_strcmp(srgbhint, "skip") == 0) {
// don't set an attribute at all.
} else {
attribs[attr++] = EGL_GL_COLORSPACE_KHR;
attribs[attr++] = SDL_GetStringBoolean(srgbhint, false) ? EGL_GL_COLORSPACE_SRGB_KHR : EGL_GL_COLORSPACE_LINEAR_KHR;
}
} else if (_this->gl_config.framebuffer_srgb_capable >= 0) { // default behavior without the hint.
attribs[attr++] = EGL_GL_COLORSPACE_KHR;
attribs[attr++] = EGL_GL_COLORSPACE_SRGB_KHR;
} else
#endif
{
SDL_SetError("EGL implementation does not support sRGB system framebuffers");
return EGL_NO_SURFACE;
attribs[attr++] = _this->gl_config.framebuffer_srgb_capable ? EGL_GL_COLORSPACE_SRGB_KHR : EGL_GL_COLORSPACE_LINEAR_KHR;
}
}
#endif
int opaque_ext_idx = -1;
#ifdef EGL_EXT_present_opaque
if (SDL_EGL_HasExtension(_this, SDL_EGL_DISPLAY_EXTENSION, "EGL_EXT_present_opaque")) {
opaque_ext_idx = attr;
bool allow_transparent = false;
if (window && (window->flags & SDL_WINDOW_TRANSPARENT)) {
allow_transparent = true;
@@ -1263,7 +1303,7 @@ EGLSurface SDL_EGL_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, Nat
#endif
if (_this->egl_surfaceattrib_callback) {
const int maxAttribs = sizeof(attribs) / sizeof(attribs[0]);
const int maxAttribs = SDL_arraysize(attribs);
EGLint *userAttribs, *userAttribP;
userAttribs = _this->egl_surfaceattrib_callback(_this->egl_attrib_callback_userdata, _this->egl_data->egl_display, _this->egl_data->egl_config);
if (!userAttribs) {
@@ -1288,10 +1328,17 @@ EGLSurface SDL_EGL_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, Nat
attribs[attr++] = EGL_NONE;
surface = _this->egl_data->eglCreateWindowSurface(
_this->egl_data->egl_display,
_this->egl_data->egl_config,
nw, &attribs[0]);
surface = _this->egl_data->eglCreateWindowSurface(_this->egl_data->egl_display, _this->egl_data->egl_config, nw, &attribs[0]);
if (surface == EGL_NO_SURFACE) {
// we had a report of Nvidia drivers that report EGL_BAD_ATTRIBUTE if you try to
// use EGL_PRESENT_OPAQUE_EXT, even when EGL_EXT_present_opaque is reported as available.
// If we used it, try a second time without this attribute.
if ((_this->egl_data->eglGetError() == EGL_BAD_ATTRIBUTE) && (opaque_ext_idx >= 0)) {
SDL_memmove(&attribs[opaque_ext_idx], &attribs[opaque_ext_idx + 2], sizeof (attribs[0]) * ((attr - opaque_ext_idx) - 2));
surface = _this->egl_data->eglCreateWindowSurface(_this->egl_data->egl_display, _this->egl_data->egl_config, nw, &attribs[0]);
}
}
if (surface == EGL_NO_SURFACE) {
SDL_EGL_SetError("unable to create an EGL window surface", "eglCreateWindowSurface");
}
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+78 -10
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -133,6 +133,69 @@ DEFINE_SSE_FILLRECT(4, Uint32)
/* *INDENT-ON* */ // clang-format on
#endif // __SSE__
#ifdef SDL_LSX_INTRINSICS
/* *INDENT-OFF* */ // clang-format off
#define LSX_BEGIN __m128i c128 = __lsx_vreplgr2vr_w(color);
#define LSX_WORK \
for (i = n / 64; i--;) { \
__lsx_vst(c128, p, 0); \
__lsx_vst(c128, p, 16); \
__lsx_vst(c128, p, 32); \
__lsx_vst(c128, p, 48); \
p += 64; \
}
#define DEFINE_LSX_FILLRECT(bpp, type) \
static void SDL_TARGETING("lsx") SDL_FillSurfaceRect##bpp##LSX(Uint8 *pixels, int pitch, Uint32 color, int w, int h) \
{ \
int i, n; \
Uint8 *p = NULL; \
\
/* If the number of bytes per row is equal to the pitch, treat */ \
/* all rows as one long continuous row (for better performance) */ \
if ((w) * (bpp) == pitch) { \
w = w * h; \
h = 1; \
} \
\
LSX_BEGIN; \
\
while (h--) { \
n = (w) * (bpp); \
p = pixels; \
\
if (n > 63) { \
int adjust = 16 - ((uintptr_t)p & 15); \
if (adjust < 16) { \
n -= adjust; \
adjust /= (bpp); \
while (adjust--) { \
*((type *)p) = (type)color; \
p += (bpp); \
} \
} \
LSX_WORK; \
} \
if (n & 63) { \
int remainder = (n & 63); \
remainder /= (bpp); \
while (remainder--) { \
*((type *)p) = (type)color; \
p += (bpp); \
} \
} \
pixels += pitch; \
} \
\
}
DEFINE_LSX_FILLRECT(4, Uint32)
/* *INDENT-ON* */ // clang-format on
#endif /* __LSX__ */
static void SDL_FillSurfaceRect1(Uint8 *pixels, int pitch, Uint32 color, int w, int h)
{
int n;
@@ -238,7 +301,7 @@ static void SDL_FillSurfaceRect4(Uint8 *pixels, int pitch, Uint32 color, int w,
*/
bool SDL_FillSurfaceRect(SDL_Surface *dst, const SDL_Rect *rect, Uint32 color)
{
if (!SDL_SurfaceValid(dst)) {
CHECK_PARAM(!SDL_SurfaceValid(dst)) {
return SDL_InvalidParamError("SDL_FillSurfaceRect(): dst");
}
@@ -262,22 +325,21 @@ bool SDL_FillSurfaceRects(SDL_Surface *dst, const SDL_Rect *rects, int count, Ui
void (*fill_function)(Uint8 * pixels, int pitch, Uint32 color, int w, int h) = NULL;
int i;
if (!SDL_SurfaceValid(dst)) {
CHECK_PARAM(!SDL_SurfaceValid(dst)) {
return SDL_InvalidParamError("SDL_FillSurfaceRects(): dst");
}
// Nothing to do
if (dst->w == 0 || dst->h == 0) {
return true;
CHECK_PARAM(!rects) {
return SDL_InvalidParamError("SDL_FillSurfaceRects(): rects");
}
// Perform software fill
if (!dst->pixels) {
if (!dst->pixels && SDL_MUSTLOCK(dst)) {
return SDL_SetError("SDL_FillSurfaceRects(): You must lock the surface");
}
if (!rects) {
return SDL_InvalidParamError("SDL_FillSurfaceRects(): rects");
// Nothing to do
if (dst->w == 0 || dst->h == 0 || !dst->pixels) {
return true;
}
/* This function doesn't usually work on surfaces < 8 bpp
@@ -340,6 +402,12 @@ bool SDL_FillSurfaceRects(SDL_Surface *dst, const SDL_Rect *rects, int count, Ui
fill_function = SDL_FillSurfaceRect4SSE;
break;
}
#endif
#ifdef SDL_LSX_INTRINSICS
if (SDL_HasLSX()) {
fill_function = SDL_FillSurfaceRect4LSX;
break;
}
#endif
fill_function = SDL_FillSurfaceRect4;
break;
+132 -62
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -28,6 +28,67 @@
// Lookup tables to expand partial bytes to the full 0..255 range
// This is the code used to generate the lookup tables below:
#if 0
#include <stdio.h>
#include <SDL3/SDL.h>
#define GENERATE_SHIFTS
static Uint32 Calculate(int v, int bits, int vmax, int shift)
{
#if defined(GENERATE_FLOOR)
return (Uint32)SDL_floor(v * 255.0f / vmax) << shift;
#elif defined(GENERATE_ROUND)
return (Uint32)SDL_roundf(v * 255.0f / vmax) << shift;
#elif defined(GENERATE_SHIFTS)
switch (bits) {
case 1:
v = (v << 7) | (v << 6) | (v << 5) | (v << 4) | (v << 3) | (v << 2) | (v << 1) | v;
break;
case 2:
v = (v << 6) | (v << 4) | (v << 2) | v;
break;
case 3:
v = (v << 5) | (v << 2) | (v >> 1);
break;
case 4:
v = (v << 4) | v;
break;
case 5:
v = (v << 3) | (v >> 2);
break;
case 6:
v = (v << 2) | (v >> 4);
break;
case 7:
v = (v << 1) | (v >> 6);
break;
case 8:
break;
}
return (Uint32)v << shift;
#endif
}
int main(int argc, char *argv[])
{
int i, b;
for (b = 1; b <= 8; ++b) {
printf("static const Uint8 lookup_%d[] = {\n ", b);
for (i = 0; i < (1 << b); ++i) {
if (i > 0) {
printf(", ");
}
printf("%d", Calculate(i, b, (1 << b) - 1, 0));
}
printf("\n};\n\n");
}
return 0;
}
#endif
static const Uint8 lookup_0[] = {
255
};
@@ -41,7 +102,7 @@ static const Uint8 lookup_2[] = {
};
static const Uint8 lookup_3[] = {
0, 36, 72, 109, 145, 182, 218, 255
0, 36, 73, 109, 146, 182, 219, 255
};
static const Uint8 lookup_4[] = {
@@ -49,15 +110,15 @@ static const Uint8 lookup_4[] = {
};
static const Uint8 lookup_5[] = {
0, 8, 16, 24, 32, 41, 49, 57, 65, 74, 82, 90, 98, 106, 115, 123, 131, 139, 148, 156, 164, 172, 180, 189, 197, 205, 213, 222, 230, 238, 246, 255
0, 8, 16, 24, 33, 41, 49, 57, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173, 181, 189, 198, 206, 214, 222, 231, 239, 247, 255
};
static const Uint8 lookup_6[] = {
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 141, 145, 149, 153, 157, 161, 165, 170, 174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 214, 218, 222, 226, 230, 234, 238, 242, 246, 250, 255
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178, 182, 186, 190, 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255
};
static const Uint8 lookup_7[] = {
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 255
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255
};
static const Uint8 lookup_8[] = {
@@ -1035,7 +1096,7 @@ SDL_Palette *SDL_CreatePalette(int ncolors)
SDL_Palette *palette;
// Input validation
if (ncolors < 1) {
CHECK_PARAM(ncolors < 1) {
SDL_InvalidParamError("ncolors");
return NULL;
}
@@ -1126,14 +1187,14 @@ void SDL_DitherPalette(SDL_Palette *palette)
/*
* Match an RGB value to a particular palette index
*/
Uint8 SDL_FindColor(const SDL_Palette *pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
static Uint8 SDL_FindColor(const SDL_Palette *pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
// Do colorspace distance matching
unsigned int smallest;
unsigned int distance;
int rd, gd, bd, ad;
int i;
Uint8 pixel = 0;
Uint8 pixelvalue = 0;
smallest = ~0U;
for (i = 0; i < pal->ncolors; ++i) {
@@ -1143,29 +1204,31 @@ Uint8 SDL_FindColor(const SDL_Palette *pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
ad = pal->colors[i].a - a;
distance = (rd * rd) + (gd * gd) + (bd * bd) + (ad * ad);
if (distance < smallest) {
pixel = (Uint8)i;
pixelvalue = (Uint8)i;
if (distance == 0) { // Perfect match!
break;
}
smallest = distance;
}
}
return pixel;
return pixelvalue;
}
Uint8 SDL_LookupRGBAColor(SDL_HashTable *palette_map, Uint32 pixel, const SDL_Palette *pal)
Uint8 SDL_LookupRGBAColor(SDL_HashTable *palette_map, Uint32 pixelvalue, const SDL_Palette *pal)
{
Uint8 color_index = 0;
const void *value;
if (SDL_FindInHashTable(palette_map, (const void *)(uintptr_t)pixel, &value)) {
color_index = (Uint8)(uintptr_t)value;
} else {
Uint8 r = (Uint8)((pixel >> 24) & 0xFF);
Uint8 g = (Uint8)((pixel >> 16) & 0xFF);
Uint8 b = (Uint8)((pixel >> 8) & 0xFF);
Uint8 a = (Uint8)((pixel >> 0) & 0xFF);
color_index = SDL_FindColor(pal, r, g, b, a);
SDL_InsertIntoHashTable(palette_map, (const void *)(uintptr_t)pixel, (const void *)(uintptr_t)color_index, true);
if (pal) {
const void *value;
if (SDL_FindInHashTable(palette_map, (const void *)(uintptr_t)pixelvalue, &value)) {
color_index = (Uint8)(uintptr_t)value;
} else {
Uint8 r = (Uint8)((pixelvalue >> 24) & 0xFF);
Uint8 g = (Uint8)((pixelvalue >> 16) & 0xFF);
Uint8 b = (Uint8)((pixelvalue >> 8) & 0xFF);
Uint8 a = (Uint8)((pixelvalue >> 0) & 0xFF);
color_index = SDL_FindColor(pal, r, g, b, a);
SDL_InsertIntoHashTable(palette_map, (const void *)(uintptr_t)pixelvalue, (const void *)(uintptr_t)color_index, true);
}
}
return color_index;
}
@@ -1219,13 +1282,13 @@ void SDL_DetectPalette(const SDL_Palette *pal, bool *is_opaque, bool *has_alpha_
// Find the opaque pixel value corresponding to an RGB triple
Uint32 SDL_MapRGB(const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 r, Uint8 g, Uint8 b)
{
if (!format) {
CHECK_PARAM(!format) {
SDL_InvalidParamError("format");
return 0;
}
if (SDL_ISPIXELFORMAT_INDEXED(format->format)) {
if (!palette) {
CHECK_PARAM(!palette) {
SDL_InvalidParamError("palette");
return 0;
}
@@ -1248,13 +1311,13 @@ Uint32 SDL_MapRGB(const SDL_PixelFormatDetails *format, const SDL_Palette *palet
// Find the pixel value corresponding to an RGBA quadruple
Uint32 SDL_MapRGBA(const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
if (!format) {
CHECK_PARAM(!format) {
SDL_InvalidParamError("format");
return 0;
}
if (SDL_ISPIXELFORMAT_INDEXED(format->format)) {
if (!palette) {
CHECK_PARAM(!palette) {
SDL_InvalidParamError("palette");
return 0;
}
@@ -1274,7 +1337,7 @@ Uint32 SDL_MapRGBA(const SDL_PixelFormatDetails *format, const SDL_Palette *pale
}
}
void SDL_GetRGB(Uint32 pixel, const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 *r, Uint8 *g, Uint8 *b)
void SDL_GetRGB(Uint32 pixelvalue, const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 *r, Uint8 *g, Uint8 *b)
{
Uint8 unused;
@@ -1294,10 +1357,10 @@ void SDL_GetRGB(Uint32 pixel, const SDL_PixelFormatDetails *format, const SDL_Pa
}
if (SDL_ISPIXELFORMAT_INDEXED(format->format)) {
if (palette && pixel < (unsigned)palette->ncolors) {
*r = palette->colors[pixel].r;
*g = palette->colors[pixel].g;
*b = palette->colors[pixel].b;
if (palette && pixelvalue < (unsigned)palette->ncolors) {
*r = palette->colors[pixelvalue].r;
*g = palette->colors[pixelvalue].g;
*b = palette->colors[pixelvalue].b;
} else {
*r = *g = *b = 0;
}
@@ -1306,24 +1369,24 @@ void SDL_GetRGB(Uint32 pixel, const SDL_PixelFormatDetails *format, const SDL_Pa
if (SDL_ISPIXELFORMAT_10BIT(format->format)) {
unsigned v;
v = (pixel & format->Rmask) >> format->Rshift;
v = (pixelvalue & format->Rmask) >> format->Rshift;
*r = (Uint8)(v >> 2);
v = (pixel & format->Gmask) >> format->Gshift;
v = (pixelvalue & format->Gmask) >> format->Gshift;
*g = (Uint8)(v >> 2);
v = (pixel & format->Bmask) >> format->Bshift;
v = (pixelvalue & format->Bmask) >> format->Bshift;
*b = (Uint8)(v >> 2);
} else {
unsigned v;
v = (pixel & format->Rmask) >> format->Rshift;
v = (pixelvalue & format->Rmask) >> format->Rshift;
*r = SDL_expand_byte[format->Rbits][v];
v = (pixel & format->Gmask) >> format->Gshift;
v = (pixelvalue & format->Gmask) >> format->Gshift;
*g = SDL_expand_byte[format->Gbits][v];
v = (pixel & format->Bmask) >> format->Bshift;
v = (pixelvalue & format->Bmask) >> format->Bshift;
*b = SDL_expand_byte[format->Bbits][v];
}
}
void SDL_GetRGBA(Uint32 pixel, const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a)
void SDL_GetRGBA(Uint32 pixelvalue, const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a)
{
Uint8 unused;
@@ -1346,11 +1409,11 @@ void SDL_GetRGBA(Uint32 pixel, const SDL_PixelFormatDetails *format, const SDL_P
}
if (SDL_ISPIXELFORMAT_INDEXED(format->format)) {
if (palette && pixel < (unsigned)palette->ncolors) {
*r = palette->colors[pixel].r;
*g = palette->colors[pixel].g;
*b = palette->colors[pixel].b;
*a = palette->colors[pixel].a;
if (palette && pixelvalue < (unsigned)palette->ncolors) {
*r = palette->colors[pixelvalue].r;
*g = palette->colors[pixelvalue].g;
*b = palette->colors[pixelvalue].b;
*a = palette->colors[pixelvalue].a;
} else {
*r = *g = *b = *a = 0;
}
@@ -1359,45 +1422,52 @@ void SDL_GetRGBA(Uint32 pixel, const SDL_PixelFormatDetails *format, const SDL_P
if (SDL_ISPIXELFORMAT_10BIT(format->format)) {
unsigned v;
v = (pixel & format->Rmask) >> format->Rshift;
v = (pixelvalue & format->Rmask) >> format->Rshift;
*r = (Uint8)(v >> 2);
v = (pixel & format->Gmask) >> format->Gshift;
v = (pixelvalue & format->Gmask) >> format->Gshift;
*g = (Uint8)(v >> 2);
v = (pixel & format->Bmask) >> format->Bshift;
v = (pixelvalue & format->Bmask) >> format->Bshift;
*b = (Uint8)(v >> 2);
v = (pixel & format->Amask) >> format->Ashift;
v = (pixelvalue & format->Amask) >> format->Ashift;
*a = SDL_expand_byte[format->Abits][v];
} else {
unsigned v;
v = (pixel & format->Rmask) >> format->Rshift;
v = (pixelvalue & format->Rmask) >> format->Rshift;
*r = SDL_expand_byte[format->Rbits][v];
v = (pixel & format->Gmask) >> format->Gshift;
v = (pixelvalue & format->Gmask) >> format->Gshift;
*g = SDL_expand_byte[format->Gbits][v];
v = (pixel & format->Bmask) >> format->Bshift;
v = (pixelvalue & format->Bmask) >> format->Bshift;
*b = SDL_expand_byte[format->Bbits][v];
v = (pixel & format->Amask) >> format->Ashift;
v = (pixelvalue & format->Amask) >> format->Ashift;
*a = SDL_expand_byte[format->Abits][v];
}
}
bool SDL_IsSamePalette(const SDL_Palette *src, const SDL_Palette *dst)
{
if (src->ncolors <= dst->ncolors) {
// If an identical palette, no need to map
if (src == dst ||
(SDL_memcmp(src->colors, dst->colors,
src->ncolors * sizeof(SDL_Color)) == 0)) {
return true;
}
}
return false;
}
// Map from Palette to Palette
static Uint8 *Map1to1(const SDL_Palette *src, const SDL_Palette *dst, int *identical)
{
Uint8 *map;
int i;
if (identical) {
if (src->ncolors <= dst->ncolors) {
// If an identical palette, no need to map
if (src == dst ||
(SDL_memcmp(src->colors, dst->colors,
src->ncolors * sizeof(SDL_Color)) == 0)) {
*identical = 1;
return NULL;
}
}
*identical = 0;
if (SDL_IsSamePalette(src, dst)) {
*identical = 1;
return NULL;
}
*identical = 0;
map = (Uint8 *)SDL_calloc(256, sizeof(Uint8));
if (!map) {
return NULL;
@@ -1492,7 +1562,7 @@ bool SDL_MapSurface(SDL_Surface *src, SDL_Surface *dst)
map = &src->map;
#ifdef SDL_HAVE_RLE
if (src->internal_flags & SDL_INTERNAL_SURFACE_RLEACCEL) {
SDL_UnRLESurface(src, true);
SDL_UnRLESurface(src);
}
#endif
SDL_InvalidateMap(map);
+3 -3
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -48,9 +48,9 @@ extern void SDL_InvalidateMap(SDL_BlitMap *map);
extern bool SDL_MapSurface(SDL_Surface *src, SDL_Surface *dst);
// Miscellaneous functions
extern bool SDL_IsSamePalette(const SDL_Palette *src, const SDL_Palette *dst);
extern void SDL_DitherPalette(SDL_Palette *palette);
extern Uint8 SDL_FindColor(const SDL_Palette *pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
extern Uint8 SDL_LookupRGBAColor(SDL_HashTable *palette_map, Uint32 pixel, const SDL_Palette *pal);
extern Uint8 SDL_LookupRGBAColor(SDL_HashTable *palette_map, Uint32 pixelvalue, const SDL_Palette *pal);
extern void SDL_DetectPalette(const SDL_Palette *pal, bool *is_opaque, bool *has_alpha_channel);
extern SDL_Surface *SDL_DuplicatePixels(int width, int height, SDL_PixelFormat format, SDL_Colorspace colorspace, void *pixels, int pitch);
+10 -6
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -31,19 +31,23 @@ bool SDL_GetSpanEnclosingRect(int width, int height,
int span_y1, span_y2;
int rect_y1, rect_y2;
if (width < 1) {
CHECK_PARAM(width < 1) {
SDL_InvalidParamError("width");
return false;
} else if (height < 1) {
}
CHECK_PARAM(height < 1) {
SDL_InvalidParamError("height");
return false;
} else if (!rects) {
}
CHECK_PARAM(!rects) {
SDL_InvalidParamError("rects");
return false;
} else if (!span) {
}
CHECK_PARAM(!span) {
SDL_InvalidParamError("span");
return false;
} else if (numrects < 1) {
}
CHECK_PARAM(numrects < 1) {
SDL_InvalidParamError("numrects");
return false;
}
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+40 -31
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -38,18 +38,17 @@ bool SDL_HASINTERSECTION(const RECTTYPE *A, const RECTTYPE *B)
{
SCALARTYPE Amin, Amax, Bmin, Bmax;
if (!A) {
CHECK_PARAM(!A) {
SDL_InvalidParamError("A");
return false;
} else if (!B) {
}
CHECK_PARAM(!B) {
SDL_InvalidParamError("B");
return false;
} else if (SDL_RECT_CAN_OVERFLOW(A) ||
SDL_RECT_CAN_OVERFLOW(B)) {
}
CHECK_PARAM(SDL_RECT_CAN_OVERFLOW(A) || SDL_RECT_CAN_OVERFLOW(B)) {
SDL_SetError("Potential rect math overflow");
return false;
} else if (SDL_RECTEMPTY(A) || SDL_RECTEMPTY(B)) {
return false; // Special cases for empty rects
}
// Horizontal intersection
@@ -87,23 +86,21 @@ bool SDL_INTERSECTRECT(const RECTTYPE *A, const RECTTYPE *B, RECTTYPE *result)
{
SCALARTYPE Amin, Amax, Bmin, Bmax;
if (!A) {
CHECK_PARAM(!A) {
SDL_InvalidParamError("A");
return false;
} else if (!B) {
}
CHECK_PARAM(!B) {
SDL_InvalidParamError("B");
return false;
} else if (SDL_RECT_CAN_OVERFLOW(A) ||
SDL_RECT_CAN_OVERFLOW(B)) {
}
CHECK_PARAM(SDL_RECT_CAN_OVERFLOW(A) || SDL_RECT_CAN_OVERFLOW(B)) {
SDL_SetError("Potential rect math overflow");
return false;
} else if (!result) {
}
CHECK_PARAM(!result) {
SDL_InvalidParamError("result");
return false;
} else if (SDL_RECTEMPTY(A) || SDL_RECTEMPTY(B)) { // Special cases for empty rects
result->w = 0;
result->h = 0;
return false;
}
// Horizontal intersection
@@ -141,16 +138,20 @@ bool SDL_UNIONRECT(const RECTTYPE *A, const RECTTYPE *B, RECTTYPE *result)
{
SCALARTYPE Amin, Amax, Bmin, Bmax;
if (!A) {
CHECK_PARAM(!A) {
return SDL_InvalidParamError("A");
} else if (!B) {
}
CHECK_PARAM(!B) {
return SDL_InvalidParamError("B");
} else if (SDL_RECT_CAN_OVERFLOW(A) ||
SDL_RECT_CAN_OVERFLOW(B)) {
}
CHECK_PARAM(SDL_RECT_CAN_OVERFLOW(A) || SDL_RECT_CAN_OVERFLOW(B)) {
return SDL_SetError("Potential rect math overflow");
} else if (!result) {
}
CHECK_PARAM(!result) {
return SDL_InvalidParamError("result");
} else if (SDL_RECTEMPTY(A)) { // Special cases for empty Rects
}
if (SDL_RECTEMPTY(A)) { // Special cases for empty Rects
if (SDL_RECTEMPTY(B)) { // A and B empty
SDL_zerop(result);
} else { // A empty, B not empty
@@ -201,10 +202,11 @@ bool SDL_ENCLOSEPOINTS(const POINTTYPE *points, int count, const RECTTYPE *clip,
SCALARTYPE x, y;
int i;
if (!points) {
CHECK_PARAM(!points) {
SDL_InvalidParamError("points");
return false;
} else if (count < 1) {
}
CHECK_PARAM(count < 1) {
SDL_InvalidParamError("count");
return false;
}
@@ -320,25 +322,32 @@ bool SDL_INTERSECTRECTANDLINE(const RECTTYPE *rect, SCALARTYPE *X1, SCALARTYPE *
SCALARTYPE recty2;
int outcode1, outcode2;
if (!rect) {
CHECK_PARAM(!rect) {
SDL_InvalidParamError("rect");
return false;
} else if (SDL_RECT_CAN_OVERFLOW(rect)) {
}
CHECK_PARAM(SDL_RECT_CAN_OVERFLOW(rect)) {
SDL_SetError("Potential rect math overflow");
return false;
} else if (!X1) {
}
CHECK_PARAM(!X1) {
SDL_InvalidParamError("X1");
return false;
} else if (!Y1) {
}
CHECK_PARAM(!Y1) {
SDL_InvalidParamError("Y1");
return false;
} else if (!X2) {
}
CHECK_PARAM(!X2) {
SDL_InvalidParamError("X2");
return false;
} else if (!Y2) {
}
CHECK_PARAM(!Y2) {
SDL_InvalidParamError("Y2");
return false;
} else if (SDL_RECTEMPTY(rect)) {
}
if (SDL_RECTEMPTY(rect)) {
return false; // Special case for empty rect
}
+605
View File
@@ -0,0 +1,605 @@
/*
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"
#include "SDL_surface_c.h"
#include "SDL_rotate.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->format == SDL_PIXELFORMAT_INDEX8) && colorKeyAvailable;
if (!is8bit &&
!(SDL_BITSPERPIXEL(src->format) == 32 && SDL_PIXELLAYOUT(src->format) == SDL_PACKEDLAYOUT_8888)) {
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;
}
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -19,13 +19,12 @@
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_vitagl_pvr_c_h_
#define SDL_vitagl_pvr_c_h_
#ifndef SDL_rotate_h_
#define SDL_rotate_h_
#include "SDL_vitavideo.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);
extern SDL_GLContext VITA_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
extern int VITA_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path);
extern SDL_FunctionPointer VITA_GL_GetProcAddress(SDL_VideoDevice *_this, const char *proc);
#endif // SDL_vitagl_pvr_c_h_
#endif // SDL_rotate_h_
+383 -6
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -21,10 +21,10 @@
#include "SDL_internal.h"
#include "SDL_stb_c.h"
#include "SDL_surface_c.h"
// We currently only support JPEG, but we could add other image formats if we wanted
#ifdef SDL_HAVE_STB
////////////////////////////////////////////////////////////////////////////
#define malloc SDL_malloc
#define realloc SDL_realloc
#define free SDL_free
@@ -48,19 +48,33 @@
#if defined(SDL_NEON_INTRINSICS)
#define STBI_NEON
#endif
#define STBI_ONLY_PNG
#define STBI_ONLY_JPEG
#define STBI_NO_GIF
#define STBI_NO_PNG
#define STBI_NO_HDR
#define STBI_NO_LINEAR
#define STBI_NO_ZLIB
#define STBI_NO_STDIO
#define STBI_ASSERT SDL_assert
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#undef memset
////////////////////////////////////////////////////////////////////////////
#define MZ_ASSERT(x) SDL_assert(x)
//#undef memcpy
//#define memcpy SDL_memcpy
//#undef memset
//#define memset SDL_memset
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
#define MINIZ_LITTLE_ENDIAN 1
#else
#define MINIZ_LITTLE_ENDIAN 0
#endif
#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0
#define MINIZ_SDL_NOUNUSED
#include "miniz.h"
#undef memset
#endif // SDL_HAVE_STB
#ifdef SDL_HAVE_STB
static bool SDL_ConvertPixels_MJPG_to_NV12(int width, int height, const void *src, int src_pitch, void *dst, int dst_pitch)
@@ -119,3 +133,366 @@ bool SDL_ConvertPixels_STB(int width, int height,
return SDL_SetError("SDL not built with STB image support");
#endif
}
#ifdef SDL_HAVE_STB
static int IMG_LoadSTB_IO_read(void *user, char *data, int size)
{
size_t amount = SDL_ReadIO((SDL_IOStream*)user, data, size);
return (int)amount;
}
static void IMG_LoadSTB_IO_skip(void *user, int n)
{
SDL_SeekIO((SDL_IOStream*)user, n, SDL_IO_SEEK_CUR);
}
static int IMG_LoadSTB_IO_eof(void *user)
{
SDL_IOStream *src = (SDL_IOStream*)user;
return SDL_GetIOStatus(src) == SDL_IO_STATUS_EOF;
}
static SDL_Surface *SDL_LoadSTB_IO(SDL_IOStream *src)
{
Sint64 start;
Uint8 magic[26];
int w, h, format;
stbi_uc *pixels;
stbi_io_callbacks rw_callbacks;
SDL_Surface *surface = NULL;
bool use_palette = false;
unsigned int palette_colors[256];
// src has already been validated
start = SDL_TellIO(src);
if (SDL_ReadIO(src, magic, sizeof(magic)) == sizeof(magic)) {
const Uint8 PNG_COLOR_INDEXED = 3;
if (magic[0] == 0x89 &&
magic[1] == 'P' &&
magic[2] == 'N' &&
magic[3] == 'G' &&
magic[12] == 'I' &&
magic[13] == 'H' &&
magic[14] == 'D' &&
magic[15] == 'R' &&
magic[25] == PNG_COLOR_INDEXED) {
use_palette = true;
}
}
SDL_SeekIO(src, start, SDL_IO_SEEK_SET);
/* Load the image data */
rw_callbacks.read = IMG_LoadSTB_IO_read;
rw_callbacks.skip = IMG_LoadSTB_IO_skip;
rw_callbacks.eof = IMG_LoadSTB_IO_eof;
w = h = format = 0; /* silence warning */
if (use_palette) {
/* Unused palette entries will be opaque white */
SDL_memset(palette_colors, 0xff, sizeof(palette_colors));
pixels = stbi_load_from_callbacks_with_palette(
&rw_callbacks,
src,
&w,
&h,
palette_colors,
SDL_arraysize(palette_colors)
);
} else {
pixels = stbi_load_from_callbacks(
&rw_callbacks,
src,
&w,
&h,
&format,
STBI_default
);
}
if (!pixels) {
SDL_SeekIO(src, start, SDL_IO_SEEK_SET);
return NULL;
}
if (use_palette) {
surface = SDL_CreateSurfaceFrom(
w,
h,
SDL_PIXELFORMAT_INDEX8,
pixels,
w
);
if (surface) {
bool has_colorkey = false;
int colorkey_index = -1;
bool has_alpha = false;
SDL_Palette *palette = SDL_CreateSurfacePalette(surface);
if (palette) {
int i;
Uint8 *palette_bytes = (Uint8 *)palette_colors;
for (i = 0; i < palette->ncolors; i++) {
palette->colors[i].r = *palette_bytes++;
palette->colors[i].g = *palette_bytes++;
palette->colors[i].b = *palette_bytes++;
palette->colors[i].a = *palette_bytes++;
if (palette->colors[i].a != SDL_ALPHA_OPAQUE) {
if (palette->colors[i].a == SDL_ALPHA_TRANSPARENT && !has_colorkey) {
has_colorkey = true;
colorkey_index = i;
} else {
/* Partial opacity or multiple colorkeys */
has_alpha = true;
}
}
}
}
if (has_alpha) {
SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
} else if (has_colorkey) {
SDL_SetSurfaceColorKey(surface, true, colorkey_index);
}
/* FIXME: This sucks. It'd be better to allocate the surface first, then
* write directly to the pixel buffer:
* https://github.com/nothings/stb/issues/58
* -flibit
*/
surface->flags &= ~SDL_SURFACE_PREALLOCATED;
}
} else if (format == STBI_grey || format == STBI_rgb || format == STBI_rgb_alpha) {
surface = SDL_CreateSurfaceFrom(
w,
h,
(format == STBI_rgb_alpha) ? SDL_PIXELFORMAT_RGBA32 :
(format == STBI_rgb) ? SDL_PIXELFORMAT_RGB24 :
SDL_PIXELFORMAT_INDEX8,
pixels,
w * format
);
if (surface) {
/* Set a grayscale palette for gray images */
if (surface->format == SDL_PIXELFORMAT_INDEX8) {
SDL_Palette *palette = SDL_CreateSurfacePalette(surface);
if (palette) {
int i;
for (i = 0; i < palette->ncolors; i++) {
palette->colors[i].r = (Uint8)i;
palette->colors[i].g = (Uint8)i;
palette->colors[i].b = (Uint8)i;
}
}
}
/* FIXME: This sucks. It'd be better to allocate the surface first, then
* write directly to the pixel buffer:
* https://github.com/nothings/stb/issues/58
* -flibit
*/
surface->flags &= ~SDL_SURFACE_PREALLOCATED;
}
} else if (format == STBI_grey_alpha) {
surface = SDL_CreateSurface(w, h, SDL_PIXELFORMAT_RGBA32);
if (surface) {
Uint8 *src_ptr = pixels;
Uint8 *dst = (Uint8 *)surface->pixels;
int skip = surface->pitch - (surface->w * 4);
int row, col;
for (row = 0; row < h; ++row) {
for (col = 0; col < w; ++col) {
Uint8 c = *src_ptr++;
Uint8 a = *src_ptr++;
*dst++ = c;
*dst++ = c;
*dst++ = c;
*dst++ = a;
}
dst += skip;
}
stbi_image_free(pixels);
}
} else {
SDL_SetError("Unknown image format: %d", format);
}
if (!surface) {
/* The error message should already be set */
stbi_image_free(pixels); /* calls SDL_free() */
SDL_SeekIO(src, start, SDL_IO_SEEK_SET);
}
return surface;
}
#endif // SDL_HAVE_STB
bool SDL_IsPNG(SDL_IOStream *src)
{
Sint64 start;
Uint8 magic[4];
bool is_PNG;
is_PNG = false;
start = SDL_TellIO(src);
if (start >= 0) {
if (SDL_ReadIO(src, magic, sizeof(magic)) == sizeof(magic)) {
if (magic[0] == 0x89 &&
magic[1] == 'P' &&
magic[2] == 'N' &&
magic[3] == 'G') {
is_PNG = true;
}
}
SDL_SeekIO(src, start, SDL_IO_SEEK_SET);
}
return is_PNG;
}
SDL_Surface *SDL_LoadPNG_IO(SDL_IOStream *src, bool closeio)
{
SDL_Surface *surface = NULL;
CHECK_PARAM(!src) {
SDL_InvalidParamError("src");
goto done;
}
if (!SDL_IsPNG(src)) {
SDL_SetError("File is not a PNG file");
goto done;
}
#ifdef SDL_HAVE_STB
surface = SDL_LoadSTB_IO(src);
#else
SDL_SetError("SDL not built with STB image support");
#endif // SDL_HAVE_STB
done:
if (src && closeio) {
SDL_CloseIO(src);
}
return surface;
}
SDL_Surface *SDL_LoadPNG(const char *file)
{
SDL_IOStream *stream = SDL_IOFromFile(file, "rb");
if (!stream) {
return NULL;
}
return SDL_LoadPNG_IO(stream, true);
}
bool SDL_SavePNG_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
{
bool retval = false;
Uint8 *plte = NULL;
Uint8 *trns = NULL;
bool free_surface = false;
// Make sure we have something to save
CHECK_PARAM(!SDL_SurfaceValid(surface)) {
SDL_InvalidParamError("surface");
goto done;
}
CHECK_PARAM(!dst) {
SDL_InvalidParamError("dst");
goto done;
}
#ifdef SDL_HAVE_STB
int plte_size = 0;
int trns_size = 0;
if (SDL_ISPIXELFORMAT_INDEXED(surface->format)) {
if (!surface->palette) {
SDL_SetError("Indexed surfaces must have a palette");
goto done;
}
if (surface->format != SDL_PIXELFORMAT_INDEX8) {
surface = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_INDEX8);
if (!surface) {
goto done;
}
free_surface = true;
}
plte_size = surface->palette->ncolors * 3;
trns_size = surface->palette->ncolors;
plte = (Uint8 *)SDL_malloc(plte_size);
trns = (Uint8 *)SDL_malloc(trns_size);
if (!plte || !trns) {
goto done;
}
SDL_Color *colors = surface->palette->colors;
for (int i = 0; i < surface->palette->ncolors; ++i) {
plte[i * 3 + 0] = colors[i].r;
plte[i * 3 + 1] = colors[i].g;
plte[i * 3 + 2] = colors[i].b;
trns[i] = colors[i].a;
}
} else {
if (surface->format != SDL_PIXELFORMAT_RGBA32) {
surface = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
if (!surface) {
goto done;
}
free_surface = true;
}
}
size_t size = 0;
void *png = tdefl_write_image_to_png_file_in_memory_ex(surface->pixels, surface->w, surface->h, SDL_BYTESPERPIXEL(surface->format), surface->pitch, &size, 6, MZ_FALSE, plte, plte_size, trns, trns_size);
if (png) {
if (SDL_WriteIO(dst, png, size)) {
retval = true;
}
mz_free(png); /* calls SDL_free() */
} else {
SDL_SetError("Failed to convert and save image");
}
#else
SDL_SetError("SDL not built with STB image support");
#endif
done:
if (free_surface) {
SDL_DestroySurface(surface);
}
SDL_free(plte);
SDL_free(trns);
if (dst && closeio) {
retval &= SDL_CloseIO(dst);
}
return retval;
}
bool SDL_SavePNG(SDL_Surface *surface, const char *file)
{
#ifdef SDL_HAVE_STB
// Make sure we have something to save
CHECK_PARAM(!SDL_SurfaceValid(surface)) {
return SDL_InvalidParamError("surface");
}
if (SDL_ISPIXELFORMAT_INDEXED(surface->format) && !surface->palette) {
return SDL_SetError("Indexed surfaces must have a palette");
}
SDL_IOStream *stream = SDL_IOFromFile(file, "wb");
if (!stream) {
return false;
}
return SDL_SavePNG_IO(surface, stream, true);
#else
return SDL_SetError("SDL not built with STB image support");
#endif
}
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+14 -10
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -33,10 +33,10 @@ bool SDL_StretchSurface(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *
SDL_Rect full_src;
SDL_Rect full_dst;
if (!src) {
CHECK_PARAM(!src) {
return SDL_InvalidParamError("src");
}
if (!dst) {
CHECK_PARAM(!dst) {
return SDL_InvalidParamError("dst");
}
@@ -80,14 +80,18 @@ bool SDL_StretchSurface(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *
return result;
}
if (scaleMode != SDL_SCALEMODE_NEAREST && scaleMode != SDL_SCALEMODE_LINEAR) {
switch (scaleMode) {
case SDL_SCALEMODE_NEAREST:
break;
case SDL_SCALEMODE_LINEAR:
break;
case SDL_SCALEMODE_PIXELART:
scaleMode = SDL_SCALEMODE_NEAREST;
break;
default:
return SDL_InvalidParamError("scaleMode");
}
if (scaleMode != SDL_SCALEMODE_NEAREST) {
scaleMode = SDL_SCALEMODE_LINEAR;
}
if (scaleMode == SDL_SCALEMODE_LINEAR) {
if (SDL_BYTESPERPIXEL(src->format) != 4 || src->format == SDL_PIXELFORMAT_ARGB2101010) {
return SDL_SetError("Wrong format");
@@ -284,7 +288,7 @@ typedef struct color_t
#if 0
static void printf_64(const char *str, void *var)
{
uint8_t *val = (uint8_t*) var;
uint8_t *val = (uint8_t *)var;
printf(" * %s: %02x %02x %02x %02x _ %02x %02x %02x %02x\n",
str, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]);
}
@@ -390,7 +394,7 @@ static bool scale_mat(const Uint32 *src, int src_w, int src_h, int src_pitch, Ui
#if 0
static void SDL_TARGETING("sse2") printf_128(const char *str, __m128i var)
{
uint16_t *val = (uint16_t*) &var;
uint16_t *val = (uint16_t *)&var;
printf(" * %s: %04x %04x %04x %04x _ %04x %04x %04x %04x\n",
str, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]);
}
File diff suppressed because it is too large Load Diff
+7 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -78,6 +78,9 @@ struct SDL_Surface
/** info for fast blit mapping to other surfaces */
SDL_BlitMap map;
/** Original pixels when RLE is enabled */
void *saved_pixels;
};
// Surface functions
@@ -89,5 +92,8 @@ extern float SDL_GetSurfaceSDRWhitePoint(SDL_Surface *surface, SDL_Colorspace co
extern float SDL_GetDefaultHDRHeadroom(SDL_Colorspace colorspace);
extern float SDL_GetSurfaceHDRHeadroom(SDL_Surface *surface, SDL_Colorspace colorspace);
extern SDL_Surface *SDL_GetSurfaceImage(SDL_Surface *surface, float display_scale);
extern SDL_Surface *SDL_ConvertSurfaceRect(SDL_Surface *surface, const SDL_Rect *rect, SDL_PixelFormat format);
extern bool SDL_IsBMP(SDL_IOStream *src);
extern bool SDL_IsPNG(SDL_IOStream *src);
#endif // SDL_surface_c_h_
+21 -7
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -60,7 +60,8 @@ struct SDL_Window
bool external_graphics_context;
bool fullscreen_exclusive; // The window is currently fullscreen exclusive
SDL_DisplayID last_fullscreen_exclusive_display; // The last fullscreen_exclusive display
SDL_DisplayID last_displayID;
SDL_DisplayID displayID;
SDL_DisplayID pending_displayID;
/* Stored position and size for the window in the non-fullscreen state,
* including when the window is maximized or tiled.
@@ -103,6 +104,7 @@ struct SDL_Window
bool restore_on_show; // Child was hidden recursively by the parent, restore when shown.
bool last_position_pending; // This should NOT be cleared by the backend, as it is used for fullscreen positioning.
bool last_size_pending; // This should be cleared by the backend if the new size cannot be applied.
bool update_fullscreen_on_display_changed;
bool constrain_popup;
bool is_destroying;
bool is_dropping; // drag/drop in progress, expecting SDL_SendDropComplete().
@@ -123,6 +125,9 @@ struct SDL_Window
SDL_HitTest hit_test;
void *hit_test_data;
SDL_ProgressState progress_state;
float progress_value;
SDL_PropertiesID props;
int num_renderers;
@@ -186,8 +191,7 @@ typedef enum
VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS = 0x04,
VIDEO_DEVICE_CAPS_FULLSCREEN_ONLY = 0x08,
VIDEO_DEVICE_CAPS_SENDS_DISPLAY_CHANGES = 0x10,
VIDEO_DEVICE_CAPS_DISABLE_MOUSE_WARP_ON_FULLSCREEN_TRANSITIONS = 0x20,
VIDEO_DEVICE_CAPS_SENDS_HDR_CHANGES = 0x40
VIDEO_DEVICE_CAPS_SENDS_HDR_CHANGES = 0x20
} DeviceCaps;
// Fullscreen operations
@@ -216,7 +220,7 @@ struct SDL_VideoDevice
/*
* Initialize the native video subsystem, filling in the list of
* displays for this driver, returning 0 or -1 if there's an error.
* displays for this driver, returning true (success) or false (error).
*/
bool (*VideoInit)(SDL_VideoDevice *_this);
@@ -306,8 +310,11 @@ struct SDL_VideoDevice
void (*OnWindowEnter)(SDL_VideoDevice *_this, SDL_Window *window);
bool (*UpdateWindowShape)(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *shape);
bool (*FlashWindow)(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
bool (*ApplyWindowProgress)(SDL_VideoDevice *_this, SDL_Window *window);
bool (*SetWindowFocusable)(SDL_VideoDevice *_this, SDL_Window *window, bool focusable);
bool (*SetWindowFillDocument)(SDL_VideoDevice *_this, SDL_Window *window, bool fill);
bool (*SyncWindow)(SDL_VideoDevice *_this, SDL_Window *window);
bool (*ReconfigureWindow)(SDL_VideoDevice *_this, SDL_Window *window, SDL_WindowFlags flags);
/* * * */
/*
@@ -331,7 +338,7 @@ struct SDL_VideoDevice
*/
bool (*Vulkan_LoadLibrary)(SDL_VideoDevice *_this, const char *path);
void (*Vulkan_UnloadLibrary)(SDL_VideoDevice *_this);
char const* const* (*Vulkan_GetInstanceExtensions)(SDL_VideoDevice *_this, Uint32 *count);
char const * const *(*Vulkan_GetInstanceExtensions)(SDL_VideoDevice *_this, Uint32 *count);
bool (*Vulkan_CreateSurface)(SDL_VideoDevice *_this, SDL_Window *window, VkInstance instance, const struct VkAllocationCallbacks *allocator, VkSurfaceKHR *surface);
void (*Vulkan_DestroySurface)(SDL_VideoDevice *_this, VkInstance instance, VkSurfaceKHR surface, const struct VkAllocationCallbacks *allocator);
bool (*Vulkan_GetPresentationSupport)(SDL_VideoDevice *_this, VkInstance instance, VkPhysicalDevice physicalDevice, Uint32 queueFamilyIndex);
@@ -366,7 +373,6 @@ struct SDL_VideoDevice
void (*ShowScreenKeyboard)(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
void (*HideScreenKeyboard)(SDL_VideoDevice *_this, SDL_Window *window);
void (*SetTextInputProperties)(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
bool (*IsScreenKeyboardShown)(SDL_VideoDevice *_this, SDL_Window *window);
// Clipboard
const char **(*GetTextMimeTypes)(SDL_VideoDevice *_this, size_t *num_mime_types);
@@ -416,6 +422,8 @@ struct SDL_VideoDevice
bool setting_display_mode;
Uint32 device_caps;
SDL_SystemTheme system_theme;
bool screen_keyboard_shown;
bool is_quitting;
/* * * */
// Data used by the GL drivers
@@ -450,6 +458,7 @@ struct SDL_VideoDevice
int retained_backing;
int egl_platform;
int driver_loaded;
int HAS_GL_ARB_color_buffer_float;
char driver_path[256];
SDL_SharedObject *dll_handle;
} gl_config;
@@ -525,6 +534,7 @@ extern VideoBootStrap PSP_bootstrap;
extern VideoBootStrap VITA_bootstrap;
extern VideoBootStrap RISCOS_bootstrap;
extern VideoBootStrap N3DS_bootstrap;
extern VideoBootStrap NGAGE_bootstrap;
extern VideoBootStrap RPI_bootstrap;
extern VideoBootStrap KMSDRM_bootstrap;
extern VideoBootStrap DUMMY_bootstrap;
@@ -566,6 +576,7 @@ extern void SDL_SetWindowSafeAreaInsets(SDL_Window *window, int left, int right,
extern void SDL_GL_DeduceMaxSupportedESProfile(int *major, int *minor);
extern bool SDL_RecreateWindow(SDL_Window *window, SDL_WindowFlags flags);
extern bool SDL_ReconfigureWindow(SDL_Window *window, SDL_WindowFlags flags);
extern bool SDL_HasWindows(void);
extern void SDL_RelativeToGlobalForWindow(SDL_Window *window, int rel_x, int rel_y, int *abs_x, int *abs_y);
extern void SDL_GlobalToRelativeForWindow(SDL_Window *window, int abs_x, int abs_y, int *rel_x, int *rel_y);
@@ -604,4 +615,7 @@ extern SDL_Capitalization SDL_GetTextInputCapitalization(SDL_PropertiesID props)
extern bool SDL_GetTextInputAutocorrect(SDL_PropertiesID props);
extern bool SDL_GetTextInputMultiline(SDL_PropertiesID props);
extern void SDL_SendScreenKeyboardShown(void);
extern void SDL_SendScreenKeyboardHidden(void);
#endif // SDL_sysvideo_h_
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+5 -11
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -20,6 +20,8 @@
*/
#include "SDL_internal.h"
#include "SDL_video_unsupported.h"
#ifndef SDL_VIDEO_DRIVER_WINDOWS
#if defined(SDL_PLATFORM_WINDOWS)
@@ -42,7 +44,6 @@ void SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata)
#endif // defined(SDL_PLATFORM_WINDOWS)
SDL_DECLSPEC bool SDLCALL SDL_GetDXGIOutputInfo(SDL_DisplayID displayID, int *adapterIndex, int *outputIndex);
bool SDL_GetDXGIOutputInfo(SDL_DisplayID displayID, int *adapterIndex, int *outputIndex)
{
(void)displayID;
@@ -51,7 +52,6 @@ bool SDL_GetDXGIOutputInfo(SDL_DisplayID displayID, int *adapterIndex, int *outp
return SDL_Unsupported();
}
SDL_DECLSPEC int SDLCALL SDL_GetDirect3D9AdapterIndex(SDL_DisplayID displayID);
int SDL_GetDirect3D9AdapterIndex(SDL_DisplayID displayID)
{
(void)displayID;
@@ -61,7 +61,6 @@ int SDL_GetDirect3D9AdapterIndex(SDL_DisplayID displayID)
#elif defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
SDL_DECLSPEC int SDLCALL SDL_GetDirect3D9AdapterIndex(SDL_DisplayID displayID);
int SDL_GetDirect3D9AdapterIndex(SDL_DisplayID displayID)
{
(void)displayID;
@@ -73,8 +72,7 @@ int SDL_GetDirect3D9AdapterIndex(SDL_DisplayID displayID)
#ifndef SDL_PLATFORM_GDK
SDL_DECLSPEC bool SDLCALL SDL_GetGDKTaskQueue(void *outTaskQueue);
bool SDL_GetGDKTaskQueue(void *outTaskQueue)
bool SDL_GetGDKTaskQueue(XTaskQueueHandle *outTaskQueue)
{
(void)outTaskQueue;
return SDL_Unsupported();
@@ -82,9 +80,8 @@ bool SDL_GetGDKTaskQueue(void *outTaskQueue)
#endif
#ifndef SDL_VIDEO_DRIVER_UIKIT
#if !defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS) || defined(SDL_PLATFORM_VISIONOS)
SDL_DECLSPEC void SDLCALL SDL_OnApplicationDidChangeStatusBarOrientation(void);
void SDL_OnApplicationDidChangeStatusBarOrientation(void)
{
SDL_Unsupported();
@@ -94,8 +91,6 @@ void SDL_OnApplicationDidChangeStatusBarOrientation(void)
#ifndef SDL_VIDEO_DRIVER_UIKIT
typedef void (SDLCALL *SDL_iOSAnimationCallback)(void *userdata);
SDL_DECLSPEC bool SDLCALL SDL_SetiOSAnimationCallback(SDL_Window *window, int interval, SDL_iOSAnimationCallback callback, void *callbackParam);
bool SDL_SetiOSAnimationCallback(SDL_Window *window, int interval, SDL_iOSAnimationCallback callback, void *callbackParam)
{
(void)window;
@@ -105,7 +100,6 @@ bool SDL_SetiOSAnimationCallback(SDL_Window *window, int interval, SDL_iOSAnimat
return SDL_Unsupported();
}
SDL_DECLSPEC void SDLCALL SDL_SetiOSEventPump(bool enabled);
void SDL_SetiOSEventPump(bool enabled)
{
(void)enabled;
@@ -0,0 +1,61 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2026 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.
*/
#if !defined(SDL_VIDEO_DRIVER_WINDOWS)
#if defined(SDL_PLATFORM_WINDOWS)
extern SDL_DECLSPEC bool SDLCALL SDL_RegisterApp(const char *name, Uint32 style, void *hInst);
extern SDL_DECLSPEC void SDLCALL SDL_UnregisterApp(void);
extern SDL_DECLSPEC void SDLCALL SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata);
#endif /* SDL_PLATFORM_WINDOWS */
extern SDL_DECLSPEC bool SDLCALL SDL_GetDXGIOutputInfo(SDL_DisplayID displayID, int *adapterIndex, int *outputIndex);
extern SDL_DECLSPEC int SDLCALL SDL_GetDirect3D9AdapterIndex(SDL_DisplayID displayID);
#elif defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
extern SDL_DECLSPEC int SDLCALL SDL_GetDirect3D9AdapterIndex(SDL_DisplayID displayID);
#endif /* !SDL_VIDEO_DRIVER_WINDOWS */
#if !defined(SDL_PLATFORM_GDK)
typedef struct XTaskQueueHandle XTaskQueueHandle;
extern SDL_DECLSPEC bool SDLCALL SDL_GetGDKTaskQueue(XTaskQueueHandle *outTaskQueue);
#endif /* !SDL_PLATFORM_GDK */
#if !defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS) || defined(SDL_PLATFORM_VISIONOS)
extern SDL_DECLSPEC void SDLCALL SDL_OnApplicationDidChangeStatusBarOrientation(void);
#endif
#if !defined(SDL_VIDEO_DRIVER_UIKIT)
typedef void (SDLCALL *SDL_iOSAnimationCallback)(void *userdata);
extern SDL_DECLSPEC bool SDLCALL SDL_SetiOSAnimationCallback(SDL_Window *window, int interval, SDL_iOSAnimationCallback callback, void *callbackParam);
extern SDL_DECLSPEC void SDLCALL SDL_SetiOSEventPump(bool enabled);
#endif
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+17 -26
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -595,29 +595,26 @@ bool SDL_ConvertPixels_YUV_to_RGB(int width, int height,
const Uint8 *v = NULL;
Uint32 y_stride = 0;
Uint32 uv_stride = 0;
YCbCrType yuv_type = YCBCR_601_LIMITED;
if (!GetYUVPlanes(width, height, src_format, src, src_pitch, &y, &u, &v, &y_stride, &uv_stride)) {
return false;
}
if (SDL_COLORSPACEPRIMARIES(src_colorspace) == SDL_COLORSPACEPRIMARIES(dst_colorspace)) {
YCbCrType yuv_type = YCBCR_601_LIMITED;
if (!GetYUVConversionType(src_colorspace, &yuv_type)) {
return false;
}
if (!GetYUVConversionType(src_colorspace, &yuv_type)) {
return false;
}
if (yuv_rgb_sse(src_format, dst_format, width, height, y, u, v, y_stride, uv_stride, (Uint8 *)dst, dst_pitch, yuv_type)) {
return true;
}
if (yuv_rgb_sse(src_format, dst_format, width, height, y, u, v, y_stride, uv_stride, (Uint8 *)dst, dst_pitch, yuv_type)) {
return true;
}
if (yuv_rgb_lsx(src_format, dst_format, width, height, y, u, v, y_stride, uv_stride, (Uint8 *)dst, dst_pitch, yuv_type)) {
return true;
}
if (yuv_rgb_lsx(src_format, dst_format, width, height, y, u, v, y_stride, uv_stride, (Uint8 *)dst, dst_pitch, yuv_type)) {
return true;
}
if (yuv_rgb_std(src_format, dst_format, width, height, y, u, v, y_stride, uv_stride, (Uint8 *)dst, dst_pitch, yuv_type)) {
return true;
}
if (yuv_rgb_std(src_format, dst_format, width, height, y, u, v, y_stride, uv_stride, (Uint8 *)dst, dst_pitch, yuv_type)) {
return true;
}
// No fast path for the RGB format, instead convert using an intermediate buffer
@@ -1158,14 +1155,12 @@ bool SDL_ConvertPixels_RGB_to_YUV(int width, int height,
#endif
// ARGB8888 to FOURCC
if ((src_format == SDL_PIXELFORMAT_ARGB8888 || src_format == SDL_PIXELFORMAT_XRGB8888) &&
SDL_COLORSPACEPRIMARIES(src_colorspace) == SDL_COLORSPACEPRIMARIES(dst_colorspace)) {
if (src_format == SDL_PIXELFORMAT_ARGB8888 || src_format == SDL_PIXELFORMAT_XRGB8888) {
return SDL_ConvertPixels_XRGB8888_to_YUV(width, height, src, src_pitch, dst_format, dst, dst_pitch, yuv_type);
}
if (dst_format == SDL_PIXELFORMAT_P010) {
if (src_format == SDL_PIXELFORMAT_XBGR2101010 &&
SDL_COLORSPACEPRIMARIES(src_colorspace) == SDL_COLORSPACEPRIMARIES(dst_colorspace)) {
if (src_format == SDL_PIXELFORMAT_XBGR2101010) {
return SDL_ConvertPixels_XBGR2101010_to_P010(width, height, src, src_pitch, dst_format, dst, dst_pitch, yuv_type);
}
@@ -1562,9 +1557,7 @@ static bool SDL_ConvertPixels_PackUVPlanes_to_NV_std(int width, int height, cons
dstUV += dstUVPitchLeft;
}
if (tmp) {
SDL_free(tmp);
}
SDL_free(tmp);
return true;
}
@@ -1616,9 +1609,7 @@ static bool SDL_ConvertPixels_SplitNV_to_UVPlanes_std(int width, int height, con
dst2 += dstUVPitchLeft;
}
if (tmp) {
SDL_free(tmp);
}
SDL_free(tmp);
return true;
}
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -50,10 +50,7 @@ static void android_egl_context_restore(SDL_Window *window)
}
data->backup_done = false;
if (data->has_swap_interval) {
SDL_GL_SetSwapInterval(data->swap_interval);
}
SDL_GL_SetSwapInterval(data->swap_interval);
}
}
@@ -156,11 +153,6 @@ static void Android_OnResume(void)
}
#endif
// Make sure SW Keyboard is restored when an app becomes foreground
if (Android_Window) {
Android_RestoreScreenKeyboardOnResume(SDL_GetVideoDevice(), Android_Window);
}
SDL_OnApplicationDidEnterForeground();
}
@@ -248,6 +240,12 @@ void Android_PumpEvents(Sint64 timeoutNS)
bool Android_WaitActiveAndLockActivity(void)
{
/* Make sure we have pumped all events so that Android_Paused state is correct */
SDL_AndroidLifecycleEvent event;
while (!Android_Destroyed && Android_WaitLifecycleEvent(&event, 0)) {
Android_HandleLifecycleEvent(event);
}
while (Android_Paused && !Android_Destroyed) {
Android_PumpEvents(-1);
}
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -94,7 +94,7 @@ static SDL_Scancode Android_Keycodes[] = {
SDL_SCANCODE_DOWN, // AKEYCODE_DPAD_DOWN
SDL_SCANCODE_LEFT, // AKEYCODE_DPAD_LEFT
SDL_SCANCODE_RIGHT, // AKEYCODE_DPAD_RIGHT
SDL_SCANCODE_SELECT, // AKEYCODE_DPAD_CENTER
SDL_SCANCODE_RETURN, // AKEYCODE_DPAD_CENTER
SDL_SCANCODE_VOLUMEUP, // AKEYCODE_VOLUME_UP
SDL_SCANCODE_VOLUMEDOWN, // AKEYCODE_VOLUME_DOWN
SDL_SCANCODE_POWER, // AKEYCODE_POWER
@@ -238,7 +238,7 @@ static SDL_Scancode Android_Keycodes[] = {
SDL_SCANCODE_UNKNOWN, // AKEYCODE_VOLUME_MUTE
SDL_SCANCODE_UNKNOWN, // AKEYCODE_INFO
SDL_SCANCODE_CHANNEL_INCREMENT, // AKEYCODE_CHANNEL_UP
SDL_SCANCODE_CHANNEL_INCREMENT, // AKEYCODE_CHANNEL_DOWN
SDL_SCANCODE_CHANNEL_DECREMENT, // AKEYCODE_CHANNEL_DOWN
SDL_SCANCODE_UNKNOWN, // AKEYCODE_ZOOM_IN
SDL_SCANCODE_UNKNOWN, // AKEYCODE_ZOOM_OUT
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV
@@ -353,8 +353,6 @@ static SDL_Scancode Android_Keycodes[] = {
SDL_SCANCODE_PASTE, // AKEYCODE_PASTE
};
static bool SDL_screen_keyboard_shown;
static SDL_Scancode TranslateKeycode(int keycode)
{
SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
@@ -444,25 +442,18 @@ void Android_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_
}
}
Android_JNI_ShowScreenKeyboard(input_type, &window->text_input_rect);
SDL_screen_keyboard_shown = true;
}
void Android_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
{
Android_JNI_HideScreenKeyboard();
SDL_screen_keyboard_shown = false;
}
void Android_RestoreScreenKeyboardOnResume(SDL_VideoDevice *_this, SDL_Window *window)
void Android_RestoreScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
{
if (SDL_screen_keyboard_shown) {
if (_this->screen_keyboard_shown) {
Android_ShowScreenKeyboard(_this, window, window->text_input_props);
}
}
bool Android_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window)
{
return Android_JNI_IsScreenKeyboardShown();
}
#endif // SDL_VIDEO_DRIVER_ANDROID
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -28,5 +28,4 @@ extern void Android_OnKeyUp(int keycode);
extern bool Android_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
extern void Android_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
extern void Android_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
extern void Android_RestoreScreenKeyboardOnResume(SDL_VideoDevice *_this, SDL_Window *window);
extern bool Android_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);
extern void Android_RestoreScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+17 -11
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -31,9 +31,10 @@
#define ACTION_CANCEL 3
#define ACTION_POINTER_DOWN 5
#define ACTION_POINTER_UP 6
#define ACTION_HOVER_ENTER 9
#define ACTION_HOVER_EXIT 10
void Android_OnPen(SDL_Window *window, int pen_id_in, int button, int action, float x, float y, float p)
void Android_OnPen(SDL_Window *window, int pen_id_in, SDL_PenDeviceType device_type, int button, int action, float x, float y, float p)
{
if (!window) {
return;
@@ -50,7 +51,8 @@ void Android_OnPen(SDL_Window *window, int pen_id_in, int button, int action, fl
peninfo.capabilities = SDL_PEN_CAPABILITY_PRESSURE | SDL_PEN_CAPABILITY_ERASER;
peninfo.num_buttons = 2;
peninfo.subtype = SDL_PEN_TYPE_PEN;
pen = SDL_AddPenDevice(0, NULL, &peninfo, (void *) (size_t) pen_id_in);
peninfo.device_type = device_type;
pen = SDL_AddPenDevice(0, NULL, window, &peninfo, (void *) (size_t) pen_id_in, true);
if (!pen) {
SDL_Log("error: can't add a pen device %d", pen_id_in);
return;
@@ -64,20 +66,24 @@ void Android_OnPen(SDL_Window *window, int pen_id_in, int button, int action, fl
SDL_PenInputFlags current = SDL_GetPenStatus(pen, NULL, 0);
int diff = current ^ button;
if (diff != 0) {
// Android only exposes BUTTON_STYLUS_PRIMARY and BUTTON_STYLUS_SECONDARY
if (diff & SDL_PEN_INPUT_BUTTON_1)
SDL_SendPenButton(0, pen, window, 1, (button & SDL_PEN_INPUT_BUTTON_1) != 0);
if (diff & SDL_PEN_INPUT_BUTTON_2)
SDL_SendPenButton(0, pen, window, 2, (button & SDL_PEN_INPUT_BUTTON_2) != 0);
for (Uint8 i = 1; i <= 5; ++i) {
Uint8 mask = (1 << i);
if (diff & mask) {
SDL_SendPenButton(0, pen, window, i, (button & mask) != 0);
}
}
}
// button contains DOWN/ERASER_TIP on DOWN/UP regardless of pressed state, use action to distinguish
// we don't compare tip flags above because MotionEvent.getButtonState doesn't return stylus tip/eraser state.
switch (action) {
case ACTION_HOVER_ENTER:
SDL_SendPenProximity(0, pen, window, true, true);
break;
case ACTION_CANCEL:
case ACTION_HOVER_EXIT:
SDL_RemovePenDevice(0, pen);
case ACTION_HOVER_EXIT: // strictly speaking, this can mean both "proximity out" and "left the View" but close enough.
SDL_SendPenProximity(0, pen, window, false, false);
break;
case ACTION_DOWN:
+2 -2
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -22,4 +22,4 @@
#include "SDL_androidvideo.h"
extern void Android_OnPen(SDL_Window *window, int pen_id_in, int button, int action, float x, float y, float p);
extern void Android_OnPen(SDL_Window *window, int pen_id_in, SDL_PenDeviceType device_type, int button, int action, float x, float y, float p);
+22 -7
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -47,6 +47,25 @@ void Android_QuitTouch(void)
{
}
SDL_TouchID Android_ConvertJavaTouchID(int touchID)
{
SDL_TouchID retval = touchID;
if (touchID < 0) {
// Touch ID -1 appears when using Android emulator, eg:
// adb shell input mouse tap 100 100
// adb shell input touchscreen tap 100 100
//
// Prevent the values -1 and -2, since they're used in SDL internal for synthetic events:
retval -= 2;
} else {
// Touch ID 0 is invalid
retval += 1;
}
return retval;
}
void Android_OnTouch(SDL_Window *window, int touch_device_id_in, int pointer_finger_id_in, int action, float x, float y, float p)
{
SDL_TouchID touchDeviceId = 0;
@@ -56,17 +75,13 @@ void Android_OnTouch(SDL_Window *window, int touch_device_id_in, int pointer_fin
return;
}
/* Touch device -1 appears when using Android emulator, eg:
* adb shell input mouse tap 100 100
* adb shell input touchscreen tap 100 100
*/
touchDeviceId = (SDL_TouchID)(touch_device_id_in + 2);
touchDeviceId = Android_ConvertJavaTouchID(touch_device_id_in);
// Finger ID should be greater than 0
fingerId = (SDL_FingerID)(pointer_finger_id_in + 1);
if (SDL_AddTouch(touchDeviceId, SDL_TOUCH_DEVICE_DIRECT, "") < 0) {
SDL_Log("error: can't add touch %s, %d", __FILE__, __LINE__);
return;
}
switch (action) {
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -25,3 +25,4 @@
extern void Android_InitTouch(void);
extern void Android_QuitTouch(void);
extern void Android_OnTouch(SDL_Window *window, int touch_device_id_in, int pointer_finger_id_in, int action, float x, float y, float p);
extern SDL_TouchID Android_ConvertJavaTouchID(int touchID);
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -142,7 +142,6 @@ static SDL_VideoDevice *Android_CreateDevice(void)
device->HasScreenKeyboardSupport = Android_HasScreenKeyboardSupport;
device->ShowScreenKeyboard = Android_ShowScreenKeyboard;
device->HideScreenKeyboard = Android_HideScreenKeyboard;
device->IsScreenKeyboardShown = Android_IsScreenKeyboardShown;
// Clipboard
device->SetClipboardText = Android_SetClipboardText;
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -91,7 +91,7 @@ bool Android_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path)
SDL_SetError("Installed Vulkan doesn't implement the " VK_KHR_SURFACE_EXTENSION_NAME " extension");
goto fail;
} else if (!hasAndroidSurfaceExtension) {
SDL_SetError("Installed Vulkan doesn't implement the " VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "extension");
SDL_SetError("Installed Vulkan doesn't implement the " VK_KHR_ANDROID_SURFACE_EXTENSION_NAME " extension");
goto fail;
}
return true;
@@ -110,8 +110,7 @@ void Android_Vulkan_UnloadLibrary(SDL_VideoDevice *_this)
}
}
char const* const* Android_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
Uint32 *count)
char const * const *Android_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count)
{
static const char *const extensionsForAndroid[] = {
VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
@@ -146,6 +145,7 @@ bool Android_Vulkan_CreateSurface(SDL_VideoDevice *_this,
return SDL_SetError(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
" extension is not enabled in the Vulkan instance.");
}
SDL_zero(createInfo);
createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = NULL;
@@ -153,7 +153,11 @@ bool Android_Vulkan_CreateSurface(SDL_VideoDevice *_this,
createInfo.window = windowData->native_window;
result = vkCreateAndroidSurfaceKHR(instance, &createInfo, allocator, surface);
if (result != VK_SUCCESS) {
return SDL_SetError("vkCreateAndroidSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result));
if (result == VK_ERROR_NATIVE_WINDOW_IN_USE_KHR) {
return SDL_SetError("vkCreateAndroidSurfaceKHR failed: %s, was the window created with SDL_WINDOW_VULKAN?", SDL_Vulkan_GetResultString(result));
} else {
return SDL_SetError("vkCreateAndroidSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result));
}
}
return true;
}
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -36,7 +36,7 @@
extern bool Android_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
extern void Android_Vulkan_UnloadLibrary(SDL_VideoDevice *_this);
extern char const* const* Android_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count);
extern char const * const *Android_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count);
extern bool Android_Vulkan_CreateSurface(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -126,7 +126,7 @@ SDL_FullscreenResult Android_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Win
/* Ensure our size matches reality after we've executed the window style change.
*
* It is possible that we've set width and height to the full-size display, but on
* Samsung DeX or Chromebooks or other windowed Android environemtns, our window may
* Samsung DeX or Chromebooks or other windowed Android environments, our window may
* still not be the full display size.
*/
if (!SDL_IsDeXMode() && !SDL_IsChromebook()) {
@@ -165,7 +165,7 @@ endfunction:
void Android_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
Android_JNI_MinizeWindow();
Android_JNI_MinimizeWindow();
}
void Android_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, bool resizable)
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+7 -13
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -105,10 +105,11 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
+ (void)registerUserDefaults
{
BOOL momentumScrollSupported = (BOOL)SDL_GetHintBoolean(SDL_HINT_MAC_SCROLL_MOMENTUM, false);
BOOL pressAndHoldEnabled = (BOOL)SDL_GetHintBoolean(SDL_HINT_MAC_PRESS_AND_HOLD, true);
NSDictionary *appDefaults = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithBool:momentumScrollSupported], @"AppleMomentumScrollSupported",
[NSNumber numberWithBool:YES], @"ApplePressAndHoldEnabled",
[NSNumber numberWithBool:pressAndHoldEnabled], @"ApplePressAndHoldEnabled",
[NSNumber numberWithBool:YES], @"ApplePersistenceIgnoreState",
nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
@@ -261,11 +262,10 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
return;
}
// Restore any fullscreen window
device = SDL_GetVideoDevice();
if (device && device->windows) {
SDL_Window *window = device->windows;
int i;
for (i = 0; i < device->num_displays; ++i) {
for (int i = 0; i < device->num_displays; ++i) {
SDL_Window *fullscreen_window = device->displays[i]->fullscreen_window;
if (fullscreen_window) {
if (fullscreen_window->flags & SDL_WINDOW_MINIMIZED) {
@@ -274,12 +274,6 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
return;
}
}
if (window->flags & SDL_WINDOW_MINIMIZED) {
SDL_RestoreWindow(window);
} else {
SDL_RaiseWindow(window);
}
}
}
@@ -370,9 +364,9 @@ static void Cocoa_DispatchEvent(NSEvent *theEvent)
- (IBAction)menu:(id)sender
{
SDL_TrayEntry *entry = [[sender representedObject] pointerValue];
SDL_TrayEntry *entry = [[sender representedObject] pointerValue];
SDL_ClickTrayEntry(entry);
SDL_ClickTrayEntry(entry);
}
@end
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -327,7 +327,7 @@ static void UpdateKeymap(SDL_CocoaVideoData *data, bool send_event)
UInt32 keyboard_type = LMGetKbdType();
SDL_Keymap *keymap = SDL_CreateKeymap();
SDL_Keymap *keymap = SDL_CreateKeymap(true);
for (int m = 0; m < SDL_arraysize(mods); ++m) {
for (int i = 0; i < SDL_arraysize(darwin_scancode_table); i++) {
OSStatus err;
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -90,7 +90,9 @@ static bool SDLCALL SDL_MetalViewEventWatch(void *userdata, SDL_Event *event)
self.layer.opaque = opaque;
SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_EARLY, SDL_MetalViewEventWatch, (__bridge void *)(self));
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_METAL_AUTO_RESIZE_DRAWABLE, true)) {
SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_EARLY, SDL_MetalViewEventWatch, (__bridge void *)(self));
}
[self updateDrawableSize];
}
+2 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -26,6 +26,7 @@
struct SDL_DisplayData
{
CGDirectDisplayID display;
SDL_Rect usable_bounds;
};
struct SDL_DisplayModeData
+38 -19
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -323,6 +323,24 @@ static void Cocoa_GetHDRProperties(CGDirectDisplayID displayID, SDL_HDROutputPro
}
}
static bool Cocoa_GetUsableBounds(CGDirectDisplayID displayID, SDL_Rect *rect)
{
NSScreen *screen = GetNSScreenForDisplayID(displayID);
if (screen == nil) {
return false;
}
SDL_VideoDevice *device = SDL_GetVideoDevice();
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)device->internal;
const NSRect frame = [screen visibleFrame];
rect->x = (int)frame.origin.x;
rect->y = (int)(data.mainDisplayHeight - frame.origin.y - frame.size.height);
rect->w = (int)frame.size.width;
rect->h = (int)frame.size.height;
return true;
}
bool Cocoa_AddDisplay(CGDirectDisplayID display, bool send_event)
{
@@ -331,7 +349,7 @@ bool Cocoa_AddDisplay(CGDirectDisplayID display, bool send_event)
return false;
}
SDL_DisplayData *displaydata = (SDL_DisplayData *)SDL_malloc(sizeof(*displaydata));
SDL_DisplayData *displaydata = (SDL_DisplayData *)SDL_calloc(1, sizeof(*displaydata));
if (!displaydata) {
CGDisplayModeRelease(moderef);
return false;
@@ -359,6 +377,8 @@ bool Cocoa_AddDisplay(CGDirectDisplayID display, bool send_event)
Cocoa_GetHDRProperties(displaydata->display, &viddisplay.HDR);
Cocoa_GetUsableBounds(displaydata->display, &displaydata->usable_bounds);
viddisplay.desktop_mode = mode;
viddisplay.internal = displaydata;
const bool retval = SDL_AddVideoDisplay(&viddisplay, send_event);
@@ -476,14 +496,20 @@ static void Cocoa_DisplayReconfigurationCallback(CGDirectDisplayID displayid, CG
if (flags & kCGDisplayDesktopShapeChangedFlag) {
SDL_UpdateDesktopBounds();
}
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal;
data.mainDisplayHeight = CGDisplayPixelsHigh(kCGDirectMainDisplay);
}
void Cocoa_InitModes(SDL_VideoDevice *_this)
{
@autoreleasepool {
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->internal;
CGDisplayErr result;
CGDisplayCount numDisplays = 0;
data.mainDisplayHeight = CGDisplayPixelsHigh(kCGDirectMainDisplay);
result = CGGetOnlineDisplayList(0, NULL, &numDisplays);
if (result != kCGErrorSuccess) {
CG_SetError("CGGetOnlineDisplayList()", result);
@@ -538,6 +564,13 @@ void Cocoa_UpdateDisplays(SDL_VideoDevice *_this)
Cocoa_GetHDRProperties(displaydata->display, &HDR);
SDL_SetDisplayHDRProperties(display, &HDR);
SDL_Rect rect;
if (Cocoa_GetUsableBounds(displaydata->display, &rect) &&
SDL_memcmp(&displaydata->usable_bounds, &rect, sizeof(rect)) != 0) {
SDL_memcpy(&displaydata->usable_bounds, &rect, sizeof(rect));
SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED, 0, 0);
}
}
}
@@ -556,24 +589,10 @@ bool Cocoa_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, S
bool Cocoa_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect)
{
@autoreleasepool {
SDL_DisplayData *displaydata = (SDL_DisplayData *)display->internal;
NSScreen *screen = GetNSScreenForDisplayID(displaydata->display);
SDL_DisplayData *displaydata = (SDL_DisplayData *)display->internal;
if (screen == nil) {
return SDL_SetError("Couldn't get NSScreen for display");
}
{
const NSRect frame = [screen visibleFrame];
rect->x = (int)frame.origin.x;
rect->y = (int)(CGDisplayPixelsHigh(kCGDirectMainDisplay) - frame.origin.y - frame.size.height);
rect->w = (int)frame.size.width;
rect->h = (int)frame.size.height;
}
return true;
}
SDL_memcpy(rect, &displaydata->usable_bounds, sizeof(*rect));
return true;
}
bool Cocoa_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display)
+14 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -32,6 +32,19 @@ extern void Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event);
extern void Cocoa_HandleMouseWarp(CGFloat x, CGFloat y);
extern void Cocoa_QuitMouse(SDL_VideoDevice *_this);
struct SDL_CursorData
{
NSTimer *frameTimer;
int current_frame;
int num_cursors;
struct
{
void *cursor;
Uint32 duration;
} frames[];
};
typedef struct
{
// Whether we've seen a cursor warp since the last move event.
+110 -43
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -32,7 +32,7 @@
#endif
#ifdef DEBUG_COCOAMOUSE
#define DLog(fmt, ...) printf("%s: " fmt "\n", __func__, ##__VA_ARGS__)
#define DLog(fmt, ...) printf("%s: " fmt "\n", SDL_FUNCTION, ##__VA_ARGS__)
#else
#define DLog(...) \
do { \
@@ -44,19 +44,20 @@
{
static NSCursor *invisibleCursor = NULL;
if (!invisibleCursor) {
// RAW 16x16 transparent GIF
static unsigned char cursorBytes[] = {
0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x10, 0x00, 0x10, 0x00, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xF9, 0x04,
0x01, 0x00, 0x00, 0x01, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x10,
0x00, 0x10, 0x00, 0x00, 0x02, 0x0E, 0x8C, 0x8F, 0xA9, 0xCB, 0xED,
0x0F, 0xA3, 0x9C, 0xB4, 0xDA, 0x8B, 0xB3, 0x3E, 0x05, 0x00, 0x3B
};
const int size = 32;
NSImage *cursorImage = [[NSImage alloc] initWithSize:NSMakeSize(size, size)];
NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:size
pixelsHigh:size
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:(size * 4)
bitsPerPixel:32];
[cursorImage addRepresentation:imgrep];
NSData *cursorData = [NSData dataWithBytesNoCopy:&cursorBytes[0]
length:sizeof(cursorBytes)
freeWhenDone:NO];
NSImage *cursorImage = [[NSImage alloc] initWithData:cursorData];
invisibleCursor = [[NSCursor alloc] initWithImage:cursorImage
hotSpot:NSZeroPoint];
}
@@ -65,27 +66,59 @@
}
@end
static SDL_Cursor *Cocoa_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
static SDL_Cursor *Cocoa_CreateAnimatedCursor(SDL_CursorFrameInfo *frames, int frame_count, int hot_x, int hot_y)
{
@autoreleasepool {
NSImage *nsimage;
NSCursor *nscursor = NULL;
SDL_Cursor *cursor = NULL;
nsimage = Cocoa_CreateImage(surface);
if (nsimage) {
nscursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSMakePoint(hot_x, hot_y)];
}
if (nscursor) {
cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
cursor->internal = (void *)CFBridgingRetain(nscursor);
cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
SDL_CursorData *cdata = SDL_calloc(1, sizeof(*cdata) + (sizeof(*cdata->frames) * frame_count));
if (!cdata) {
SDL_free(cursor);
return NULL;
}
}
return cursor;
cursor->internal = cdata;
for (int i = 0; i < frame_count; ++i) {
nsimage = Cocoa_CreateImage(frames[i].surface);
if (nsimage) {
nscursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSMakePoint(hot_x, hot_y)];
}
if (nscursor) {
++cdata->num_cursors;
cdata->frames[i].cursor = (void *)CFBridgingRetain(nscursor);
cdata->frames[i].duration = frames[i].duration;
} else {
for (int j = 0; j < i; ++j) {
CFBridgingRelease(cdata->frames[i].cursor);
}
SDL_free(cdata);
SDL_free(cursor);
cursor = NULL;
break;
}
}
return cursor;
}
}
return NULL;
}
static SDL_Cursor *Cocoa_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
{
SDL_CursorFrameInfo frame = {
surface, 0
};
return Cocoa_CreateAnimatedCursor(&frame, 1, hot_x, hot_y);
}
/* there are .pdf files of some of the cursors we need, installed by default on macOS, but not available through NSCursor.
@@ -203,8 +236,11 @@ static SDL_Cursor *Cocoa_CreateSystemCursor(SDL_SystemCursor id)
if (nscursor) {
cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
SDL_CursorData *cdata = SDL_calloc(1, sizeof(*cdata) + sizeof(*cdata->frames));
// We'll free it later, so retain it here
cursor->internal = (void *)CFBridgingRetain(nscursor);
cursor->internal = cdata;
cdata->frames[0].cursor = (void *)CFBridgingRetain(nscursor);
cdata->num_cursors = 1;
}
}
@@ -221,7 +257,14 @@ static SDL_Cursor *Cocoa_CreateDefaultCursor(void)
static void Cocoa_FreeCursor(SDL_Cursor *cursor)
{
@autoreleasepool {
CFBridgingRelease((void *)cursor->internal);
SDL_CursorData *cdata = cursor->internal;
if (cdata->frameTimer) {
[cdata->frameTimer invalidate];
}
for (int i = 0; i < cdata->num_cursors; ++i) {
CFBridgingRelease(cdata->frames[i].cursor);
}
SDL_free(cdata);
SDL_free(cursor);
}
}
@@ -231,6 +274,16 @@ static bool Cocoa_ShowCursor(SDL_Cursor *cursor)
@autoreleasepool {
SDL_VideoDevice *device = SDL_GetVideoDevice();
SDL_Window *window = (device ? device->windows : NULL);
if (cursor != NULL) {
SDL_CursorData *cdata = cursor->internal;
cdata->current_frame = 0;
if (cdata->frameTimer) {
[cdata->frameTimer invalidate];
cdata->frameTimer = nil;
}
}
for (; window != NULL; window = window->next) {
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal;
if (data) {
@@ -356,9 +409,11 @@ static SDL_MouseButtonFlags Cocoa_GetGlobalMouseState(float *x, float *y)
const NSUInteger cocoaButtons = [NSEvent pressedMouseButtons];
const NSPoint cocoaLocation = [NSEvent mouseLocation];
SDL_MouseButtonFlags result = 0;
SDL_VideoDevice *device = SDL_GetVideoDevice();
SDL_CocoaVideoData *videodata = (__bridge SDL_CocoaVideoData *)device->internal;
*x = cocoaLocation.x;
*y = (CGDisplayPixelsHigh(kCGDirectMainDisplay) - cocoaLocation.y);
*y = (videodata.mainDisplayHeight - cocoaLocation.y);
result |= (cocoaButtons & (1 << 0)) ? SDL_BUTTON_LMASK : 0;
result |= (cocoaButtons & (1 << 1)) ? SDL_BUTTON_RMASK : 0;
@@ -373,13 +428,14 @@ bool Cocoa_InitMouse(SDL_VideoDevice *_this)
{
NSPoint location;
SDL_Mouse *mouse = SDL_GetMouse();
SDL_MouseData *internal = (SDL_MouseData *)SDL_calloc(1, sizeof(SDL_MouseData));
if (internal == NULL) {
SDL_MouseData *data = (SDL_MouseData *)SDL_calloc(1, sizeof(SDL_MouseData));
if (data == NULL) {
return false;
}
mouse->internal = internal;
mouse->internal = data;
mouse->CreateCursor = Cocoa_CreateCursor;
mouse->CreateAnimatedCursor = Cocoa_CreateAnimatedCursor;
mouse->CreateSystemCursor = Cocoa_CreateSystemCursor;
mouse->ShowCursor = Cocoa_ShowCursor;
mouse->FreeCursor = Cocoa_FreeCursor;
@@ -392,8 +448,8 @@ bool Cocoa_InitMouse(SDL_VideoDevice *_this)
SDL_SetDefaultCursor(Cocoa_CreateDefaultCursor());
location = [NSEvent mouseLocation];
internal->lastMoveX = location.x;
internal->lastMoveY = location.y;
data->lastMoveX = location.x;
data->lastMoveY = location.y;
return true;
}
@@ -437,6 +493,22 @@ NSWindow *Cocoa_GetMouseFocus()
return Cocoa_MouseFocus;
}
static void Cocoa_ReconcileButtonState(NSEvent *event)
{
// Send mouse up events for any buttons that are no longer pressed
Uint32 buttons = SDL_GetMouseState(NULL, NULL);
if (buttons && ![NSEvent pressedMouseButtons]) {
Uint8 button = SDL_BUTTON_LEFT;
while (buttons) {
if (buttons & 0x01) {
SDL_SendMouseButton(Cocoa_GetEventTimestamp([event timestamp]), SDL_GetMouseFocus(), SDL_GLOBAL_MOUSE_ID, button, false);
}
++button;
buttons >>= 1;
}
}
}
void Cocoa_HandleMouseEvent(SDL_VideoDevice *_this, NSEvent *event)
{
SDL_MouseID mouseID = SDL_DEFAULT_MOUSE_ID;
@@ -451,7 +523,7 @@ void Cocoa_HandleMouseEvent(SDL_VideoDevice *_this, NSEvent *event)
// has mouse focus, so we'll always set the focus even if we happen to miss
// NSEventTypeMouseEntered, which apparently happens if the window is
// created under the mouse on macOS 12.7. But, only set the focus if
// the event acutally has a non-NULL window, otherwise what would happen
// the event actually has a non-NULL window, otherwise what would happen
// is that after an NSEventTypeMouseEntered there would sometimes be
// NSEventTypeMouseMoved without a window causing us to suppress subsequent
// mouse move events.
@@ -461,6 +533,7 @@ void Cocoa_HandleMouseEvent(SDL_VideoDevice *_this, NSEvent *event)
} else {
if ([event window] != NULL) {
Cocoa_MouseFocus = [event window];
Cocoa_ReconcileButtonState(event);
}
}
@@ -529,8 +602,9 @@ void Cocoa_HandleMouseEvent(SDL_VideoDevice *_this, NSEvent *event)
deltaY = [event deltaY];
if (seenWarp) {
SDL_CocoaVideoData *videodata = (__bridge SDL_CocoaVideoData *)_this->internal;
deltaX += (lastMoveX - data->lastWarpX);
deltaY += ((CGDisplayPixelsHigh(kCGDirectMainDisplay) - lastMoveY) - data->lastWarpY);
deltaY += ((videodata.mainDisplayHeight - lastMoveY) - data->lastWarpY);
DLog("Motion was (%g, %g), offset to (%g, %g)", [event deltaX], [event deltaY], deltaX, deltaY);
}
@@ -585,13 +659,6 @@ void Cocoa_HandleMouseWarp(CGFloat x, CGFloat y)
void Cocoa_QuitMouse(SDL_VideoDevice *_this)
{
SDL_Mouse *mouse = SDL_GetMouse();
if (mouse) {
if (mouse->internal) {
SDL_free(mouse->internal);
mouse->internal = NULL;
}
}
}
#endif // SDL_VIDEO_DRIVER_COCOA
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+13 -5
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -84,7 +84,14 @@ static void Cocoa_HandlePenProximityEvent(SDL_CocoaWindowData *_data, NSEvent *e
return; // we ignore other things, which hopefully is right.
}
Cocoa_PenHandle *handle = (Cocoa_PenHandle *) SDL_calloc(1, sizeof (*handle));
Cocoa_PenHandle *handle = Cocoa_FindPenByDeviceID(devid, toolid);
if (handle) {
handle->is_eraser = is_eraser; // in case this changed.
SDL_SendPenProximity(Cocoa_GetEventTimestamp([event timestamp]), handle->pen, _data.window, true, true);
return; // already have this one.
}
handle = (Cocoa_PenHandle *) SDL_calloc(1, sizeof (*handle));
if (!handle) {
return; // oh well.
}
@@ -100,15 +107,16 @@ static void Cocoa_HandlePenProximityEvent(SDL_CocoaWindowData *_data, NSEvent *e
handle->deviceid = devid;
handle->toolid = toolid;
handle->is_eraser = is_eraser;
handle->pen = SDL_AddPenDevice(Cocoa_GetEventTimestamp([event timestamp]), NULL, &peninfo, handle);
handle->pen = SDL_AddPenDevice(Cocoa_GetEventTimestamp([event timestamp]), NULL, _data.window, &peninfo, handle, true);
if (!handle->pen) {
SDL_free(handle); // oh well.
}
} else { // old pen leaving!
Cocoa_PenHandle *handle = Cocoa_FindPenByDeviceID(devid, toolid);
if (handle) {
SDL_RemovePenDevice(Cocoa_GetEventTimestamp([event timestamp]), handle->pen);
SDL_free(handle);
// We never remove pens (until shutdown), since Apple gives no indication when they are actually gone.
// But unless you are plugging and unplugging a tablet millions of times, generating new device IDs, this shouldn't be a massive memory drain.
SDL_SendPenProximity(Cocoa_GetEventTimestamp([event timestamp]), handle->pen, _data.window, false, false);
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+2 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -62,6 +62,7 @@ typedef enum
@property(nonatomic) IOPMAssertionID screensaver_assertion;
@property(nonatomic) SDL_Mutex *swaplock;
@property(nonatomic) OptionAsAlt option_as_alt;
@property(nonatomic) CGFloat mainDisplayHeight;
@end
// Utility functions
+4 -4
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -211,8 +211,8 @@ static bool Cocoa_VideoInit(SDL_VideoDevice *_this)
// Assume we have a mouse and keyboard
// We could use GCMouse and GCKeyboard if we needed to, as is done in SDL_uikitevents.m
SDL_AddKeyboard(SDL_DEFAULT_KEYBOARD_ID, NULL, false);
SDL_AddMouse(SDL_DEFAULT_MOUSE_ID, NULL, false);
SDL_AddKeyboard(SDL_DEFAULT_KEYBOARD_ID, NULL);
SDL_AddMouse(SDL_DEFAULT_MOUSE_ID, NULL);
data.allow_spaces = SDL_GetHintBoolean(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, true);
data.trackpad_is_touch_only = SDL_GetHintBoolean(SDL_HINT_TRACKPAD_IS_TOUCH_ONLY, false);
@@ -244,7 +244,7 @@ void Cocoa_VideoQuit(SDL_VideoDevice *_this)
SDL_SystemTheme Cocoa_GetSystemTheme(void)
{
if (@available(macOS 10.14, *)) {
NSAppearance* appearance = [[NSApplication sharedApplication] effectiveAppearance];
NSAppearance *appearance = [[NSApplication sharedApplication] effectiveAppearance];
if ([appearance.name containsString: @"Dark"]) {
return SDL_SYSTEM_THEME_DARK;
+2 -2
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -36,7 +36,7 @@
extern bool Cocoa_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
extern void Cocoa_Vulkan_UnloadLibrary(SDL_VideoDevice *_this);
extern char const* const* Cocoa_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count);
extern char const * const *Cocoa_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count);
extern bool Cocoa_Vulkan_CreateSurface(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
+4 -4
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -36,6 +36,7 @@
#include <dlfcn.h>
const char *defaultPaths[] = {
"@executable_path/../Frameworks/libMoltenVK.dylib",
"vulkan.framework/vulkan",
"libvulkan.1.dylib",
"libvulkan.dylib",
@@ -161,11 +162,10 @@ void Cocoa_Vulkan_UnloadLibrary(SDL_VideoDevice *_this)
}
}
char const* const* Cocoa_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
Uint32 *count)
char const * const *Cocoa_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count)
{
static const char *const extensionsForCocoa[] = {
VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_METAL_SURFACE_EXTENSION_NAME, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME
VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_METAL_SURFACE_EXTENSION_NAME
};
if(count) {
*count = SDL_arraysize(extensionsForCocoa);
+3 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -122,6 +122,7 @@ typedef enum
- (void)touchesMovedWithEvent:(NSEvent *)theEvent;
- (void)touchesEndedWithEvent:(NSEvent *)theEvent;
- (void)touchesCancelledWithEvent:(NSEvent *)theEvent;
- (void)magnifyWithEvent:(NSEvent *) theEvent;
// Touch event handling
- (void)handleTouches:(NSTouchPhase)phase withEvent:(NSEvent *)theEvent;
@@ -140,6 +141,7 @@ typedef enum
@property(nonatomic) SDL_Window *window;
@property(nonatomic) NSWindow *nswindow;
@property(nonatomic) NSView *sdlContentView;
@property(nonatomic) NSRect viewport;
@property(nonatomic) NSMutableArray *nscontexts;
@property(nonatomic) BOOL in_blocking_transition;
@property(nonatomic) BOOL fullscreen_space_requested;
+131 -38
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -41,7 +41,7 @@
#endif
#ifdef DEBUG_COCOAWINDOW
#define DLog(fmt, ...) printf("%s: " fmt "\n", __func__, ##__VA_ARGS__)
#define DLog(fmt, ...) printf("%s: " fmt "\n", SDL_FUNCTION, ##__VA_ARGS__)
#else
#define DLog(...) \
do { \
@@ -411,6 +411,19 @@ bool Cocoa_IsWindowInFullscreenSpace(SDL_Window *window)
}
}
bool Cocoa_IsWindowInFullscreenSpaceTransition(SDL_Window *window)
{
@autoreleasepool {
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal;
if ([data.listener isInFullscreenSpaceTransition]) {
return true;
} else {
return false;
}
}
}
bool Cocoa_IsWindowZoomed(SDL_Window *window)
{
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->internal;
@@ -494,7 +507,8 @@ static NSScreen *ScreenForRect(const NSRect *rect)
static void ConvertNSRect(NSRect *r)
{
r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height;
SDL_CocoaVideoData *videodata = (__bridge SDL_CocoaVideoData *)SDL_GetVideoDevice()->internal;
r->origin.y = videodata.mainDisplayHeight - r->origin.y - r->size.height;
}
static void ScheduleContextUpdates(SDL_CocoaWindowData *data)
@@ -748,12 +762,44 @@ static void Cocoa_WaitForMiniaturizable(SDL_Window *window)
}
}
static void Cocoa_IncrementCursorFrame(void)
{
SDL_Mouse *mouse = SDL_GetMouse();
if (mouse->cur_cursor) {
SDL_CursorData *cdata = mouse->cur_cursor->internal;
cdata->current_frame = (cdata->current_frame + 1) % cdata->num_cursors;
SDL_Window *focus = SDL_GetMouseFocus();
if (focus) {
SDL_CocoaWindowData *_data = (__bridge SDL_CocoaWindowData *)focus->internal;
[_data.nswindow invalidateCursorRectsForView:_data.sdlContentView];
}
}
}
static NSCursor *Cocoa_GetDesiredCursor(void)
{
SDL_Mouse *mouse = SDL_GetMouse();
if (mouse->cursor_shown && mouse->cur_cursor && !mouse->relative_mode) {
return (__bridge NSCursor *)mouse->cur_cursor->internal;
if (mouse->cursor_visible && mouse->cur_cursor && !mouse->relative_mode) {
SDL_CursorData *cdata = mouse->cur_cursor->internal;
if (cdata) {
if (cdata->num_cursors > 1 && cdata->frames[cdata->current_frame].duration && !cdata->frameTimer) {
const NSTimeInterval interval = cdata->frames[cdata->current_frame].duration * 0.001;
cdata->frameTimer = [NSTimer timerWithTimeInterval:interval
repeats:NO
block:^(NSTimer *timer) {
cdata->frameTimer = nil;
Cocoa_IncrementCursorFrame();
}];
[[NSRunLoop currentRunLoop] addTimer:cdata->frameTimer forMode:NSRunLoopCommonModes];
}
return (__bridge NSCursor *)cdata->frames[cdata->current_frame].cursor;
}
}
return [NSCursor invisibleCursor];
@@ -1197,6 +1243,12 @@ static NSCursor *Cocoa_GetDesiredCursor(void)
w = (int)rect.size.width;
h = (int)rect.size.height;
_data.viewport = [_data.sdlContentView bounds];
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
// This gives us the correct viewport for a Retina-enabled view.
_data.viewport = [_data.sdlContentView convertRectToBacking:_data.viewport];
}
ScheduleContextUpdates(_data);
/* The OS can resize the window automatically if the display density
@@ -1323,6 +1375,8 @@ static NSCursor *Cocoa_GetDesiredCursor(void)
- (void)windowDidChangeBackingProperties:(NSNotification *)aNotification
{
SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)_data.window->internal;
NSView *contentView = windata.sdlContentView;
NSNumber *oldscale = [[aNotification userInfo] objectForKey:NSBackingPropertyOldScaleFactorKey];
if (inFullscreenTransition) {
@@ -1330,6 +1384,9 @@ static NSCursor *Cocoa_GetDesiredCursor(void)
}
if ([oldscale doubleValue] != [_data.nswindow backingScaleFactor]) {
// Update the content scale on the window layer
// This is required to keep content scale in sync with ANGLE
contentView.layer.contentsScale = [_data.nswindow backingScaleFactor];
// Send a resize event when the backing scale factor changes.
[self windowDidResize:aNotification];
}
@@ -1849,6 +1906,19 @@ static void Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL
x = point.x;
y = (window->h - point.y);
// On macOS 26 if you move away from a space and then back, mouse motion events will have incorrect
// values at the top of the screen. The global mouse position query is still correct, so we'll fall
// back to that until this is fixed by Apple. Mouse button events are interestingly not affected.
if (@available(macOS 26.0, *)) {
if ([_data.listener isInFullscreenSpace]) {
int posx = 0, posy = 0;
SDL_GetWindowPosition(window, &posx, &posy);
SDL_GetGlobalMouseState(&x, &y);
x -= posx;
y -= posy;
}
}
if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_13_2) {
// Mouse grab is taken care of by the confinement rect
} else {
@@ -1964,6 +2034,27 @@ static void Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL
[self handleTouches:NSTouchPhaseCancelled withEvent:theEvent];
}
- (void)magnifyWithEvent:(NSEvent *)theEvent
{
switch ([theEvent phase]) {
case NSEventPhaseBegan:
SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, 0);
break;
case NSEventPhaseChanged:
{
CGFloat scale = 1.0f + [theEvent magnification];
SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, scale);
}
break;
case NSEventPhaseEnded:
case NSEventPhaseCancelled:
SDL_SendPinch(SDL_EVENT_PINCH_END, Cocoa_GetEventTimestamp([theEvent timestamp]), NULL, 0);
break;
default:
break;
}
}
- (void)handleTouches:(NSTouchPhase)phase withEvent:(NSEvent *)theEvent
{
NSSet *touches = [theEvent touchesMatchingPhase:phase inView:nil];
@@ -2130,20 +2221,19 @@ static void Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL
}
}
// NSTrackingArea is how Cocoa tells you when the mouse cursor has entered or
// left certain regions. We put one over our entire window so we know when
// it has "mouse focus."
- (void)updateTrackingAreas
{
[super updateTrackingAreas];
if (@available(macOS 12.0, *)) {
// we (currently) use the tracking areas as a workaround for older macOSes, but we might be safe everywhere...
} else {
SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)_sdlWindow->internal;
if (_trackingArea) {
[self removeTrackingArea:_trackingArea];
}
_trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options:NSTrackingMouseEnteredAndExited|NSTrackingActiveAlways owner:windata.listener userInfo:nil];
[self addTrackingArea:_trackingArea];
SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)_sdlWindow->internal;
if (_trackingArea) {
[self removeTrackingArea:_trackingArea];
}
_trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options:NSTrackingMouseEnteredAndExited|NSTrackingActiveAlways owner:windata.listener userInfo:nil];
[self addTrackingArea:_trackingArea];
}
@end
@@ -2165,12 +2255,13 @@ static void Cocoa_UpdateMouseFocus()
}
*stop = YES;
if (sdlwindow) {
SDL_CocoaVideoData *videodata = (__bridge SDL_CocoaVideoData *)vid->internal;
int wx, wy;
SDL_RelativeToGlobalForWindow(sdlwindow, sdlwindow->x, sdlwindow->y, &wx, &wy);
// Calculate the cursor coordinates relative to the window.
const float dx = mouseLocation.x - wx;
const float dy = (CGDisplayPixelsHigh(kCGDirectMainDisplay) - mouseLocation.y) - wy;
const float dy = (videodata.mainDisplayHeight - mouseLocation.y) - wy;
SDL_SendMouseMotion(0, sdlwindow, SDL_GLOBAL_MOUSE_ID, false, dx, dy);
}
}
@@ -2196,6 +2287,12 @@ static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, NSWindow
data.nscontexts = [[NSMutableArray alloc] init];
data.sdlContentView = nsview;
data.viewport = [data.sdlContentView bounds];
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
// This gives us the correct viewport for a Retina-enabled view.
data.viewport = [data.sdlContentView convertRectToBacking:data.viewport];
}
// Create an event listener for the window
data.listener = [[SDL3Cocoa_WindowListener alloc] init];
@@ -2390,12 +2487,12 @@ bool Cocoa_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properti
[nswindow setTabbingMode:NSWindowTabbingModeDisallowed];
if (videodata.allow_spaces) {
// we put fullscreen desktop windows in their own Space, without a toggle button or menubar, later
if (window->flags & SDL_WINDOW_RESIZABLE) {
// resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar.
[nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
}
// we put fullscreen desktop windows in their own Space, without a toggle button or menubar, later
if ((window->flags & SDL_WINDOW_RESIZABLE) && videodata.allow_spaces) {
// resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar.
[nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
} else {
[nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenNone];
}
// Create a default view for this window
@@ -2551,7 +2648,8 @@ void Cocoa_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window)
SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)window->internal;
NSWindow *nswindow = windata.nswindow;
if ([windata.listener isInFullscreenSpaceTransition]) {
if ([windata.listener isInFullscreenSpace] ||
[windata.listener isInFullscreenSpaceTransition]) {
windata.pending_size = YES;
return;
}
@@ -2625,16 +2723,9 @@ void Cocoa_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int
{
@autoreleasepool {
SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)window->internal;
NSView *contentView = windata.sdlContentView;
NSRect viewport = [contentView bounds];
if (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) {
// This gives us the correct viewport for a Retina-enabled view.
viewport = [contentView convertRectToBacking:viewport];
}
*w = (int)viewport.size.width;
*h = (int)viewport.size.height;
*w = (int)windata.viewport.size.width;
*h = (int)windata.viewport.size.height;
}
}
@@ -2861,13 +2952,12 @@ void Cocoa_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, bool r
if (![listener isInFullscreenSpace] && ![listener isInFullscreenSpaceTransition]) {
SetWindowStyle(window, GetWindowStyle(window));
}
if (videodata.allow_spaces) {
if (resizable) {
// resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar.
[nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
} else {
[nswindow setCollectionBehavior:NSWindowCollectionBehaviorManaged];
}
if (resizable && videodata.allow_spaces) {
// resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar.
[nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
} else {
[nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenNone];
}
}
}
@@ -2964,6 +3054,9 @@ SDL_FullscreenResult Cocoa_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Windo
[nswindow setContentSize:rect.size];
[nswindow setFrameOrigin:rect.origin];
// Disable the window shadow in fullscreen to avoid a visible 1px border on Tahoe
nswindow.hasShadow = !fullscreen && !(window->flags & SDL_WINDOW_TRANSPARENT);
// When the window style changes the title is cleared
if (!fullscreen) {
Cocoa_SetWindowTitle(_this, window);
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
+41 -14
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
@@ -52,8 +52,13 @@
#define DUMMYVID_DRIVER_EVDEV_NAME "evdev"
// Initialization/Query functions
static bool DUMMY_VideoInitCommon(SDL_VideoDevice *_this);
static bool DUMMY_VideoInit(SDL_VideoDevice *_this);
static void DUMMY_VideoQuit(SDL_VideoDevice *_this);
#ifdef SDL_INPUT_LINUXEV
static bool DUMMY_EVDEV_VideoInit(SDL_VideoDevice *_this);
static void DUMMY_EVDEV_VideoQuit(SDL_VideoDevice *_this);
#endif
static bool DUMMY_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window)
{
@@ -68,13 +73,11 @@ static void DUMMY_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window)
// DUMMY driver bootstrap functions
static bool DUMMY_Available(const char *enable_hint)
static bool DUMMY_Available(const char *drivername)
{
const char *hint = SDL_GetHint(SDL_HINT_VIDEO_DRIVER);
if (hint) {
if (SDL_strcmp(hint, enable_hint) == 0) {
return true;
}
if (hint && SDL_strstr(hint, drivername) != NULL) {
return true;
}
return false;
}
@@ -127,6 +130,21 @@ VideoBootStrap DUMMY_bootstrap = {
#ifdef SDL_INPUT_LINUXEV
static bool DUMMY_EVDEV_VideoInit(SDL_VideoDevice *_this)
{
if (!DUMMY_VideoInitCommon(_this)) {
return false;
}
SDL_EVDEV_Init();
return true;
}
static void DUMMY_EVDEV_VideoQuit(SDL_VideoDevice *_this)
{
SDL_EVDEV_Quit();
}
static void DUMMY_EVDEV_Poll(SDL_VideoDevice *_this)
{
(void)_this;
@@ -137,6 +155,8 @@ static SDL_VideoDevice *DUMMY_EVDEV_CreateDevice(void)
{
SDL_VideoDevice *device = DUMMY_InternalCreateDevice(DUMMYVID_DRIVER_EVDEV_NAME);
if (device) {
device->VideoInit = DUMMY_EVDEV_VideoInit;
device->VideoQuit = DUMMY_EVDEV_VideoQuit;
device->PumpEvents = DUMMY_EVDEV_Poll;
}
return device;
@@ -151,7 +171,12 @@ VideoBootStrap DUMMY_evdev_bootstrap = {
#endif // SDL_INPUT_LINUXEV
bool DUMMY_VideoInit(SDL_VideoDevice *_this)
static bool DUMMY_SetRelativeMouseMode(bool enabled)
{
return true;
}
bool DUMMY_VideoInitCommon(SDL_VideoDevice *_this)
{
SDL_DisplayMode mode;
@@ -164,19 +189,21 @@ bool DUMMY_VideoInit(SDL_VideoDevice *_this)
return false;
}
#ifdef SDL_INPUT_LINUXEV
SDL_EVDEV_Init();
#endif
return true;
}
// We're done!
bool DUMMY_VideoInit(SDL_VideoDevice *_this)
{
if (!DUMMY_VideoInitCommon(_this)) {
return false;
}
SDL_GetMouse()->SetRelativeMouseMode = DUMMY_SetRelativeMouseMode;
return true;
}
void DUMMY_VideoQuit(SDL_VideoDevice *_this)
{
#ifdef SDL_INPUT_LINUXEV
SDL_EVDEV_Quit();
#endif
}
#endif // SDL_VIDEO_DRIVER_DUMMY
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2026 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
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More