Merge commit 'dec0d4ec4153bf9fc2b78ae6c2df45b6ea8dde7a' as 'external/sdl/SDL'

This commit is contained in:
2023-07-25 22:27:55 +02:00
1663 changed files with 627495 additions and 0 deletions

1602
external/sdl/SDL/src/video/SDL_RLEaccel.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_RLEaccel_c_h_
#define SDL_RLEaccel_c_h_
#include "SDL_internal.h"
/* Useful functions and variables from SDL_RLEaccel.c */
extern int SDL_RLESurface(SDL_Surface *surface);
extern void SDL_UnRLESurface(SDL_Surface *surface, int recode);
#endif /* SDL_RLEaccel_c_h_ */

283
external/sdl/SDL/src/video/SDL_blit.c vendored Normal file
View File

@ -0,0 +1,283 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_sysvideo.h"
#include "SDL_blit.h"
#include "SDL_blit_auto.h"
#include "SDL_blit_copy.h"
#include "SDL_blit_slow.h"
#include "SDL_RLEaccel_c.h"
#include "SDL_pixels_c.h"
/* The general purpose software blit routine */
static int SDLCALL SDL_SoftBlit(SDL_Surface *src, const SDL_Rect *srcrect,
SDL_Surface *dst, const SDL_Rect *dstrect)
{
int okay;
int src_locked;
int dst_locked;
/* Everything is okay at the beginning... */
okay = 1;
/* Lock the destination if it's in hardware */
dst_locked = 0;
if (SDL_MUSTLOCK(dst)) {
if (SDL_LockSurface(dst) < 0) {
okay = 0;
} else {
dst_locked = 1;
}
}
/* Lock the source if it's in hardware */
src_locked = 0;
if (SDL_MUSTLOCK(src)) {
if (SDL_LockSurface(src) < 0) {
okay = 0;
} else {
src_locked = 1;
}
}
/* Set up source and destination buffer pointers, and BLIT! */
if (okay && !SDL_RectEmpty(srcrect)) {
SDL_BlitFunc RunBlit;
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->BytesPerPixel;
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->BytesPerPixel;
info->dst =
(Uint8 *)dst->pixels + (Uint16)dstrect->y * dst->pitch +
(Uint16)dstrect->x * info->dst_fmt->BytesPerPixel;
info->dst_w = dstrect->w;
info->dst_h = dstrect->h;
info->dst_pitch = dst->pitch;
info->dst_skip =
info->dst_pitch - info->dst_w * info->dst_fmt->BytesPerPixel;
RunBlit = (SDL_BlitFunc)src->map->data;
/* Run the actual software blit */
RunBlit(info);
}
/* We need to unlock the surfaces if they're locked */
if (dst_locked) {
SDL_UnlockSurface(dst);
}
if (src_locked) {
SDL_UnlockSurface(src);
}
/* Blit is done! */
return okay ? 0 : -1;
}
#if SDL_HAVE_BLIT_AUTO
#ifdef __MACOS__
#include <sys/sysctl.h>
static SDL_bool SDL_UseAltivecPrefetch(void)
{
const char key[] = "hw.l3cachesize";
u_int64_t result = 0;
size_t typeSize = sizeof(result);
if (sysctlbyname(key, &result, &typeSize, NULL, 0) == 0 && result > 0) {
return SDL_TRUE;
} else {
return SDL_FALSE;
}
}
#else
static SDL_bool SDL_UseAltivecPrefetch(void)
{
/* Just guess G4 */
return SDL_TRUE;
}
#endif /* __MACOS__ */
static SDL_BlitFunc SDL_ChooseBlitFunc(Uint32 src_format, Uint32 dst_format, int flags,
SDL_BlitFuncEntry *entries)
{
int i, flagcheck = (flags & (SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA | SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL | SDL_COPY_COLORKEY | SDL_COPY_NEAREST));
static int features = 0x7fffffff;
/* Get the available CPU features */
if (features == 0x7fffffff) {
const char *override = SDL_getenv("SDL_BLIT_CPU_FEATURES");
features = SDL_CPU_ANY;
/* Allow an override for testing .. */
if (override) {
(void)SDL_sscanf(override, "%u", &features);
} else {
if (SDL_HasMMX()) {
features |= SDL_CPU_MMX;
}
if (SDL_HasSSE()) {
features |= SDL_CPU_SSE;
}
if (SDL_HasSSE2()) {
features |= SDL_CPU_SSE2;
}
if (SDL_HasAltiVec()) {
if (SDL_UseAltivecPrefetch()) {
features |= SDL_CPU_ALTIVEC_PREFETCH;
} else {
features |= SDL_CPU_ALTIVEC_NOPREFETCH;
}
}
}
}
for (i = 0; entries[i].func; ++i) {
/* Check for matching pixel formats */
if (src_format != entries[i].src_format) {
continue;
}
if (dst_format != entries[i].dst_format) {
continue;
}
/* Check flags */
if ((flagcheck & entries[i].flags) != flagcheck) {
continue;
}
/* Check CPU features */
if ((entries[i].cpu & features) != entries[i].cpu) {
continue;
}
/* We found the best one! */
return entries[i].func;
}
return NULL;
}
#endif /* SDL_HAVE_BLIT_AUTO */
/* Figure out which of many blit routines to set up on a surface */
int SDL_CalculateBlit(SDL_Surface *surface)
{
SDL_BlitFunc blit = NULL;
SDL_BlitMap *map = surface->map;
SDL_Surface *dst = map->dst;
/* We don't currently support blitting to < 8 bpp surfaces */
if (dst->format->BitsPerPixel < 8) {
SDL_InvalidateMap(map);
return SDL_SetError("Blit combination not supported");
}
#if SDL_HAVE_RLE
/* Clean everything out to start */
if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
SDL_UnRLESurface(surface, 1);
}
#endif
map->blit = SDL_SoftBlit;
map->info.src_fmt = surface->format;
map->info.src_pitch = surface->pitch;
map->info.dst_fmt = dst->format;
map->info.dst_pitch = dst->pitch;
#if SDL_HAVE_RLE
/* See if we can do RLE acceleration */
if (map->info.flags & SDL_COPY_RLE_DESIRED) {
if (SDL_RLESurface(surface) == 0) {
return 0;
}
}
#endif
/* Choose a standard blit function */
if (map->identity && !(map->info.flags & ~SDL_COPY_RLE_DESIRED)) {
blit = SDL_BlitCopy;
} else if (surface->format->Rloss > 8 || dst->format->Rloss > 8) {
blit = SDL_Blit_Slow;
}
#if SDL_HAVE_BLIT_0
else if (surface->format->BitsPerPixel < 8 &&
SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
blit = SDL_CalculateBlit0(surface);
}
#endif
#if SDL_HAVE_BLIT_1
else if (surface->format->BytesPerPixel == 1 &&
SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
blit = SDL_CalculateBlit1(surface);
}
#endif
#if SDL_HAVE_BLIT_A
else if (map->info.flags & SDL_COPY_BLEND) {
blit = SDL_CalculateBlitA(surface);
}
#endif
#if SDL_HAVE_BLIT_N
else {
blit = SDL_CalculateBlitN(surface);
}
#endif
#if SDL_HAVE_BLIT_AUTO
if (blit == NULL) {
Uint32 src_format = surface->format->format;
Uint32 dst_format = dst->format->format;
blit =
SDL_ChooseBlitFunc(src_format, dst_format, map->info.flags,
SDL_GeneratedBlitFuncTable);
}
#endif
#ifndef TEST_SLOW_BLIT
if (blit == NULL)
#endif
{
Uint32 src_format = surface->format->format;
Uint32 dst_format = dst->format->format;
if (!SDL_ISPIXELFORMAT_INDEXED(src_format) &&
!SDL_ISPIXELFORMAT_FOURCC(src_format) &&
!SDL_ISPIXELFORMAT_INDEXED(dst_format) &&
!SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
blit = SDL_Blit_Slow;
}
}
map->data = blit;
/* Make sure we have a blit function */
if (blit == NULL) {
SDL_InvalidateMap(map);
return SDL_SetError("Blit combination not supported");
}
return 0;
}

581
external/sdl/SDL/src/video/SDL_blit.h vendored Normal file
View File

@ -0,0 +1,581 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_blit_h_
#define SDL_blit_h_
/* pixman ARM blitters are 32 bit only : */
#if defined(__aarch64__) || defined(_M_ARM64)
#undef SDL_ARM_SIMD_BLITTERS
#undef SDL_ARM_NEON_BLITTERS
#endif
/* Table to do pixel byte expansion */
extern Uint8 *SDL_expand_byte[9];
/* SDL blit copy flags */
#define SDL_COPY_MODULATE_COLOR 0x00000001
#define SDL_COPY_MODULATE_ALPHA 0x00000002
#define SDL_COPY_BLEND 0x00000010
#define SDL_COPY_ADD 0x00000020
#define SDL_COPY_MOD 0x00000040
#define SDL_COPY_MUL 0x00000080
#define SDL_COPY_COLORKEY 0x00000100
#define SDL_COPY_NEAREST 0x00000200
#define SDL_COPY_RLE_DESIRED 0x00001000
#define SDL_COPY_RLE_COLORKEY 0x00002000
#define SDL_COPY_RLE_ALPHAKEY 0x00004000
#define SDL_COPY_RLE_MASK (SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY | SDL_COPY_RLE_ALPHAKEY)
/* SDL blit CPU flags */
#define SDL_CPU_ANY 0x00000000
#define SDL_CPU_MMX 0x00000001
#define SDL_CPU_SSE 0x00000002
#define SDL_CPU_SSE2 0x00000004
#define SDL_CPU_ALTIVEC_PREFETCH 0x00000008
#define SDL_CPU_ALTIVEC_NOPREFETCH 0x00000010
typedef struct
{
Uint8 *src;
int src_w, src_h;
int src_pitch;
int src_skip;
Uint8 *dst;
int dst_w, dst_h;
int dst_pitch;
int dst_skip;
SDL_PixelFormat *src_fmt;
SDL_PixelFormat *dst_fmt;
Uint8 *table;
int flags;
Uint32 colorkey;
Uint8 r, g, b, a;
} SDL_BlitInfo;
typedef void (*SDL_BlitFunc)(SDL_BlitInfo *info);
typedef struct
{
Uint32 src_format;
Uint32 dst_format;
int flags;
int cpu;
SDL_BlitFunc func;
} SDL_BlitFuncEntry;
/* Blit mapping definition */
/* typedef'ed in SDL_surface.h */
struct SDL_BlitMap
{
SDL_Surface *dst;
int identity;
SDL_blit blit;
void *data;
SDL_BlitInfo info;
/* the version count matches the destination; mismatch indicates
an invalid mapping */
Uint32 dst_palette_version;
Uint32 src_palette_version;
};
/* Functions found in SDL_blit.c */
extern int SDL_CalculateBlit(SDL_Surface *surface);
/* Functions found in SDL_blit_*.c */
extern SDL_BlitFunc SDL_CalculateBlit0(SDL_Surface *surface);
extern SDL_BlitFunc SDL_CalculateBlit1(SDL_Surface *surface);
extern SDL_BlitFunc SDL_CalculateBlitN(SDL_Surface *surface);
extern SDL_BlitFunc SDL_CalculateBlitA(SDL_Surface *surface);
/*
* Useful macros for blitting routines
*/
#ifdef __GNUC__
#define DECLARE_ALIGNED(t, v, a) t __attribute__((aligned(a))) v
#elif defined(_MSC_VER)
#define DECLARE_ALIGNED(t, v, a) __declspec(align(a)) t v
#else
#define DECLARE_ALIGNED(t, v, a) t v
#endif
/* Load pixel of the specified format from a buffer and get its R-G-B values */
#define RGB_FROM_PIXEL(Pixel, fmt, r, g, b) \
{ \
r = SDL_expand_byte[fmt->Rloss][((Pixel & fmt->Rmask) >> fmt->Rshift)]; \
g = SDL_expand_byte[fmt->Gloss][((Pixel & fmt->Gmask) >> fmt->Gshift)]; \
b = SDL_expand_byte[fmt->Bloss][((Pixel & fmt->Bmask) >> fmt->Bshift)]; \
}
#define RGB_FROM_RGB565(Pixel, r, g, b) \
{ \
r = SDL_expand_byte[3][((Pixel & 0xF800) >> 11)]; \
g = SDL_expand_byte[2][((Pixel & 0x07E0) >> 5)]; \
b = SDL_expand_byte[3][(Pixel & 0x001F)]; \
}
#define RGB_FROM_RGB555(Pixel, r, g, b) \
{ \
r = SDL_expand_byte[3][((Pixel & 0x7C00) >> 10)]; \
g = SDL_expand_byte[3][((Pixel & 0x03E0) >> 5)]; \
b = SDL_expand_byte[3][(Pixel & 0x001F)]; \
}
#define RGB_FROM_XRGB8888(Pixel, r, g, b) \
{ \
r = ((Pixel & 0xFF0000) >> 16); \
g = ((Pixel & 0xFF00) >> 8); \
b = (Pixel & 0xFF); \
}
#define RETRIEVE_RGB_PIXEL(buf, bpp, Pixel) \
do { \
switch (bpp) { \
case 1: \
Pixel = *((Uint8 *)(buf)); \
break; \
\
case 2: \
Pixel = *((Uint16 *)(buf)); \
break; \
\
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]; \
} \
} break; \
\
case 4: \
Pixel = *((Uint32 *)(buf)); \
break; \
\
default: \
Pixel = 0; /* stop gcc complaints */ \
break; \
} \
} 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; \
} \
} while (0)
/* Assemble R-G-B values into a specified pixel format and store them */
#define PIXEL_FROM_RGB(Pixel, fmt, r, g, b) \
{ \
Pixel = ((r >> fmt->Rloss) << fmt->Rshift) | \
((g >> fmt->Gloss) << fmt->Gshift) | \
((b >> fmt->Bloss) << fmt->Bshift) | \
fmt->Amask; \
}
#define RGB565_FROM_RGB(Pixel, r, g, b) \
{ \
Pixel = (Uint16)(((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)); \
}
#define RGB555_FROM_RGB(Pixel, r, g, b) \
{ \
Pixel = (Uint16)(((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3)); \
}
#define XRGB8888_FROM_RGB(Pixel, r, g, b) \
{ \
Pixel = (r << 16) | (g << 8) | b; \
}
#define ARGB8888_FROM_RGBA(Pixel, r, g, b, a) \
{ \
Pixel = (a << 24) | (r << 16) | (g << 8) | b; \
}
#define RGBA8888_FROM_RGBA(Pixel, r, g, b, a) \
{ \
Pixel = (r << 24) | (g << 16) | (b << 8) | a; \
}
#define ABGR8888_FROM_RGBA(Pixel, r, g, b, a) \
{ \
Pixel = (a << 24) | (b << 16) | (g << 8) | r; \
}
#define BGRA8888_FROM_RGBA(Pixel, r, g, b, a) \
{ \
Pixel = (b << 24) | (g << 16) | (r << 8) | a; \
}
#define ARGB2101010_FROM_RGBA(Pixel, r, g, b, a) \
{ \
r = r ? ((r << 2) | 0x3) : 0; \
g = g ? ((g << 2) | 0x3) : 0; \
b = b ? ((b << 2) | 0x3) : 0; \
a = (a * 3) / 255; \
Pixel = (a << 30) | (r << 20) | (g << 10) | b; \
}
#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; \
} \
}
/* FIXME: Should we rescale alpha into 0..255 here? */
#define RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a) \
{ \
r = SDL_expand_byte[fmt->Rloss][((Pixel & fmt->Rmask) >> fmt->Rshift)]; \
g = SDL_expand_byte[fmt->Gloss][((Pixel & fmt->Gmask) >> fmt->Gshift)]; \
b = SDL_expand_byte[fmt->Bloss][((Pixel & fmt->Bmask) >> fmt->Bshift)]; \
a = SDL_expand_byte[fmt->Aloss][((Pixel & fmt->Amask) >> fmt->Ashift)]; \
}
#define RGBA_FROM_8888(Pixel, fmt, r, g, b, a) \
{ \
r = (Pixel & fmt->Rmask) >> fmt->Rshift; \
g = (Pixel & fmt->Gmask) >> fmt->Gshift; \
b = (Pixel & fmt->Bmask) >> fmt->Bshift; \
a = (Pixel & fmt->Amask) >> fmt->Ashift; \
}
#define RGBA_FROM_RGBA8888(Pixel, r, g, b, a) \
{ \
r = (Pixel >> 24); \
g = ((Pixel >> 16) & 0xFF); \
b = ((Pixel >> 8) & 0xFF); \
a = (Pixel & 0xFF); \
}
#define RGBA_FROM_ARGB8888(Pixel, r, g, b, a) \
{ \
r = ((Pixel >> 16) & 0xFF); \
g = ((Pixel >> 8) & 0xFF); \
b = (Pixel & 0xFF); \
a = (Pixel >> 24); \
}
#define RGBA_FROM_ABGR8888(Pixel, r, g, b, a) \
{ \
r = (Pixel & 0xFF); \
g = ((Pixel >> 8) & 0xFF); \
b = ((Pixel >> 16) & 0xFF); \
a = (Pixel >> 24); \
}
#define RGBA_FROM_BGRA8888(Pixel, r, g, b, a) \
{ \
r = ((Pixel >> 8) & 0xFF); \
g = ((Pixel >> 16) & 0xFF); \
b = (Pixel >> 24); \
a = (Pixel & 0xFF); \
}
#define RGBA_FROM_ARGB2101010(Pixel, r, g, b, a) \
{ \
r = ((Pixel >> 22) & 0xFF); \
g = ((Pixel >> 12) & 0xFF); \
b = ((Pixel >> 2) & 0xFF); \
a = SDL_expand_byte[6][(Pixel >> 30)]; \
}
#define DISEMBLE_RGBA(buf, bpp, fmt, Pixel, r, g, b, a) \
do { \
switch (bpp) { \
case 1: \
Pixel = *((Uint8 *)(buf)); \
RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a); \
break; \
\
case 2: \
Pixel = *((Uint16 *)(buf)); \
RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a); \
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); \
} \
a = 0xFF; \
} break; \
\
case 4: \
Pixel = *((Uint32 *)(buf)); \
RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a); \
break; \
\
default: \
/* stop gcc complaints */ \
Pixel = 0; \
r = g = b = a = 0; \
break; \
} \
} while (0)
/* FIXME: this isn't correct, especially for Alpha (maximum != 255) */
#define PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a) \
{ \
Pixel = ((r >> fmt->Rloss) << fmt->Rshift) | \
((g >> fmt->Gloss) << fmt->Gshift) | \
((b >> fmt->Bloss) << fmt->Bshift) | \
((a >> fmt->Aloss) << 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; \
} \
}
/* Blend the RGB values of two pixels with an alpha value */
#define ALPHA_BLEND_RGB(sR, sG, sB, A, dR, dG, dB) \
do { \
dR = (Uint8)((((int)(sR - dR) * (int)A) / 255) + dR); \
dG = (Uint8)((((int)(sG - dG) * (int)A) / 255) + dG); \
dB = (Uint8)((((int)(sB - dB) * (int)A) / 255) + dB); \
} while (0)
/* Blend the RGBA values of two pixels */
#define ALPHA_BLEND_RGBA(sR, sG, sB, sA, dR, dG, dB, dA) \
do { \
dR = (Uint8)((((int)(sR - dR) * (int)sA) / 255) + dR); \
dG = (Uint8)((((int)(sG - dG) * (int)sA) / 255) + dG); \
dB = (Uint8)((((int)(sB - dB) * (int)sA) / 255) + dB); \
dA = (Uint8)((int)sA + dA - ((int)sA * dA) / 255); \
} while (0)
/* This is a very useful loop for optimizing blitters */
#if defined(_MSC_VER) && (_MSC_VER == 1300)
/* There's a bug in the Visual C++ 7 optimizer when compiling this code */
#else
#define USE_DUFFS_LOOP
#endif
#ifdef USE_DUFFS_LOOP
/* 8-times unrolled loop */
#define DUFFS_LOOP8(pixel_copy_increment, width) \
{ \
int n = (width + 7) / 8; \
switch (width & 7) { \
case 0: \
do { \
pixel_copy_increment; \
SDL_FALLTHROUGH; \
case 7: \
pixel_copy_increment; \
SDL_FALLTHROUGH; \
case 6: \
pixel_copy_increment; \
SDL_FALLTHROUGH; \
case 5: \
pixel_copy_increment; \
SDL_FALLTHROUGH; \
case 4: \
pixel_copy_increment; \
SDL_FALLTHROUGH; \
case 3: \
pixel_copy_increment; \
SDL_FALLTHROUGH; \
case 2: \
pixel_copy_increment; \
SDL_FALLTHROUGH; \
case 1: \
pixel_copy_increment; \
} while (--n > 0); \
} \
}
/* 4-times unrolled loop */
#define DUFFS_LOOP4(pixel_copy_increment, width) \
{ \
int n = (width + 3) / 4; \
switch (width & 3) { \
case 0: \
do { \
pixel_copy_increment; \
SDL_FALLTHROUGH; \
case 3: \
pixel_copy_increment; \
SDL_FALLTHROUGH; \
case 2: \
pixel_copy_increment; \
SDL_FALLTHROUGH; \
case 1: \
pixel_copy_increment; \
} while (--n > 0); \
} \
}
/* Use the 8-times version of the loop by default */
#define DUFFS_LOOP(pixel_copy_increment, width) \
DUFFS_LOOP8(pixel_copy_increment, width)
/* Special version of Duff's device for even more optimization */
#define DUFFS_LOOP_124(pixel_copy_increment1, \
pixel_copy_increment2, \
pixel_copy_increment4, width) \
{ \
int n = width; \
if (n & 1) { \
pixel_copy_increment1; \
n -= 1; \
} \
if (n & 2) { \
pixel_copy_increment2; \
n -= 2; \
} \
if (n & 4) { \
pixel_copy_increment4; \
n -= 4; \
} \
if (n) { \
n /= 8; \
do { \
pixel_copy_increment4; \
pixel_copy_increment4; \
} while (--n > 0); \
} \
}
#else
/* Don't use Duff's device to unroll loops */
#define DUFFS_LOOP(pixel_copy_increment, width) \
{ \
int n; \
for (n = width; n > 0; --n) { \
pixel_copy_increment; \
} \
}
#define DUFFS_LOOP8(pixel_copy_increment, width) \
DUFFS_LOOP(pixel_copy_increment, width)
#define DUFFS_LOOP4(pixel_copy_increment, width) \
DUFFS_LOOP(pixel_copy_increment, width)
#define DUFFS_LOOP_124(pixel_copy_increment1, \
pixel_copy_increment2, \
pixel_copy_increment4, width) \
DUFFS_LOOP(pixel_copy_increment1, width)
#endif /* USE_DUFFS_LOOP */
#if defined(_MSC_VER) && (_MSC_VER >= 600)
#pragma warning(disable : 4244) /* '=': conversion from 'X' to 'Y', possible loss of data */
#endif
#endif /* SDL_blit_h_ */

793
external/sdl/SDL/src/video/SDL_blit_0.c vendored Normal file
View File

@ -0,0 +1,793 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if SDL_HAVE_BLIT_0
#include "SDL_blit.h"
/* Functions to blit from bitmaps to other surfaces */
static void BlitBto1(SDL_BlitInfo *info)
{
int c;
int width, height;
Uint8 *src, *map, *dst;
int srcskip, dstskip;
/* Set up some basic variables */
width = info->dst_w;
height = info->dst_h;
src = info->src;
srcskip = info->src_skip;
dst = info->dst;
dstskip = info->dst_skip;
map = info->table;
srcskip += width - (width + 7) / 8;
if (map) {
if (info->src_fmt->format == SDL_PIXELFORMAT_INDEX1LSB) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x01);
if (1) {
*dst = map[bit];
}
dst++;
byte >>= 1;
}
src += srcskip;
dst += dstskip;
}
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x80) >> 7;
if (1) {
*dst = map[bit];
}
dst++;
byte <<= 1;
}
src += srcskip;
dst += dstskip;
}
}
} else {
if (info->src_fmt->format == SDL_PIXELFORMAT_INDEX1LSB) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x01);
if (1) {
*dst = bit;
}
dst++;
byte >>= 1;
}
src += srcskip;
dst += dstskip;
}
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x80) >> 7;
if (1) {
*dst = bit;
}
dst++;
byte <<= 1;
}
src += srcskip;
dst += dstskip;
}
}
}
}
static void BlitBto2(SDL_BlitInfo *info)
{
int c;
int width, height;
Uint8 *src;
Uint16 *map, *dst;
int srcskip, dstskip;
/* Set up some basic variables */
width = info->dst_w;
height = info->dst_h;
src = info->src;
srcskip = info->src_skip;
dst = (Uint16 *)info->dst;
dstskip = info->dst_skip / 2;
map = (Uint16 *)info->table;
srcskip += width - (width + 7) / 8;
if (info->src_fmt->format == SDL_PIXELFORMAT_INDEX1LSB) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x01);
if (1) {
*dst = map[bit];
}
byte >>= 1;
dst++;
}
src += srcskip;
dst += dstskip;
}
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x80) >> 7;
if (1) {
*dst = map[bit];
}
byte <<= 1;
dst++;
}
src += srcskip;
dst += dstskip;
}
}
}
static void BlitBto3(SDL_BlitInfo *info)
{
int c, o;
int width, height;
Uint8 *src, *map, *dst;
int srcskip, dstskip;
/* Set up some basic variables */
width = info->dst_w;
height = info->dst_h;
src = info->src;
srcskip = info->src_skip;
dst = info->dst;
dstskip = info->dst_skip;
map = info->table;
srcskip += width - (width + 7) / 8;
if (info->src_fmt->format == SDL_PIXELFORMAT_INDEX1LSB) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x01);
if (1) {
o = bit * 4;
dst[0] = map[o++];
dst[1] = map[o++];
dst[2] = map[o++];
}
byte >>= 1;
dst += 3;
}
src += srcskip;
dst += dstskip;
}
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x80) >> 7;
if (1) {
o = bit * 4;
dst[0] = map[o++];
dst[1] = map[o++];
dst[2] = map[o++];
}
byte <<= 1;
dst += 3;
}
src += srcskip;
dst += dstskip;
}
}
}
static void BlitBto4(SDL_BlitInfo *info)
{
int width, height;
Uint8 *src;
Uint32 *map, *dst;
int srcskip, dstskip;
int c;
/* Set up some basic variables */
width = info->dst_w;
height = info->dst_h;
src = info->src;
srcskip = info->src_skip;
dst = (Uint32 *)info->dst;
dstskip = info->dst_skip / 4;
map = (Uint32 *)info->table;
srcskip += width - (width + 7) / 8;
if (info->src_fmt->format == SDL_PIXELFORMAT_INDEX1LSB) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x01);
if (1) {
*dst = map[bit];
}
byte >>= 1;
dst++;
}
src += srcskip;
dst += dstskip;
}
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x80) >> 7;
if (1) {
*dst = map[bit];
}
byte <<= 1;
dst++;
}
src += srcskip;
dst += dstskip;
}
}
}
static void BlitBto1Key(SDL_BlitInfo *info)
{
int width = info->dst_w;
int height = info->dst_h;
Uint8 *src = info->src;
Uint8 *dst = info->dst;
int srcskip = info->src_skip;
int dstskip = info->dst_skip;
Uint32 ckey = info->colorkey;
Uint8 *palmap = info->table;
int c;
/* Set up some basic variables */
srcskip += width - (width + 7) / 8;
if (palmap) {
if (info->src_fmt->format == SDL_PIXELFORMAT_INDEX1LSB) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x01);
if (bit != ckey) {
*dst = palmap[bit];
}
dst++;
byte >>= 1;
}
src += srcskip;
dst += dstskip;
}
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x80) >> 7;
if (bit != ckey) {
*dst = palmap[bit];
}
dst++;
byte <<= 1;
}
src += srcskip;
dst += dstskip;
}
}
} else {
if (info->src_fmt->format == SDL_PIXELFORMAT_INDEX1LSB) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x01);
if (bit != ckey) {
*dst = bit;
}
dst++;
byte >>= 1;
}
src += srcskip;
dst += dstskip;
}
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x80) >> 7;
if (bit != ckey) {
*dst = bit;
}
dst++;
byte <<= 1;
}
src += srcskip;
dst += dstskip;
}
}
}
}
static void BlitBto2Key(SDL_BlitInfo *info)
{
int width = info->dst_w;
int height = info->dst_h;
Uint8 *src = info->src;
Uint16 *dstp = (Uint16 *)info->dst;
int srcskip = info->src_skip;
int dstskip = info->dst_skip;
Uint32 ckey = info->colorkey;
Uint8 *palmap = info->table;
int c;
/* Set up some basic variables */
srcskip += width - (width + 7) / 8;
dstskip /= 2;
if (info->src_fmt->format == SDL_PIXELFORMAT_INDEX1LSB) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x01);
if (bit != ckey) {
*dstp = ((Uint16 *)palmap)[bit];
}
byte >>= 1;
dstp++;
}
src += srcskip;
dstp += dstskip;
}
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x80) >> 7;
if (bit != ckey) {
*dstp = ((Uint16 *)palmap)[bit];
}
byte <<= 1;
dstp++;
}
src += srcskip;
dstp += dstskip;
}
}
}
static void BlitBto3Key(SDL_BlitInfo *info)
{
int width = info->dst_w;
int height = info->dst_h;
Uint8 *src = info->src;
Uint8 *dst = info->dst;
int srcskip = info->src_skip;
int dstskip = info->dst_skip;
Uint32 ckey = info->colorkey;
Uint8 *palmap = info->table;
int c;
/* Set up some basic variables */
srcskip += width - (width + 7) / 8;
if (info->src_fmt->format == SDL_PIXELFORMAT_INDEX1LSB) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x01);
if (bit != ckey) {
SDL_memcpy(dst, &palmap[bit * 4], 3);
}
byte >>= 1;
dst += 3;
}
src += srcskip;
dst += dstskip;
}
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x80) >> 7;
if (bit != ckey) {
SDL_memcpy(dst, &palmap[bit * 4], 3);
}
byte <<= 1;
dst += 3;
}
src += srcskip;
dst += dstskip;
}
}
}
static void BlitBto4Key(SDL_BlitInfo *info)
{
int width = info->dst_w;
int height = info->dst_h;
Uint8 *src = info->src;
Uint32 *dstp = (Uint32 *)info->dst;
int srcskip = info->src_skip;
int dstskip = info->dst_skip;
Uint32 ckey = info->colorkey;
Uint8 *palmap = info->table;
int c;
/* Set up some basic variables */
srcskip += width - (width + 7) / 8;
dstskip /= 4;
if (info->src_fmt->format == SDL_PIXELFORMAT_INDEX1LSB) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x01);
if (bit != ckey) {
*dstp = ((Uint32 *)palmap)[bit];
}
byte >>= 1;
dstp++;
}
src += srcskip;
dstp += dstskip;
}
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x80) >> 7;
if (bit != ckey) {
*dstp = ((Uint32 *)palmap)[bit];
}
byte <<= 1;
dstp++;
}
src += srcskip;
dstp += dstskip;
}
}
}
static void BlitBtoNAlpha(SDL_BlitInfo *info)
{
int width = info->dst_w;
int height = info->dst_h;
Uint8 *src = info->src;
Uint8 *dst = info->dst;
int srcskip = info->src_skip;
int dstskip = info->dst_skip;
const SDL_Color *srcpal = info->src_fmt->palette->colors;
SDL_PixelFormat *dstfmt = info->dst_fmt;
int dstbpp;
int c;
Uint32 pixel;
unsigned sR, sG, sB;
unsigned dR, dG, dB, dA;
const unsigned A = info->a;
/* Set up some basic variables */
dstbpp = dstfmt->BytesPerPixel;
srcskip += width - (width + 7) / 8;
if (info->src_fmt->format == SDL_PIXELFORMAT_INDEX1LSB) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x01);
if (1) {
sR = srcpal[bit].r;
sG = srcpal[bit].g;
sB = srcpal[bit].b;
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA);
ALPHA_BLEND_RGBA(sR, sG, sB, A, dR, dG, dB, dA);
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
}
byte >>= 1;
dst += dstbpp;
}
src += srcskip;
dst += dstskip;
}
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x80) >> 7;
if (1) {
sR = srcpal[bit].r;
sG = srcpal[bit].g;
sB = srcpal[bit].b;
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA);
ALPHA_BLEND_RGBA(sR, sG, sB, A, dR, dG, dB, dA);
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
}
byte <<= 1;
dst += dstbpp;
}
src += srcskip;
dst += dstskip;
}
}
}
static void BlitBtoNAlphaKey(SDL_BlitInfo *info)
{
int width = info->dst_w;
int height = info->dst_h;
Uint8 *src = info->src;
Uint8 *dst = info->dst;
int srcskip = info->src_skip;
int dstskip = info->dst_skip;
SDL_PixelFormat *srcfmt = info->src_fmt;
SDL_PixelFormat *dstfmt = info->dst_fmt;
const SDL_Color *srcpal = srcfmt->palette->colors;
int dstbpp;
int c;
Uint32 pixel;
unsigned sR, sG, sB;
unsigned dR, dG, dB, dA;
const unsigned A = info->a;
Uint32 ckey = info->colorkey;
/* Set up some basic variables */
dstbpp = dstfmt->BytesPerPixel;
srcskip += width - (width + 7) / 8;
if (info->src_fmt->format == SDL_PIXELFORMAT_INDEX1LSB) {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x01);
if (bit != ckey) {
sR = srcpal[bit].r;
sG = srcpal[bit].g;
sB = srcpal[bit].b;
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA);
ALPHA_BLEND_RGBA(sR, sG, sB, A, dR, dG, dB, dA);
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
}
byte >>= 1;
dst += dstbpp;
}
src += srcskip;
dst += dstskip;
}
} else {
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 7)) {
byte = *src++;
}
bit = (byte & 0x80) >> 7;
if (bit != ckey) {
sR = srcpal[bit].r;
sG = srcpal[bit].g;
sB = srcpal[bit].b;
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA);
ALPHA_BLEND_RGBA(sR, sG, sB, A, dR, dG, dB, dA);
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
}
byte <<= 1;
dst += dstbpp;
}
src += srcskip;
dst += dstskip;
}
}
}
static const SDL_BlitFunc bitmap_blit[] = {
(SDL_BlitFunc)NULL, BlitBto1, BlitBto2, BlitBto3, BlitBto4
};
static const SDL_BlitFunc colorkey_blit[] = {
(SDL_BlitFunc)NULL, BlitBto1Key, BlitBto2Key, BlitBto3Key, BlitBto4Key
};
static void Blit4bto4(SDL_BlitInfo *info)
{
int width = info->dst_w;
int height = info->dst_h;
Uint8 *src = info->src;
Uint32 *dst = (Uint32 *)info->dst;
int srcskip = info->src_skip;
int dstskip = info->dst_skip;
Uint32 *map = (Uint32 *)info->table;
int c;
/* Set up some basic variables */
srcskip += width - (width + 1) / 2;
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 0x1)) {
byte = *src++;
}
bit = (byte & 0xF0) >> 4;
if (1) {
*dst = map[bit];
}
byte <<= 4;
dst++;
}
src += srcskip;
dst = (Uint32 *)((Uint8 *)dst + dstskip);
}
}
static void Blit4bto4Key(SDL_BlitInfo *info)
{
int width = info->dst_w;
int height = info->dst_h;
Uint8 *src = info->src;
Uint32 *dst = (Uint32 *)info->dst;
int srcskip = info->src_skip;
int dstskip = info->dst_skip;
Uint32 ckey = info->colorkey;
Uint32 *map = (Uint32 *)info->table;
int c;
/* Set up some basic variables */
srcskip += width - (width + 1) / 2;
while (height--) {
Uint8 byte = 0, bit;
for (c = 0; c < width; ++c) {
if (!(c & 0x1)) {
byte = *src++;
}
bit = (byte & 0xF0) >> 4;
if (bit != ckey) {
*dst = map[bit];
}
byte <<= 4;
dst++;
}
src += srcskip;
dst = (Uint32 *)((Uint8 *)dst + dstskip);
}
}
SDL_BlitFunc SDL_CalculateBlit0(SDL_Surface *surface)
{
int which;
/* 4bits to 32bits */
if (surface->format->format == SDL_PIXELFORMAT_INDEX4MSB) {
if (surface->map->dst->format->BytesPerPixel == 4) {
switch (surface->map->info.flags & ~SDL_COPY_RLE_MASK) {
case 0:
return Blit4bto4;
case SDL_COPY_COLORKEY:
return Blit4bto4Key;
}
}
return NULL;
}
if (surface->format->format == SDL_PIXELFORMAT_INDEX1MSB) {
if (surface->map->dst->format->BitsPerPixel < 8) {
which = 0;
} else {
which = surface->map->dst->format->BytesPerPixel;
}
switch (surface->map->info.flags & ~SDL_COPY_RLE_MASK) {
case 0:
return bitmap_blit[which];
case SDL_COPY_COLORKEY:
return colorkey_blit[which];
case SDL_COPY_MODULATE_ALPHA | SDL_COPY_BLEND:
return which >= 2 ? BlitBtoNAlpha : (SDL_BlitFunc)NULL;
case SDL_COPY_COLORKEY | SDL_COPY_MODULATE_ALPHA | SDL_COPY_BLEND:
return which >= 2 ? BlitBtoNAlphaKey : (SDL_BlitFunc)NULL;
}
return NULL;
}
return NULL;
}
#endif /* SDL_HAVE_BLIT_0 */

548
external/sdl/SDL/src/video/SDL_blit_1.c vendored Normal file
View File

@ -0,0 +1,548 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if SDL_HAVE_BLIT_1
#include "SDL_blit.h"
#include "SDL_sysvideo.h"
/* Functions to blit from 8-bit surfaces to other surfaces */
static void Blit1to1(SDL_BlitInfo *info)
{
#ifndef USE_DUFFS_LOOP
int c;
#endif
int width, height;
Uint8 *src, *map, *dst;
int srcskip, dstskip;
/* Set up some basic variables */
width = info->dst_w;
height = info->dst_h;
src = info->src;
srcskip = info->src_skip;
dst = info->dst;
dstskip = info->dst_skip;
map = info->table;
while (height--) {
#ifdef USE_DUFFS_LOOP
/* *INDENT-OFF* */ /* clang-format off */
DUFFS_LOOP(
{
*dst = map[*src];
}
dst++;
src++;
, width);
/* *INDENT-ON* */ /* clang-format on */
#else
for (c = width; c; --c) {
*dst = map[*src];
dst++;
src++;
}
#endif
src += srcskip;
dst += dstskip;
}
}
/* This is now endian dependent */
#ifndef USE_DUFFS_LOOP
#if (SDL_BYTEORDER == SDL_LIL_ENDIAN)
#define HI 1
#define LO 0
#else /* ( SDL_BYTEORDER == SDL_BIG_ENDIAN ) */
#define HI 0
#define LO 1
#endif
#endif
static void Blit1to2(SDL_BlitInfo *info)
{
#ifndef USE_DUFFS_LOOP
int c;
#endif
int width, height;
Uint8 *src, *dst;
Uint16 *map;
int srcskip, dstskip;
/* Set up some basic variables */
width = info->dst_w;
height = info->dst_h;
src = info->src;
srcskip = info->src_skip;
dst = info->dst;
dstskip = info->dst_skip;
map = (Uint16 *)info->table;
#ifdef USE_DUFFS_LOOP
while (height--) {
/* *INDENT-OFF* */ /* clang-format off */
DUFFS_LOOP(
{
*(Uint16 *)dst = map[*src++];
dst += 2;
},
width);
/* *INDENT-ON* */ /* clang-format on */
src += srcskip;
dst += dstskip;
}
#else
/* Memory align at 4-byte boundary, if necessary */
if ((long)dst & 0x03) {
/* Don't do anything if width is 0 */
if (width == 0) {
return;
}
--width;
while (height--) {
/* Perform copy alignment */
*(Uint16 *)dst = map[*src++];
dst += 2;
/* Copy in 4 pixel chunks */
for (c = width / 4; c; --c) {
*(Uint32 *)dst = (map[src[HI]] << 16) | (map[src[LO]]);
src += 2;
dst += 4;
*(Uint32 *)dst = (map[src[HI]] << 16) | (map[src[LO]]);
src += 2;
dst += 4;
}
/* Get any leftovers */
switch (width & 3) {
case 3:
*(Uint16 *)dst = map[*src++];
dst += 2;
SDL_FALLTHROUGH;
case 2:
*(Uint32 *)dst = (map[src[HI]] << 16) | (map[src[LO]]);
src += 2;
dst += 4;
break;
case 1:
*(Uint16 *)dst = map[*src++];
dst += 2;
break;
}
src += srcskip;
dst += dstskip;
}
} else {
while (height--) {
/* Copy in 4 pixel chunks */
for (c = width / 4; c; --c) {
*(Uint32 *)dst = (map[src[HI]] << 16) | (map[src[LO]]);
src += 2;
dst += 4;
*(Uint32 *)dst = (map[src[HI]] << 16) | (map[src[LO]]);
src += 2;
dst += 4;
}
/* Get any leftovers */
switch (width & 3) {
case 3:
*(Uint16 *)dst = map[*src++];
dst += 2;
SDL_FALLTHROUGH;
case 2:
*(Uint32 *)dst = (map[src[HI]] << 16) | (map[src[LO]]);
src += 2;
dst += 4;
break;
case 1:
*(Uint16 *)dst = map[*src++];
dst += 2;
break;
}
src += srcskip;
dst += dstskip;
}
}
#endif /* USE_DUFFS_LOOP */
}
static void Blit1to3(SDL_BlitInfo *info)
{
#ifndef USE_DUFFS_LOOP
int c;
#endif
int o;
int width, height;
Uint8 *src, *map, *dst;
int srcskip, dstskip;
/* Set up some basic variables */
width = info->dst_w;
height = info->dst_h;
src = info->src;
srcskip = info->src_skip;
dst = info->dst;
dstskip = info->dst_skip;
map = info->table;
while (height--) {
#ifdef USE_DUFFS_LOOP
/* *INDENT-OFF* */ /* clang-format off */
DUFFS_LOOP(
{
o = *src * 4;
dst[0] = map[o++];
dst[1] = map[o++];
dst[2] = map[o++];
}
src++;
dst += 3;
, width);
/* *INDENT-ON* */ /* clang-format on */
#else
for (c = width; c; --c) {
o = *src * 4;
dst[0] = map[o++];
dst[1] = map[o++];
dst[2] = map[o++];
src++;
dst += 3;
}
#endif /* USE_DUFFS_LOOP */
src += srcskip;
dst += dstskip;
}
}
static void Blit1to4(SDL_BlitInfo *info)
{
#ifndef USE_DUFFS_LOOP
int c;
#endif
int width, height;
Uint8 *src;
Uint32 *map, *dst;
int srcskip, dstskip;
/* Set up some basic variables */
width = info->dst_w;
height = info->dst_h;
src = info->src;
srcskip = info->src_skip;
dst = (Uint32 *)info->dst;
dstskip = info->dst_skip / 4;
map = (Uint32 *)info->table;
while (height--) {
#ifdef USE_DUFFS_LOOP
/* *INDENT-OFF* */ /* clang-format off */
DUFFS_LOOP(
*dst++ = map[*src++];
, width);
/* *INDENT-ON* */ /* clang-format on */
#else
for (c = width / 4; c; --c) {
*dst++ = map[*src++];
*dst++ = map[*src++];
*dst++ = map[*src++];
*dst++ = map[*src++];
}
switch (width & 3) {
case 3:
*dst++ = map[*src++];
SDL_FALLTHROUGH;
case 2:
*dst++ = map[*src++];
SDL_FALLTHROUGH;
case 1:
*dst++ = map[*src++];
}
#endif /* USE_DUFFS_LOOP */
src += srcskip;
dst += dstskip;
}
}
static void Blit1to1Key(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;
Uint8 *palmap = info->table;
Uint32 ckey = info->colorkey;
if (palmap) {
while (height--) {
/* *INDENT-OFF* */ /* clang-format off */
DUFFS_LOOP(
{
if ( *src != ckey ) {
*dst = palmap[*src];
}
dst++;
src++;
},
width);
/* *INDENT-ON* */ /* clang-format on */
src += srcskip;
dst += dstskip;
}
} else {
while (height--) {
/* *INDENT-OFF* */ /* clang-format off */
DUFFS_LOOP(
{
if ( *src != ckey ) {
*dst = *src;
}
dst++;
src++;
},
width);
/* *INDENT-ON* */ /* clang-format on */
src += srcskip;
dst += dstskip;
}
}
}
static void Blit1to2Key(SDL_BlitInfo *info)
{
int width = info->dst_w;
int height = info->dst_h;
Uint8 *src = info->src;
int srcskip = info->src_skip;
Uint16 *dstp = (Uint16 *)info->dst;
int dstskip = info->dst_skip;
Uint16 *palmap = (Uint16 *)info->table;
Uint32 ckey = info->colorkey;
/* Set up some basic variables */
dstskip /= 2;
while (height--) {
/* *INDENT-OFF* */ /* clang-format off */
DUFFS_LOOP(
{
if ( *src != ckey ) {
*dstp=palmap[*src];
}
src++;
dstp++;
},
width);
/* *INDENT-ON* */ /* clang-format on */
src += srcskip;
dstp += dstskip;
}
}
static void Blit1to3Key(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;
Uint8 *palmap = info->table;
Uint32 ckey = info->colorkey;
int o;
while (height--) {
/* *INDENT-OFF* */ /* clang-format off */
DUFFS_LOOP(
{
if ( *src != ckey ) {
o = *src * 4;
dst[0] = palmap[o++];
dst[1] = palmap[o++];
dst[2] = palmap[o++];
}
src++;
dst += 3;
},
width);
/* *INDENT-ON* */ /* clang-format on */
src += srcskip;
dst += dstskip;
}
}
static void Blit1to4Key(SDL_BlitInfo *info)
{
int width = info->dst_w;
int height = info->dst_h;
Uint8 *src = info->src;
int srcskip = info->src_skip;
Uint32 *dstp = (Uint32 *)info->dst;
int dstskip = info->dst_skip;
Uint32 *palmap = (Uint32 *)info->table;
Uint32 ckey = info->colorkey;
/* Set up some basic variables */
dstskip /= 4;
while (height--) {
/* *INDENT-OFF* */ /* clang-format off */
DUFFS_LOOP(
{
if ( *src != ckey ) {
*dstp = palmap[*src];
}
src++;
dstp++;
},
width);
/* *INDENT-ON* */ /* clang-format on */
src += srcskip;
dstp += dstskip;
}
}
static void Blit1toNAlpha(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;
SDL_PixelFormat *dstfmt = info->dst_fmt;
const SDL_Color *srcpal = info->src_fmt->palette->colors;
int dstbpp;
Uint32 pixel;
unsigned sR, sG, sB;
unsigned dR, dG, dB, dA;
const unsigned A = info->a;
/* Set up some basic variables */
dstbpp = dstfmt->BytesPerPixel;
while (height--) {
/* *INDENT-OFF* */ /* clang-format off */
DUFFS_LOOP4(
{
sR = srcpal[*src].r;
sG = srcpal[*src].g;
sB = srcpal[*src].b;
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA);
ALPHA_BLEND_RGBA(sR, sG, sB, A, dR, dG, dB, dA);
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
src++;
dst += dstbpp;
},
width);
/* *INDENT-ON* */ /* clang-format on */
src += srcskip;
dst += dstskip;
}
}
static void Blit1toNAlphaKey(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;
SDL_PixelFormat *dstfmt = info->dst_fmt;
const SDL_Color *srcpal = info->src_fmt->palette->colors;
Uint32 ckey = info->colorkey;
int dstbpp;
Uint32 pixel;
unsigned sR, sG, sB;
unsigned dR, dG, dB, dA;
const unsigned A = info->a;
/* Set up some basic variables */
dstbpp = dstfmt->BytesPerPixel;
while (height--) {
/* *INDENT-OFF* */ /* clang-format off */
DUFFS_LOOP(
{
if ( *src != ckey ) {
sR = srcpal[*src].r;
sG = srcpal[*src].g;
sB = srcpal[*src].b;
DISEMBLE_RGBA(dst, dstbpp, dstfmt, pixel, dR, dG, dB, dA);
ALPHA_BLEND_RGBA(sR, sG, sB, A, dR, dG, dB, dA);
ASSEMBLE_RGBA(dst, dstbpp, dstfmt, dR, dG, dB, dA);
}
src++;
dst += dstbpp;
},
width);
/* *INDENT-ON* */ /* clang-format on */
src += srcskip;
dst += dstskip;
}
}
static const SDL_BlitFunc one_blit[] = {
(SDL_BlitFunc)NULL, Blit1to1, Blit1to2, Blit1to3, Blit1to4
};
static const SDL_BlitFunc one_blitkey[] = {
(SDL_BlitFunc)NULL, Blit1to1Key, Blit1to2Key, Blit1to3Key, Blit1to4Key
};
SDL_BlitFunc SDL_CalculateBlit1(SDL_Surface *surface)
{
int which;
SDL_PixelFormat *dstfmt;
dstfmt = surface->map->dst->format;
if (dstfmt->BitsPerPixel < 8) {
which = 0;
} else {
which = dstfmt->BytesPerPixel;
}
switch (surface->map->info.flags & ~SDL_COPY_RLE_MASK) {
case 0:
return one_blit[which];
case SDL_COPY_COLORKEY:
return one_blitkey[which];
case SDL_COPY_COLORKEY | SDL_COPY_BLEND: /* this is not super-robust but handles a specific case we found sdl12-compat. */
return (surface->map->info.a == 255) ? one_blitkey[which] : (SDL_BlitFunc)NULL;
case SDL_COPY_MODULATE_ALPHA | SDL_COPY_BLEND:
/* Supporting 8bpp->8bpp alpha is doable but requires lots of
tables which consume space and takes time to precompute,
so is better left to the user */
return which >= 2 ? Blit1toNAlpha : (SDL_BlitFunc)NULL;
case SDL_COPY_COLORKEY | SDL_COPY_MODULATE_ALPHA | SDL_COPY_BLEND:
return which >= 2 ? Blit1toNAlphaKey : (SDL_BlitFunc)NULL;
}
return (SDL_BlitFunc)NULL;
}
#endif /* SDL_HAVE_BLIT_1 */

1471
external/sdl/SDL/src/video/SDL_blit_A.c vendored Normal file

File diff suppressed because it is too large Load Diff

3448
external/sdl/SDL/src/video/SDL_blit_N.c vendored Normal file

File diff suppressed because it is too large Load Diff

6995
external/sdl/SDL/src/video/SDL_blit_auto.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
/* DO NOT EDIT! This file is generated by sdlgenblit.pl */
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if SDL_HAVE_BLIT_AUTO
/* *INDENT-OFF* */ /* clang-format off */
extern SDL_BlitFuncEntry SDL_GeneratedBlitFuncTable[];
/* *INDENT-ON* */ /* clang-format on */
#endif /* SDL_HAVE_BLIT_AUTO */

View File

@ -0,0 +1,164 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_blit.h"
#include "SDL_blit_copy.h"
#ifdef SDL_SSE_INTRINSICS
/* This assumes 16-byte aligned src and dst */
static SDL_INLINE void SDL_TARGETING("sse") SDL_memcpySSE(Uint8 *dst, const Uint8 *src, int len)
{
int i;
__m128 values[4];
for (i = len / 64; i--;) {
_mm_prefetch((const char *)src, _MM_HINT_NTA);
values[0] = *(__m128 *)(src + 0);
values[1] = *(__m128 *)(src + 16);
values[2] = *(__m128 *)(src + 32);
values[3] = *(__m128 *)(src + 48);
_mm_stream_ps((float *)(dst + 0), values[0]);
_mm_stream_ps((float *)(dst + 16), values[1]);
_mm_stream_ps((float *)(dst + 32), values[2]);
_mm_stream_ps((float *)(dst + 48), values[3]);
src += 64;
dst += 64;
}
if (len & 63) {
SDL_memcpy(dst, src, len & 63);
}
}
#endif /* SDL_SSE_INTRINSICS */
#ifdef SDL_MMX_INTRINSICS
#ifdef _MSC_VER
#pragma warning(disable : 4799)
#endif
static SDL_INLINE void SDL_TARGETING("mmx") SDL_memcpyMMX(Uint8 *dst, const Uint8 *src, int len)
{
int remain = len & 63;
int i;
__m64 *d64 = (__m64 *)dst;
__m64 *s64 = (__m64 *)src;
for (i = len / 64; i--;) {
d64[0] = s64[0];
d64[1] = s64[1];
d64[2] = s64[2];
d64[3] = s64[3];
d64[4] = s64[4];
d64[5] = s64[5];
d64[6] = s64[6];
d64[7] = s64[7];
d64 += 8;
s64 += 8;
}
if (remain) {
const int skip = len - remain;
dst += skip;
src += skip;
while (remain--) {
*dst++ = *src++;
}
}
}
static SDL_INLINE void SDL_TARGETING("mmx") SDL_BlitCopyMMX(Uint8 *dst, const Uint8 *src, const int dstskip, const int srcskip, const int w, int h)
{
while (h--) {
SDL_memcpyMMX(dst, src, w);
src += srcskip;
dst += dstskip;
}
_mm_empty();
}
#endif /* SDL_MMX_INTRINSICS */
void SDL_BlitCopy(SDL_BlitInfo *info)
{
SDL_bool overlap;
Uint8 *src, *dst;
int w, h;
int srcskip, dstskip;
w = info->dst_w * info->dst_fmt->BytesPerPixel;
h = info->dst_h;
src = info->src;
dst = info->dst;
srcskip = info->src_pitch;
dstskip = info->dst_pitch;
/* Properly handle overlapping blits */
if (src < dst) {
overlap = (dst < (src + h * srcskip));
} else {
overlap = (src < (dst + h * dstskip));
}
if (overlap) {
if (dst < src) {
while (h--) {
SDL_memmove(dst, src, w);
src += srcskip;
dst += dstskip;
}
} else {
src += ((h - 1) * srcskip);
dst += ((h - 1) * dstskip);
while (h--) {
SDL_memmove(dst, src, w);
src -= srcskip;
dst -= dstskip;
}
}
return;
}
#ifdef SDL_SSE_INTRINSICS
if (SDL_HasSSE() &&
!((uintptr_t)src & 15) && !(srcskip & 15) &&
!((uintptr_t)dst & 15) && !(dstskip & 15)) {
while (h--) {
SDL_memcpySSE(dst, src, w);
src += srcskip;
dst += dstskip;
}
return;
}
#endif
#ifdef SDL_MMX_INTRINSICS
if (SDL_HasMMX() && !(srcskip & 7) && !(dstskip & 7)) {
SDL_BlitCopyMMX(dst, src, dstskip, srcskip, w, h);
return;
}
#endif
while (h--) {
SDL_memcpy(dst, src, w);
src += srcskip;
dst += dstskip;
}
}

View File

@ -0,0 +1,27 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_blit_copy_h_
#define SDL_blit_copy_h_
void SDL_BlitCopy(SDL_BlitInfo *info);
#endif /* SDL_blit_copy_h_ */

View File

@ -0,0 +1,198 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_blit.h"
#include "SDL_blit_slow.h"
#define FORMAT_ALPHA 0
#define FORMAT_NO_ALPHA (-1)
#define FORMAT_2101010 1
#define FORMAT_HAS_ALPHA(format) format == 0
#define FORMAT_HAS_NO_ALPHA(format) format < 0
static int detect_format(SDL_PixelFormat *pf)
{
if (pf->format == SDL_PIXELFORMAT_ARGB2101010) {
return FORMAT_2101010;
} else if (pf->Amask) {
return FORMAT_ALPHA;
} else {
return FORMAT_NO_ALPHA;
}
}
/* The ONE TRUE BLITTER
* This puppy has to handle all the unoptimized cases - yes, it's slow.
*/
void SDL_Blit_Slow(SDL_BlitInfo *info)
{
const int flags = info->flags;
const Uint32 modulateR = info->r;
const Uint32 modulateG = info->g;
const Uint32 modulateB = info->b;
const Uint32 modulateA = info->a;
Uint32 srcpixel;
Uint32 srcR, srcG, srcB, srcA;
Uint32 dstpixel;
Uint32 dstR, dstG, dstB, dstA;
int srcy, srcx;
Uint32 posy, posx;
int incy, incx;
SDL_PixelFormat *src_fmt = info->src_fmt;
SDL_PixelFormat *dst_fmt = info->dst_fmt;
int srcbpp = src_fmt->BytesPerPixel;
int dstbpp = dst_fmt->BytesPerPixel;
int srcfmt_val;
int dstfmt_val;
Uint32 rgbmask = ~src_fmt->Amask;
Uint32 ckey = info->colorkey & rgbmask;
srcfmt_val = detect_format(src_fmt);
dstfmt_val = detect_format(dst_fmt);
incy = (info->src_h << 16) / info->dst_h;
incx = (info->src_w << 16) / info->dst_w;
posy = incy / 2; /* start at the middle of pixel */
while (info->dst_h--) {
Uint8 *src = 0;
Uint8 *dst = info->dst;
int n = info->dst_w;
posx = incx / 2; /* start at the middle of pixel */
srcy = posy >> 16;
while (n--) {
srcx = posx >> 16;
src = (info->src + (srcy * info->src_pitch) + (srcx * srcbpp));
if (FORMAT_HAS_ALPHA(srcfmt_val)) {
DISEMBLE_RGBA(src, srcbpp, src_fmt, srcpixel, srcR, srcG, srcB, srcA);
} else if (FORMAT_HAS_NO_ALPHA(srcfmt_val)) {
DISEMBLE_RGB(src, srcbpp, src_fmt, srcpixel, srcR, srcG, srcB);
srcA = 0xFF;
} else {
/* SDL_PIXELFORMAT_ARGB2101010 */
srcpixel = *((Uint32 *)(src));
RGBA_FROM_ARGB2101010(srcpixel, srcR, srcG, srcB, srcA);
}
if (flags & SDL_COPY_COLORKEY) {
/* srcpixel isn't set for 24 bpp */
if (srcbpp == 3) {
srcpixel = (srcR << src_fmt->Rshift) |
(srcG << src_fmt->Gshift) | (srcB << src_fmt->Bshift);
}
if ((srcpixel & rgbmask) == ckey) {
posx += incx;
dst += dstbpp;
continue;
}
}
if (FORMAT_HAS_ALPHA(dstfmt_val)) {
DISEMBLE_RGBA(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB, dstA);
} else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) {
DISEMBLE_RGB(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB);
dstA = 0xFF;
} else {
/* SDL_PIXELFORMAT_ARGB2101010 */
dstpixel = *((Uint32 *)(dst));
RGBA_FROM_ARGB2101010(dstpixel, dstR, dstG, dstB, dstA);
}
if (flags & SDL_COPY_MODULATE_COLOR) {
srcR = (srcR * modulateR) / 255;
srcG = (srcG * modulateG) / 255;
srcB = (srcB * modulateB) / 255;
}
if (flags & SDL_COPY_MODULATE_ALPHA) {
srcA = (srcA * modulateA) / 255;
}
if (flags & (SDL_COPY_BLEND | SDL_COPY_ADD)) {
/* This goes away if we ever use premultiplied alpha */
if (srcA < 255) {
srcR = (srcR * srcA) / 255;
srcG = (srcG * srcA) / 255;
srcB = (srcB * srcA) / 255;
}
}
switch (flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL)) {
case 0:
dstR = srcR;
dstG = srcG;
dstB = srcB;
dstA = srcA;
break;
case SDL_COPY_BLEND:
dstR = srcR + ((255 - srcA) * dstR) / 255;
dstG = srcG + ((255 - srcA) * dstG) / 255;
dstB = srcB + ((255 - srcA) * dstB) / 255;
dstA = srcA + ((255 - srcA) * dstA) / 255;
break;
case SDL_COPY_ADD:
dstR = srcR + dstR;
if (dstR > 255) {
dstR = 255;
}
dstG = srcG + dstG;
if (dstG > 255) {
dstG = 255;
}
dstB = srcB + dstB;
if (dstB > 255) {
dstB = 255;
}
break;
case SDL_COPY_MOD:
dstR = (srcR * dstR) / 255;
dstG = (srcG * dstG) / 255;
dstB = (srcB * dstB) / 255;
break;
case SDL_COPY_MUL:
dstR = ((srcR * dstR) + (dstR * (255 - srcA))) / 255;
if (dstR > 255) {
dstR = 255;
}
dstG = ((srcG * dstG) + (dstG * (255 - srcA))) / 255;
if (dstG > 255) {
dstG = 255;
}
dstB = ((srcB * dstB) + (dstB * (255 - srcA))) / 255;
if (dstB > 255) {
dstB = 255;
}
break;
}
if (FORMAT_HAS_ALPHA(dstfmt_val)) {
ASSEMBLE_RGBA(dst, dstbpp, dst_fmt, dstR, dstG, dstB, dstA);
} else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) {
ASSEMBLE_RGB(dst, dstbpp, dst_fmt, dstR, dstG, dstB);
} else {
/* SDL_PIXELFORMAT_ARGB2101010 */
Uint32 pixel;
ARGB2101010_FROM_RGBA(pixel, dstR, dstG, dstB, dstA);
*(Uint32 *)dst = pixel;
}
posx += incx;
dst += dstbpp;
}
posy += incy;
info->dst += info->dst_pitch;
}
}

View File

@ -0,0 +1,29 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_blit_slow_h_
#define SDL_blit_slow_h_
#include "SDL_internal.h"
extern void SDL_Blit_Slow(SDL_BlitInfo *info);
#endif /* SDL_blit_slow_h_ */

881
external/sdl/SDL/src/video/SDL_bmp.c vendored Normal file
View File

@ -0,0 +1,881 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
/*
Code to load and save surfaces in Windows BMP format.
Why support BMP format? Well, it's a native format for Windows, and
most image processing programs can read and write it. It would be nice
to be able to have at least one image format that we can natively load
and save, and since PNG is so complex that it would bloat the library,
BMP is a good alternative.
This code currently supports Win32 DIBs in uncompressed 8 and 24 bpp.
*/
#include "SDL_pixels_c.h"
#define SAVE_32BIT_BMP
/* Compression encodings for BMP files */
#ifndef BI_RGB
#define BI_RGB 0
#define BI_RLE8 1
#define BI_RLE4 2
#define BI_BITFIELDS 3
#endif
/* Logical color space values for BMP files */
#ifndef LCS_WINDOWS_COLOR_SPACE
/* 0x57696E20 == "Win " */
#define LCS_WINDOWS_COLOR_SPACE 0x57696E20
#endif
static SDL_bool readRlePixels(SDL_Surface *surface, SDL_RWops *src, int isRle8)
{
/*
| Sets the surface pixels from src. A bmp image is upside down.
*/
int pitch = surface->pitch;
int height = surface->h;
Uint8 *start = (Uint8 *)surface->pixels;
Uint8 *end = start + (height * pitch);
Uint8 *bits = end - pitch, *spot;
int ofs = 0;
Uint8 ch;
Uint8 needsPad;
#define COPY_PIXEL(x) \
spot = &bits[ofs++]; \
if (spot >= start && spot < end) \
*spot = (x)
/* !!! FIXME: for all these reads, handle error vs eof? handle -2 if non-blocking? */
for (;;) {
if (SDL_RWread(src, &ch, 1) <= 0) {
return SDL_TRUE;
}
/*
| encoded mode starts with a run length, and then a byte
| with two colour indexes to alternate between for the run
*/
if (ch) {
Uint8 pixel;
if (SDL_RWread(src, &pixel, 1) <= 0) {
return SDL_TRUE;
}
if (isRle8) { /* 256-color bitmap, compressed */
do {
COPY_PIXEL(pixel);
} while (--ch);
} else { /* 16-color bitmap, compressed */
Uint8 pixel0 = pixel >> 4;
Uint8 pixel1 = pixel & 0x0F;
for (;;) {
COPY_PIXEL(pixel0); /* even count, high nibble */
if (!--ch) {
break;
}
COPY_PIXEL(pixel1); /* odd count, low nibble */
if (!--ch) {
break;
}
}
}
} else {
/*
| A leading zero is an escape; it may signal the end of the bitmap,
| a cursor move, or some absolute data.
| zero tag may be absolute mode or an escape
*/
if (SDL_RWread(src, &ch, 1) <= 0) {
return SDL_TRUE;
}
switch (ch) {
case 0: /* end of line */
ofs = 0;
bits -= pitch; /* go to previous */
break;
case 1: /* end of bitmap */
return SDL_FALSE; /* success! */
case 2: /* delta */
if (SDL_RWread(src, &ch, 1) <= 0) {
return SDL_TRUE;
}
ofs += ch;
if (SDL_RWread(src, &ch, 1) <= 0) {
return SDL_TRUE;
}
bits -= (ch * pitch);
break;
default: /* no compression */
if (isRle8) {
needsPad = (ch & 1);
do {
Uint8 pixel;
if (SDL_RWread(src, &pixel, 1) <= 0) {
return SDL_TRUE;
}
COPY_PIXEL(pixel);
} while (--ch);
} else {
needsPad = (((ch + 1) >> 1) & 1); /* (ch+1)>>1: bytes size */
for (;;) {
Uint8 pixel;
if (SDL_RWread(src, &pixel, 1) <= 0) {
return SDL_TRUE;
}
COPY_PIXEL(pixel >> 4);
if (!--ch) {
break;
}
COPY_PIXEL(pixel & 0x0F);
if (!--ch) {
break;
}
}
}
/* pad at even boundary */
if (needsPad && (SDL_RWread(src, &ch, 1) <= 0)) {
return SDL_TRUE;
}
break;
}
}
}
}
static void CorrectAlphaChannel(SDL_Surface *surface)
{
/* Check to see if there is any alpha channel data */
SDL_bool hasAlpha = SDL_FALSE;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
int alphaChannelOffset = 0;
#else
int alphaChannelOffset = 3;
#endif
Uint8 *alpha = ((Uint8 *)surface->pixels) + alphaChannelOffset;
Uint8 *end = alpha + surface->h * surface->pitch;
while (alpha < end) {
if (*alpha != 0) {
hasAlpha = SDL_TRUE;
break;
}
alpha += 4;
}
if (!hasAlpha) {
alpha = ((Uint8 *)surface->pixels) + alphaChannelOffset;
while (alpha < end) {
*alpha = SDL_ALPHA_OPAQUE;
alpha += 4;
}
}
}
SDL_Surface *SDL_LoadBMP_RW(SDL_RWops *src, SDL_bool freesrc)
{
SDL_bool was_error;
Sint64 fp_offset = 0;
int bmpPitch;
int i, pad;
SDL_Surface *surface;
Uint32 Rmask = 0;
Uint32 Gmask = 0;
Uint32 Bmask = 0;
Uint32 Amask = 0;
SDL_Palette *palette;
Uint8 *bits;
Uint8 *top, *end;
SDL_bool topDown;
int ExpandBMP;
SDL_bool haveRGBMasks = SDL_FALSE;
SDL_bool haveAlphaMask = SDL_FALSE;
SDL_bool correctAlpha = SDL_FALSE;
/* The Win32 BMP file header (14 bytes) */
char magic[2];
/* Uint32 bfSize; */
/* Uint16 bfReserved1; */
/* Uint16 bfReserved2; */
Uint32 bfOffBits;
/* The Win32 BITMAPINFOHEADER struct (40 bytes) */
Uint32 biSize;
Sint32 biWidth = 0;
Sint32 biHeight = 0;
/* Uint16 biPlanes; */
Uint16 biBitCount = 0;
Uint32 biCompression = 0;
/* Uint32 biSizeImage; */
/* Sint32 biXPelsPerMeter; */
/* Sint32 biYPelsPerMeter; */
Uint32 biClrUsed = 0;
/* Uint32 biClrImportant; */
/* Make sure we are passed a valid data source */
surface = NULL;
was_error = SDL_FALSE;
if (src == NULL) {
SDL_InvalidParamError("src");
was_error = SDL_TRUE;
goto done;
}
/* Read in the BMP file header */
fp_offset = SDL_RWtell(src);
if (fp_offset < 0) {
was_error = SDL_TRUE;
goto done;
}
SDL_ClearError();
if (SDL_RWread(src, magic, 2) != 2) {
SDL_Error(SDL_EFREAD);
was_error = SDL_TRUE;
goto done;
}
if (SDL_strncmp(magic, "BM", 2) != 0) {
SDL_SetError("File is not a Windows BMP file");
was_error = SDL_TRUE;
goto done;
}
/* bfSize = */ SDL_ReadLE32(src);
/* bfReserved1 = */ SDL_ReadLE16(src);
/* bfReserved2 = */ SDL_ReadLE16(src);
bfOffBits = SDL_ReadLE32(src);
/* Read the Win32 BITMAPINFOHEADER */
biSize = SDL_ReadLE32(src);
if (biSize == 12) { /* really old BITMAPCOREHEADER */
biWidth = (Uint32)SDL_ReadLE16(src);
biHeight = (Uint32)SDL_ReadLE16(src);
/* biPlanes = */ SDL_ReadLE16(src);
biBitCount = SDL_ReadLE16(src);
biCompression = BI_RGB;
/* biSizeImage = 0; */
/* biXPelsPerMeter = 0; */
/* biYPelsPerMeter = 0; */
biClrUsed = 0;
/* biClrImportant = 0; */
} else if (biSize >= 40) { /* some version of BITMAPINFOHEADER */
Uint32 headerSize;
biWidth = SDL_ReadLE32(src);
biHeight = SDL_ReadLE32(src);
/* biPlanes = */ SDL_ReadLE16(src);
biBitCount = SDL_ReadLE16(src);
biCompression = SDL_ReadLE32(src);
/* biSizeImage = */ SDL_ReadLE32(src);
/* biXPelsPerMeter = */ SDL_ReadLE32(src);
/* biYPelsPerMeter = */ SDL_ReadLE32(src);
biClrUsed = SDL_ReadLE32(src);
/* biClrImportant = */ SDL_ReadLE32(src);
/* 64 == BITMAPCOREHEADER2, an incompatible OS/2 2.x extension. Skip this stuff for now. */
if (biSize != 64) {
/* This is complicated. If compression is BI_BITFIELDS, then
we have 3 DWORDS that specify the RGB masks. This is either
stored here in an BITMAPV2INFOHEADER (which only differs in
that it adds these RGB masks) and biSize >= 52, or we've got
these masks stored in the exact same place, but strictly
speaking, this is the bmiColors field in BITMAPINFO immediately
following the legacy v1 info header, just past biSize. */
if (biCompression == BI_BITFIELDS) {
haveRGBMasks = SDL_TRUE;
Rmask = SDL_ReadLE32(src);
Gmask = SDL_ReadLE32(src);
Bmask = SDL_ReadLE32(src);
/* ...v3 adds an alpha mask. */
if (biSize >= 56) { /* BITMAPV3INFOHEADER; adds alpha mask */
haveAlphaMask = SDL_TRUE;
Amask = SDL_ReadLE32(src);
}
} else {
/* the mask fields are ignored for v2+ headers if not BI_BITFIELD. */
if (biSize >= 52) { /* BITMAPV2INFOHEADER; adds RGB masks */
/*Rmask = */ SDL_ReadLE32(src);
/*Gmask = */ SDL_ReadLE32(src);
/*Bmask = */ SDL_ReadLE32(src);
}
if (biSize >= 56) { /* BITMAPV3INFOHEADER; adds alpha mask */
/*Amask = */ SDL_ReadLE32(src);
}
}
/* Insert other fields here; Wikipedia and MSDN say we're up to
v5 of this header, but we ignore those for now (they add gamma,
color spaces, etc). Ignoring the weird OS/2 2.x format, we
currently parse up to v3 correctly (hopefully!). */
}
/* skip any header bytes we didn't handle... */
headerSize = (Uint32)(SDL_RWtell(src) - (fp_offset + 14));
if (biSize > headerSize) {
SDL_RWseek(src, (biSize - headerSize), SDL_RW_SEEK_CUR);
}
}
if (biWidth <= 0 || biHeight == 0) {
SDL_SetError("BMP file with bad dimensions (%" SDL_PRIs32 "x%" SDL_PRIs32 ")", biWidth, biHeight);
was_error = SDL_TRUE;
goto done;
}
if (biHeight < 0) {
topDown = SDL_TRUE;
biHeight = -biHeight;
} else {
topDown = SDL_FALSE;
}
/* Check for read error */
if (SDL_strcmp(SDL_GetError(), "") != 0) {
was_error = SDL_TRUE;
goto done;
}
/* Expand 1, 2 and 4 bit bitmaps to 8 bits per pixel */
switch (biBitCount) {
case 1:
case 2:
case 4:
ExpandBMP = biBitCount;
biBitCount = 8;
break;
case 0:
case 3:
case 5:
case 6:
case 7:
SDL_SetError("%d-bpp BMP images are not supported", biBitCount);
was_error = SDL_TRUE;
goto done;
default:
ExpandBMP = 0;
break;
}
/* RLE4 and RLE8 BMP compression is supported */
switch (biCompression) {
case BI_RGB:
/* If there are no masks, use the defaults */
SDL_assert(!haveRGBMasks);
SDL_assert(!haveAlphaMask);
/* Default values for the BMP format */
switch (biBitCount) {
case 15:
case 16:
/* SDL_PIXELFORMAT_RGB555 or SDL_PIXELFORMAT_ARGB1555 if Amask */
Rmask = 0x7C00;
Gmask = 0x03E0;
Bmask = 0x001F;
break;
case 24:
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
/* SDL_PIXELFORMAT_RGB24 */
Rmask = 0x000000FF;
Gmask = 0x0000FF00;
Bmask = 0x00FF0000;
#else
/* SDL_PIXELFORMAT_BGR24 */
Rmask = 0x00FF0000;
Gmask = 0x0000FF00;
Bmask = 0x000000FF;
#endif
break;
case 32:
/* We don't know if this has alpha channel or not */
correctAlpha = SDL_TRUE;
/* SDL_PIXELFORMAT_RGBA8888 */
Amask = 0xFF000000;
Rmask = 0x00FF0000;
Gmask = 0x0000FF00;
Bmask = 0x000000FF;
break;
default:
break;
}
break;
case BI_BITFIELDS:
break; /* we handled this in the info header. */
default:
break;
}
/* Create a compatible surface, note that the colors are RGB ordered */
{
Uint32 format;
/* Get the pixel format */
format = SDL_GetPixelFormatEnumForMasks(biBitCount, Rmask, Gmask, Bmask, Amask);
surface = SDL_CreateSurface(biWidth, biHeight, format);
if (surface == NULL) {
was_error = SDL_TRUE;
goto done;
}
}
/* Load the palette, if any */
palette = (surface->format)->palette;
if (palette) {
if (SDL_RWseek(src, fp_offset + 14 + biSize, SDL_RW_SEEK_SET) < 0) {
SDL_Error(SDL_EFSEEK);
was_error = SDL_TRUE;
goto done;
}
if (biBitCount >= 32) { /* we shift biClrUsed by this value later. */
SDL_SetError("Unsupported or incorrect biBitCount field");
was_error = SDL_TRUE;
goto done;
}
if (biClrUsed == 0) {
biClrUsed = 1 << biBitCount;
}
if (biClrUsed > (Uint32)palette->ncolors) {
biClrUsed = 1 << biBitCount; /* try forcing it? */
if (biClrUsed > (Uint32)palette->ncolors) {
SDL_SetError("Unsupported or incorrect biClrUsed field");
was_error = SDL_TRUE;
goto done;
}
}
if (biSize == 12) {
for (i = 0; i < (int)biClrUsed; ++i) {
/* !!! FIXME: this should check for i/o errors! */
SDL_RWread(src, &palette->colors[i].b, 1);
SDL_RWread(src, &palette->colors[i].g, 1);
SDL_RWread(src, &palette->colors[i].r, 1);
palette->colors[i].a = SDL_ALPHA_OPAQUE;
}
} else {
for (i = 0; i < (int)biClrUsed; ++i) {
/* !!! FIXME: this should check for i/o errors! */
SDL_RWread(src, &palette->colors[i].b, 1);
SDL_RWread(src, &palette->colors[i].g, 1);
SDL_RWread(src, &palette->colors[i].r, 1);
SDL_RWread(src, &palette->colors[i].a, 1);
/* According to Microsoft documentation, the fourth element
is reserved and must be zero, so we shouldn't treat it as
alpha.
*/
palette->colors[i].a = SDL_ALPHA_OPAQUE;
}
}
palette->ncolors = biClrUsed;
}
/* Read the surface pixels. Note that the bmp image is upside down */
if (SDL_RWseek(src, fp_offset + bfOffBits, SDL_RW_SEEK_SET) < 0) {
SDL_Error(SDL_EFSEEK);
was_error = SDL_TRUE;
goto done;
}
if ((biCompression == BI_RLE4) || (biCompression == BI_RLE8)) {
was_error = readRlePixels(surface, src, biCompression == BI_RLE8);
if (was_error) {
SDL_Error(SDL_EFREAD);
}
goto done;
}
top = (Uint8 *)surface->pixels;
end = (Uint8 *)surface->pixels + (surface->h * surface->pitch);
switch (ExpandBMP) {
case 1:
bmpPitch = (biWidth + 7) >> 3;
pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
break;
case 2:
bmpPitch = (biWidth + 3) >> 2;
pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
break;
case 4:
bmpPitch = (biWidth + 1) >> 1;
pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
break;
default:
pad = ((surface->pitch % 4) ? (4 - (surface->pitch % 4)) : 0);
break;
}
if (topDown) {
bits = top;
} else {
bits = end - surface->pitch;
}
while (bits >= top && bits < end) {
switch (ExpandBMP) {
case 1:
case 2:
case 4:
{
Uint8 pixel = 0;
int shift = (8 - ExpandBMP);
for (i = 0; i < surface->w; ++i) {
if (i % (8 / ExpandBMP) == 0) {
if (SDL_RWread(src, &pixel, 1) != 1) {
SDL_Error(SDL_EFREAD);
was_error = SDL_TRUE;
goto done;
}
}
bits[i] = (pixel >> shift);
if (bits[i] >= biClrUsed) {
SDL_SetError("A BMP image contains a pixel with a color out of the palette");
was_error = SDL_TRUE;
goto done;
}
pixel <<= ExpandBMP;
}
} break;
default:
if (SDL_RWread(src, bits, surface->pitch) != surface->pitch) {
SDL_Error(SDL_EFREAD);
was_error = SDL_TRUE;
goto done;
}
if (biBitCount == 8 && palette && biClrUsed < (1u << biBitCount)) {
for (i = 0; i < surface->w; ++i) {
if (bits[i] >= biClrUsed) {
SDL_SetError("A BMP image contains a pixel with a color out of the palette");
was_error = SDL_TRUE;
goto done;
}
}
}
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
/* Byte-swap the pixels if needed. Note that the 24bpp
case has already been taken care of above. */
switch (biBitCount) {
case 15:
case 16:
{
Uint16 *pix = (Uint16 *)bits;
for (i = 0; i < surface->w; i++) {
pix[i] = SDL_Swap16(pix[i]);
}
break;
}
case 32:
{
Uint32 *pix = (Uint32 *)bits;
for (i = 0; i < surface->w; i++) {
pix[i] = SDL_Swap32(pix[i]);
}
break;
}
}
#endif
break;
}
/* Skip padding bytes, ugh */
if (pad) {
Uint8 padbyte;
for (i = 0; i < pad; ++i) {
SDL_RWread(src, &padbyte, 1);
}
}
if (topDown) {
bits += surface->pitch;
} else {
bits -= surface->pitch;
}
}
if (correctAlpha) {
CorrectAlphaChannel(surface);
}
done:
if (was_error) {
if (src) {
SDL_RWseek(src, fp_offset, SDL_RW_SEEK_SET);
}
SDL_DestroySurface(surface);
surface = NULL;
}
if (freesrc && src) {
SDL_RWclose(src);
}
return surface;
}
SDL_Surface *SDL_LoadBMP(const char *file)
{
return SDL_LoadBMP_RW(SDL_RWFromFile(file, "rb"), 1);
}
int SDL_SaveBMP_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst)
{
/* !!! FIXME: this calls SDL_ClearError() and then checks if an error happened during this function to
!!! FIXME: decide if there was a problem, but there's risk of innocent things setting an error
!!! FIXME: string for innocent unrelated reasons, and also, an app supplying its own RWops
!!! FIXME: implementation may not set the error string on failure. We should check for i/o
!!! FIXME: failures as we go, and return early if one occurs. */
Sint64 fp_offset;
int i, pad;
SDL_Surface *intermediate_surface;
Uint8 *bits;
SDL_bool save32bit = SDL_FALSE;
SDL_bool saveLegacyBMP = SDL_FALSE;
/* The Win32 BMP file header (14 bytes) */
char magic[2] = { 'B', 'M' };
Uint32 bfSize;
Uint16 bfReserved1;
Uint16 bfReserved2;
Uint32 bfOffBits;
/* The Win32 BITMAPINFOHEADER struct (40 bytes) */
Uint32 biSize;
Sint32 biWidth;
Sint32 biHeight;
Uint16 biPlanes;
Uint16 biBitCount;
Uint32 biCompression;
Uint32 biSizeImage;
Sint32 biXPelsPerMeter;
Sint32 biYPelsPerMeter;
Uint32 biClrUsed;
Uint32 biClrImportant;
/* The additional header members from the Win32 BITMAPV4HEADER struct (108 bytes in total) */
Uint32 bV4RedMask = 0;
Uint32 bV4GreenMask = 0;
Uint32 bV4BlueMask = 0;
Uint32 bV4AlphaMask = 0;
Uint32 bV4CSType = 0;
Sint32 bV4Endpoints[3 * 3] = { 0 };
Uint32 bV4GammaRed = 0;
Uint32 bV4GammaGreen = 0;
Uint32 bV4GammaBlue = 0;
/* Make sure we have somewhere to save */
intermediate_surface = NULL;
if (dst) {
#ifdef SAVE_32BIT_BMP
/* We can save alpha information in a 32-bit BMP */
if (surface->format->BitsPerPixel >= 8 &&
(surface->format->Amask != 0 ||
surface->map->info.flags & SDL_COPY_COLORKEY)) {
save32bit = SDL_TRUE;
}
#endif /* SAVE_32BIT_BMP */
if (surface->format->palette != NULL && !save32bit) {
if (surface->format->BitsPerPixel == 8) {
intermediate_surface = surface;
} else {
SDL_SetError("%d bpp BMP files not supported",
surface->format->BitsPerPixel);
}
} else if ((surface->format->BitsPerPixel == 24) && !save32bit &&
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
(surface->format->Rmask == 0x00FF0000) &&
(surface->format->Gmask == 0x0000FF00) &&
(surface->format->Bmask == 0x000000FF)
#else
(surface->format->Rmask == 0x000000FF) &&
(surface->format->Gmask == 0x0000FF00) &&
(surface->format->Bmask == 0x00FF0000)
#endif
) {
intermediate_surface = surface;
} else {
SDL_PixelFormat 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) {
SDL_InitFormat(&format, SDL_PIXELFORMAT_BGRA32);
} else {
SDL_InitFormat(&format, SDL_PIXELFORMAT_BGR24);
}
intermediate_surface = SDL_ConvertSurface(surface, &format);
if (intermediate_surface == NULL) {
SDL_SetError("Couldn't convert image to %d bpp",
format.BitsPerPixel);
}
}
} else {
/* Set no error here because it may overwrite a more useful message from
SDL_RWFromFile() if SDL_SaveBMP_RW() is called from SDL_SaveBMP(). */
return -1;
}
if (save32bit) {
saveLegacyBMP = SDL_GetHintBoolean(SDL_HINT_BMP_SAVE_LEGACY_FORMAT, SDL_FALSE);
}
if (intermediate_surface && (SDL_LockSurface(intermediate_surface) == 0)) {
const int bw = intermediate_surface->w * intermediate_surface->format->BytesPerPixel;
/* Set the BMP file header values */
bfSize = 0; /* We'll write this when we're done */
bfReserved1 = 0;
bfReserved2 = 0;
bfOffBits = 0; /* We'll write this when we're done */
/* Write the BMP file header values */
fp_offset = SDL_RWtell(dst);
SDL_ClearError();
SDL_RWwrite(dst, magic, 2);
SDL_WriteLE32(dst, bfSize);
SDL_WriteLE16(dst, bfReserved1);
SDL_WriteLE16(dst, bfReserved2);
SDL_WriteLE32(dst, bfOffBits);
/* Set the BMP info values */
biSize = 40;
biWidth = intermediate_surface->w;
biHeight = intermediate_surface->h;
biPlanes = 1;
biBitCount = intermediate_surface->format->BitsPerPixel;
biCompression = BI_RGB;
biSizeImage = intermediate_surface->h * intermediate_surface->pitch;
biXPelsPerMeter = 0;
biYPelsPerMeter = 0;
if (intermediate_surface->format->palette) {
biClrUsed = intermediate_surface->format->palette->ncolors;
} else {
biClrUsed = 0;
}
biClrImportant = 0;
/* Set the BMP info values for the version 4 header */
if (save32bit && !saveLegacyBMP) {
biSize = 108;
biCompression = BI_BITFIELDS;
/* The BMP format is always little endian, these masks stay the same */
bV4RedMask = 0x00ff0000;
bV4GreenMask = 0x0000ff00;
bV4BlueMask = 0x000000ff;
bV4AlphaMask = 0xff000000;
bV4CSType = LCS_WINDOWS_COLOR_SPACE;
bV4GammaRed = 0;
bV4GammaGreen = 0;
bV4GammaBlue = 0;
}
/* Write the BMP info values */
SDL_WriteLE32(dst, biSize);
SDL_WriteLE32(dst, biWidth);
SDL_WriteLE32(dst, biHeight);
SDL_WriteLE16(dst, biPlanes);
SDL_WriteLE16(dst, biBitCount);
SDL_WriteLE32(dst, biCompression);
SDL_WriteLE32(dst, biSizeImage);
SDL_WriteLE32(dst, biXPelsPerMeter);
SDL_WriteLE32(dst, biYPelsPerMeter);
SDL_WriteLE32(dst, biClrUsed);
SDL_WriteLE32(dst, biClrImportant);
/* Write the BMP info values for the version 4 header */
if (save32bit && !saveLegacyBMP) {
SDL_WriteLE32(dst, bV4RedMask);
SDL_WriteLE32(dst, bV4GreenMask);
SDL_WriteLE32(dst, bV4BlueMask);
SDL_WriteLE32(dst, bV4AlphaMask);
SDL_WriteLE32(dst, bV4CSType);
for (i = 0; i < 3 * 3; i++) {
SDL_WriteLE32(dst, bV4Endpoints[i]);
}
SDL_WriteLE32(dst, bV4GammaRed);
SDL_WriteLE32(dst, bV4GammaGreen);
SDL_WriteLE32(dst, bV4GammaBlue);
}
/* Write the palette (in BGR color order) */
if (intermediate_surface->format->palette) {
SDL_Color *colors;
int ncolors;
colors = intermediate_surface->format->palette->colors;
ncolors = intermediate_surface->format->palette->ncolors;
for (i = 0; i < ncolors; ++i) {
SDL_RWwrite(dst, &colors[i].b, 1);
SDL_RWwrite(dst, &colors[i].g, 1);
SDL_RWwrite(dst, &colors[i].r, 1);
SDL_RWwrite(dst, &colors[i].a, 1);
}
}
/* Write the bitmap offset */
bfOffBits = (Uint32)(SDL_RWtell(dst) - fp_offset);
if (SDL_RWseek(dst, fp_offset + 10, SDL_RW_SEEK_SET) < 0) {
SDL_Error(SDL_EFSEEK);
}
SDL_WriteLE32(dst, bfOffBits);
if (SDL_RWseek(dst, fp_offset + bfOffBits, SDL_RW_SEEK_SET) < 0) {
SDL_Error(SDL_EFSEEK);
}
/* Write the bitmap image upside down */
bits = (Uint8 *)intermediate_surface->pixels + (intermediate_surface->h * intermediate_surface->pitch);
pad = ((bw % 4) ? (4 - (bw % 4)) : 0);
while (bits > (Uint8 *)intermediate_surface->pixels) {
bits -= intermediate_surface->pitch;
if (SDL_RWwrite(dst, bits, bw) != bw) {
SDL_Error(SDL_EFWRITE);
break;
}
if (pad) {
const Uint8 padbyte = 0;
for (i = 0; i < pad; ++i) {
SDL_RWwrite(dst, &padbyte, 1);
}
}
}
/* Write the BMP file size */
bfSize = (Uint32)(SDL_RWtell(dst) - fp_offset);
if (SDL_RWseek(dst, fp_offset + 2, SDL_RW_SEEK_SET) < 0) {
SDL_Error(SDL_EFSEEK);
}
SDL_WriteLE32(dst, bfSize);
if (SDL_RWseek(dst, fp_offset + bfSize, SDL_RW_SEEK_SET) < 0) {
SDL_Error(SDL_EFSEEK);
}
/* Close it up.. */
SDL_UnlockSurface(intermediate_surface);
if (intermediate_surface != surface) {
SDL_DestroySurface(intermediate_surface);
}
}
if (freedst && dst) {
SDL_RWclose(dst);
}
return (SDL_strcmp(SDL_GetError(), "") == 0) ? 0 : -1;
}
int SDL_SaveBMP(SDL_Surface *surface, const char *file)
{
return SDL_SaveBMP_RW(surface, SDL_RWFromFile(file, "wb"), 1);
}

View File

@ -0,0 +1,400 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_clipboard_c.h"
#include "SDL_sysvideo.h"
#include "../events/SDL_clipboardevents_c.h"
void SDL_CancelClipboardData(Uint32 sequence)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
size_t i;
if (sequence != _this->clipboard_sequence) {
/* This clipboard data was already canceled */
return;
}
if (_this->clipboard_cleanup) {
_this->clipboard_cleanup(_this->clipboard_userdata);
}
if (_this->clipboard_mime_types) {
for (i = 0; i < _this->num_clipboard_mime_types; ++i) {
SDL_free(_this->clipboard_mime_types[i]);
}
SDL_free(_this->clipboard_mime_types);
_this->clipboard_mime_types = NULL;
_this->num_clipboard_mime_types = 0;
}
_this->clipboard_callback = NULL;
_this->clipboard_cleanup = NULL;
_this->clipboard_userdata = NULL;
}
int SDL_SetClipboardData(SDL_ClipboardDataCallback callback, SDL_ClipboardCleanupCallback cleanup, void *userdata, const char **mime_types, size_t num_mime_types)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
size_t i;
if (_this == NULL) {
return SDL_SetError("Video subsystem must be initialized to set clipboard text");
}
/* Parameter validation */
if (!((callback && mime_types && num_mime_types > 0) ||
(!callback && !mime_types && num_mime_types == 0))) {
return SDL_SetError("Invalid parameters");
}
if (!callback && !_this->clipboard_callback) {
/* Nothing to do, don't modify the system clipboard */
return 0;
}
SDL_CancelClipboardData(_this->clipboard_sequence);
++_this->clipboard_sequence;
if (!_this->clipboard_sequence) {
_this->clipboard_sequence = 1;
}
_this->clipboard_callback = callback;
_this->clipboard_cleanup = cleanup;
_this->clipboard_userdata = userdata;
if (mime_types && num_mime_types > 0) {
size_t num_allocated = 0;
_this->clipboard_mime_types = (char **)SDL_malloc(num_mime_types * sizeof(char *));
if (_this->clipboard_mime_types) {
for (i = 0; i < num_mime_types; ++i) {
_this->clipboard_mime_types[i] = SDL_strdup(mime_types[i]);
if (_this->clipboard_mime_types[i]) {
++num_allocated;
}
}
}
if (num_allocated < num_mime_types) {
SDL_ClearClipboardData();
return SDL_OutOfMemory();
}
_this->num_clipboard_mime_types = num_mime_types;
}
if (_this->SetClipboardData) {
if (_this->SetClipboardData(_this) < 0) {
return -1;
}
} else if (_this->SetClipboardText) {
char *text = NULL;
size_t size;
for (i = 0; i < num_mime_types; ++i) {
const char *mime_type = _this->clipboard_mime_types[i];
if (SDL_IsTextMimeType(mime_type)) {
const void *data = _this->clipboard_callback(_this->clipboard_userdata, mime_type, &size);
if (data) {
text = (char *)SDL_malloc(size + 1);
SDL_memcpy(text, data, size);
text[size] = '\0';
if (_this->SetClipboardText(_this, text) < 0) {
SDL_free(text);
return -1;
}
break;
}
}
}
if (text) {
SDL_free(text);
} else {
if (_this->SetClipboardText(_this, "") < 0) {
return -1;
}
}
}
SDL_SendClipboardUpdate();
return 0;
}
int SDL_ClearClipboardData(void)
{
return SDL_SetClipboardData(NULL, NULL, NULL, NULL, 0);
}
void *SDL_GetInternalClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size)
{
void *data = NULL;
if (_this->clipboard_callback) {
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 */
data = SDL_malloc(*size + sizeof(Uint32));
if (data) {
SDL_memcpy(data, provided_data, *size);
SDL_memset((Uint8 *)data + *size, 0, sizeof(Uint32));
} else {
SDL_OutOfMemory();
}
}
}
return data;
}
void *SDL_GetClipboardData(const char *mime_type, size_t *size)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (_this == NULL) {
SDL_SetError("Video subsystem must be initialized to get clipboard data");
return NULL;
}
if (!mime_type) {
SDL_InvalidParamError("mime_type");
return NULL;
}
if (!size) {
SDL_InvalidParamError("size");
return NULL;
}
/* Initialize size to empty, so implementations don't have to worry about it */
*size = 0;
if (_this->GetClipboardData) {
return _this->GetClipboardData(_this, mime_type, size);
} else if (_this->GetClipboardText && SDL_IsTextMimeType(mime_type)) {
void *data = _this->GetClipboardText(_this);
if (data && *(char *)data == '\0') {
SDL_free(data);
data = NULL;
}
return data;
} else {
return SDL_GetInternalClipboardData(_this, mime_type, size);
}
}
SDL_bool SDL_HasInternalClipboardData(SDL_VideoDevice *_this, const char *mime_type)
{
size_t i;
for (i = 0; i < _this->num_clipboard_mime_types; ++i) {
if (SDL_strcmp(mime_type, _this->clipboard_mime_types[i]) == 0) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
SDL_bool SDL_HasClipboardData(const char *mime_type)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (_this == NULL) {
SDL_SetError("Video subsystem must be initialized to check clipboard data");
return SDL_FALSE;
}
if (!mime_type) {
SDL_InvalidParamError("mime_type");
return SDL_FALSE;
}
if (_this->HasClipboardData) {
return _this->HasClipboardData(_this, mime_type);
} else if (_this->HasClipboardText && SDL_IsTextMimeType(mime_type)) {
return _this->HasClipboardText(_this);
} else {
return SDL_HasInternalClipboardData(_this, mime_type);
}
}
/* Clipboard text */
SDL_bool SDL_IsTextMimeType(const char *mime_type)
{
return (SDL_strncmp(mime_type, "text", 4) == 0);
}
static const char **SDL_GetTextMimeTypes(SDL_VideoDevice *_this, size_t *num_mime_types)
{
if (_this->GetTextMimeTypes) {
return _this->GetTextMimeTypes(_this, num_mime_types);
} else {
static const char *text_mime_types[] = {
"text/plain;charset=utf-8"
};
*num_mime_types = SDL_arraysize(text_mime_types);
return text_mime_types;
}
}
const void *SDL_ClipboardTextCallback(void *userdata, const char *mime_type, size_t *size)
{
char *text = (char *)userdata;
if (text) {
*size = SDL_strlen(text);
} else {
*size = 0;
}
return text;
}
int SDL_SetClipboardText(const char *text)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
size_t num_mime_types;
const char **text_mime_types;
if (_this == NULL) {
return SDL_SetError("Video subsystem must be initialized to set clipboard text");
}
if (text && *text) {
text_mime_types = SDL_GetTextMimeTypes(_this, &num_mime_types);
return SDL_SetClipboardData(SDL_ClipboardTextCallback, SDL_free, SDL_strdup(text), text_mime_types, num_mime_types);
} else {
return SDL_ClearClipboardData();
}
}
char *SDL_GetClipboardText(void)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
size_t i, num_mime_types;
const char **text_mime_types;
size_t length;
char *text = NULL;
if (_this == NULL) {
SDL_SetError("Video subsystem must be initialized to get clipboard text");
return SDL_strdup("");
}
text_mime_types = SDL_GetTextMimeTypes(_this, &num_mime_types);
for (i = 0; i < num_mime_types; ++i) {
text = SDL_GetClipboardData(text_mime_types[i], &length);
if (text) {
break;
}
}
if (!text) {
text = SDL_strdup("");
}
return text;
}
SDL_bool SDL_HasClipboardText(void)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
size_t i, num_mime_types;
const char **text_mime_types;
if (_this == NULL) {
SDL_SetError("Video subsystem must be initialized to check clipboard text");
return SDL_FALSE;
}
text_mime_types = SDL_GetTextMimeTypes(_this, &num_mime_types);
for (i = 0; i < num_mime_types; ++i) {
if (SDL_HasClipboardData(text_mime_types[i])) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
/* Primary selection text */
int SDL_SetPrimarySelectionText(const char *text)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (_this == NULL) {
return SDL_SetError("Video subsystem must be initialized to set primary selection text");
}
if (text == NULL) {
text = "";
}
if (_this->SetPrimarySelectionText) {
if (_this->SetPrimarySelectionText(_this, text) < 0) {
return -1;
}
} else {
SDL_free(_this->primary_selection_text);
_this->primary_selection_text = SDL_strdup(text);
}
SDL_SendClipboardUpdate();
return 0;
}
char *SDL_GetPrimarySelectionText(void)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (_this == NULL) {
SDL_SetError("Video subsystem must be initialized to get primary selection text");
return SDL_strdup("");
}
if (_this->GetPrimarySelectionText) {
return _this->GetPrimarySelectionText(_this);
} else {
const char *text = _this->primary_selection_text;
if (text == NULL) {
text = "";
}
return SDL_strdup(text);
}
}
SDL_bool SDL_HasPrimarySelectionText(void)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
if (_this == NULL) {
SDL_SetError("Video subsystem must be initialized to check primary selection text");
return SDL_FALSE;
}
if (_this->HasPrimarySelectionText) {
return _this->HasPrimarySelectionText(_this);
} else {
if (_this->primary_selection_text && _this->primary_selection_text[0] != '\0') {
return SDL_TRUE;
} else {
return SDL_FALSE;
}
}
}

View File

@ -0,0 +1,42 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_clipboard_c_h_
#define SDL_clipboard_c_h_
#include "SDL_sysvideo.h"
/* Return true if the mime type is valid clipboard text */
extern SDL_bool SDL_IsTextMimeType(const char *mime_type);
/* Cancel the clipboard data callback, called internally for cleanup */
extern void SDL_CancelClipboardData(Uint32 sequence);
/* Call the clipboard callback for application data */
extern void *SDL_GetInternalClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size);
extern SDL_bool SDL_HasInternalClipboardData(SDL_VideoDevice *_this, const char *mime_type);
/* General purpose clipboard text callback */
const void *SDL_ClipboardTextCallback(void *userdata, const char *mime_type, size_t *size);
#endif /* SDL_clipboard_c_h_ */

1343
external/sdl/SDL/src/video/SDL_egl.c vendored Normal file

File diff suppressed because it is too large Load Diff

170
external/sdl/SDL/src/video/SDL_egl_c.h vendored Normal file
View File

@ -0,0 +1,170 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_egl_h_
#define SDL_egl_h_
#ifdef SDL_VIDEO_OPENGL_EGL
#include <SDL3/SDL_egl.h>
#include "SDL_sysvideo.h"
#define SDL_EGL_MAX_DEVICES 8
/* For systems that don't define these */
typedef intptr_t EGLAttrib;
typedef void *EGLDeviceEXT;
typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETDISPLAYPROC) (EGLNativeDisplayType display_id);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLINITIALIZEPROC) (EGLDisplay dpy, EGLint *major, EGLint *minor);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLTERMINATEPROC) (EGLDisplay dpy);
typedef __eglMustCastToProperFunctionPointerType (EGLAPIENTRYP PFNEGLGETPROCADDRESSPROC) (const char *procname);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLCHOOSECONFIGPROC) (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
typedef EGLContext (EGLAPIENTRYP PFNEGLCREATECONTEXTPROC) (EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYCONTEXTPROC) (EGLDisplay dpy, EGLContext ctx);
typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPBUFFERSURFACEPROC) (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEWINDOWSURFACEPROC) (EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSURFACEPROC) (EGLDisplay dpy, EGLSurface surface);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLMAKECURRENTPROC) (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSPROC) (EGLDisplay dpy, EGLSurface surface);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPINTERVALPROC) (EGLDisplay dpy, EGLint interval);
typedef const char *(EGLAPIENTRYP PFNEGLQUERYSTRINGPROC) (EGLDisplay dpy, EGLint name);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCONFIGATTRIBPROC) (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITNATIVEPROC) (EGLint engine);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITGLPROC) (void);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDAPIPROC) (EGLenum api);
typedef EGLint (EGLAPIENTRYP PFNEGLGETERRORPROC) (void);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEVICESEXTPROC) (EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices);
typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYPROC) (EGLenum platform, void *native_display, const EGLAttrib *attrib_list);
typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync);
typedef EGLint (EGLAPIENTRYP PFNEGLDUPNATIVEFENCEFDANDROIDPROC) (EGLDisplay dpy, EGLSyncKHR sync);
typedef EGLint (EGLAPIENTRYP PFNEGLWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
typedef struct SDL_EGL_VideoData
{
void *opengl_dll_handle, *egl_dll_handle;
EGLDisplay egl_display;
EGLConfig egl_config;
int egl_swapinterval;
int egl_surfacetype;
int egl_version_major, egl_version_minor;
EGLint egl_required_visual_id;
SDL_bool is_offscreen; /* whether EGL display was offscreen */
EGLenum apitype; /* EGL_OPENGL_ES_API, EGL_OPENGL_API, etc */
PFNEGLGETDISPLAYPROC eglGetDisplay;
PFNEGLINITIALIZEPROC eglInitialize;
PFNEGLTERMINATEPROC eglTerminate;
PFNEGLGETPROCADDRESSPROC eglGetProcAddress;
PFNEGLCHOOSECONFIGPROC eglChooseConfig;
PFNEGLCREATECONTEXTPROC eglCreateContext;
PFNEGLDESTROYCONTEXTPROC eglDestroyContext;
PFNEGLCREATEPBUFFERSURFACEPROC eglCreatePbufferSurface;
PFNEGLCREATEWINDOWSURFACEPROC eglCreateWindowSurface;
PFNEGLDESTROYSURFACEPROC eglDestroySurface;
PFNEGLMAKECURRENTPROC eglMakeCurrent;
PFNEGLSWAPBUFFERSPROC eglSwapBuffers;
PFNEGLSWAPINTERVALPROC eglSwapInterval;
PFNEGLQUERYSTRINGPROC eglQueryString;
PFNEGLGETCONFIGATTRIBPROC eglGetConfigAttrib;
PFNEGLWAITNATIVEPROC eglWaitNative;
PFNEGLWAITGLPROC eglWaitGL;
PFNEGLBINDAPIPROC eglBindAPI;
PFNEGLGETERRORPROC eglGetError;
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT;
PFNEGLGETPLATFORMDISPLAYPROC eglGetPlatformDisplay;
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
/* Atomic functions */
PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR;
PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR;
PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID;
PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR;
PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR;
/* Atomic functions end */
} SDL_EGL_VideoData;
/* OpenGLES functions */
typedef enum SDL_EGL_ExtensionType
{
SDL_EGL_DISPLAY_EXTENSION,
SDL_EGL_CLIENT_EXTENSION
} SDL_EGL_ExtensionType;
extern SDL_bool SDL_EGL_HasExtension(SDL_VideoDevice *_this, SDL_EGL_ExtensionType type, const char *ext);
extern int SDL_EGL_GetAttribute(SDL_VideoDevice *_this, SDL_GLattr attrib, int *value);
/* SDL_EGL_LoadLibrary can get a display for a specific platform (EGL_PLATFORM_*)
* or, if 0 is passed, let the implementation decide.
*/
extern int SDL_EGL_LoadLibraryOnly(SDL_VideoDevice *_this, const char *path);
extern int SDL_EGL_LoadLibrary(SDL_VideoDevice *_this, const char *path, NativeDisplayType native_display, EGLenum platform);
extern SDL_FunctionPointer SDL_EGL_GetProcAddressInternal(SDL_VideoDevice *_this, const char *proc);
extern void SDL_EGL_UnloadLibrary(SDL_VideoDevice *_this);
extern void SDL_EGL_SetRequiredVisualId(SDL_VideoDevice *_this, int visual_id);
extern int SDL_EGL_ChooseConfig(SDL_VideoDevice *_this);
extern int SDL_EGL_SetSwapInterval(SDL_VideoDevice *_this, int interval);
extern int SDL_EGL_GetSwapInterval(SDL_VideoDevice *_this, int *interval);
extern int SDL_EGL_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context);
extern EGLSurface *SDL_EGL_CreateSurface(SDL_VideoDevice *_this, SDL_Window *window, NativeWindowType nw);
extern void SDL_EGL_DestroySurface(SDL_VideoDevice *_this, EGLSurface egl_surface);
extern EGLSurface SDL_EGL_CreateOffscreenSurface(SDL_VideoDevice *_this, int width, int height);
/* Assumes that LoadLibraryOnly() has succeeded */
extern int SDL_EGL_InitializeOffscreen(SDL_VideoDevice *_this, int device);
/* These need to be wrapped to get the surface for the window by the platform GLES implementation */
extern SDL_GLContext SDL_EGL_CreateContext(SDL_VideoDevice *_this, EGLSurface egl_surface);
extern int SDL_EGL_MakeCurrent(SDL_VideoDevice *_this, EGLSurface egl_surface, SDL_GLContext context);
extern int SDL_EGL_SwapBuffers(SDL_VideoDevice *_this, EGLSurface egl_surface);
/* SDL Error-reporting */
extern int SDL_EGL_SetErrorEx(const char *message, const char *eglFunctionName, EGLint eglErrorCode);
#define SDL_EGL_SetError(message, eglFunctionName) SDL_EGL_SetErrorEx(message, eglFunctionName, _this->egl_data->eglGetError())
/* A few of useful macros */
#define SDL_EGL_SwapWindow_impl(BACKEND) \
int BACKEND##_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) \
{ \
return SDL_EGL_SwapBuffers(_this, window->driverdata->egl_surface); \
}
#define SDL_EGL_MakeCurrent_impl(BACKEND) \
int BACKEND##_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context) \
{ \
return SDL_EGL_MakeCurrent(_this, window ? window->driverdata->egl_surface : EGL_NO_SURFACE, context); \
}
#define SDL_EGL_CreateContext_impl(BACKEND) \
SDL_GLContext BACKEND##_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window) \
{ \
return SDL_EGL_CreateContext(_this, window->driverdata->egl_surface); \
}
#endif /* SDL_VIDEO_OPENGL_EGL */
#endif /* SDL_egl_h_ */

View File

@ -0,0 +1,442 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_blit.h"
#ifdef SDL_SSE_INTRINSICS
/* *INDENT-OFF* */ /* clang-format off */
#if defined(_MSC_VER) && !defined(__clang__)
#define SSE_BEGIN \
__m128 c128; \
c128.m128_u32[0] = color; \
c128.m128_u32[1] = color; \
c128.m128_u32[2] = color; \
c128.m128_u32[3] = color;
#else
#define SSE_BEGIN \
__m128 c128; \
DECLARE_ALIGNED(Uint32, cccc[4], 16); \
cccc[0] = color; \
cccc[1] = color; \
cccc[2] = color; \
cccc[3] = color; \
c128 = *(__m128 *)cccc;
#endif
#define SSE_WORK \
for (i = n / 64; i--;) { \
_mm_stream_ps((float *)(p+0), c128); \
_mm_stream_ps((float *)(p+16), c128); \
_mm_stream_ps((float *)(p+32), c128); \
_mm_stream_ps((float *)(p+48), c128); \
p += 64; \
}
#define SSE_END
#define DEFINE_SSE_FILLRECT(bpp, type) \
static void SDL_TARGETING("sse") SDL_FillSurfaceRect##bpp##SSE(Uint8 *pixels, int pitch, Uint32 color, int w, int h) \
{ \
int i, n; \
Uint8 *p = NULL; \
\
SSE_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); \
} \
} \
SSE_WORK; \
} \
if (n & 63) { \
int remainder = (n & 63); \
remainder /= (bpp); \
while (remainder--) { \
*((type *)p) = (type)color; \
p += (bpp); \
} \
} \
pixels += pitch; \
} \
\
SSE_END; \
}
static void SDL_TARGETING("sse") SDL_FillSurfaceRect1SSE(Uint8 *pixels, int pitch, Uint32 color, int w, int h)
{
int i, n;
SSE_BEGIN;
while (h--) {
Uint8 *p = pixels;
n = w;
if (n > 63) {
int adjust = 16 - ((uintptr_t)p & 15);
if (adjust) {
n -= adjust;
SDL_memset(p, color, adjust);
p += adjust;
}
SSE_WORK;
}
if (n & 63) {
int remainder = (n & 63);
SDL_memset(p, color, remainder);
}
pixels += pitch;
}
SSE_END;
}
/* DEFINE_SSE_FILLRECT(1, Uint8) */
DEFINE_SSE_FILLRECT(2, Uint16)
DEFINE_SSE_FILLRECT(4, Uint32)
/* *INDENT-ON* */ /* clang-format on */
#endif /* __SSE__ */
static void SDL_FillSurfaceRect1(Uint8 *pixels, int pitch, Uint32 color, int w, int h)
{
int n;
Uint8 *p = NULL;
while (h--) {
n = w;
p = pixels;
if (n > 3) {
switch ((uintptr_t)p & 3) {
case 1:
*p++ = (Uint8)color;
--n;
SDL_FALLTHROUGH;
case 2:
*p++ = (Uint8)color;
--n;
SDL_FALLTHROUGH;
case 3:
*p++ = (Uint8)color;
--n;
}
SDL_memset4(p, color, (n >> 2));
}
if (n & 3) {
p += (n & ~3);
switch (n & 3) {
case 3:
*p++ = (Uint8)color;
SDL_FALLTHROUGH;
case 2:
*p++ = (Uint8)color;
SDL_FALLTHROUGH;
case 1:
*p++ = (Uint8)color;
}
}
pixels += pitch;
}
}
static void SDL_FillSurfaceRect2(Uint8 *pixels, int pitch, Uint32 color, int w, int h)
{
int n;
Uint16 *p = NULL;
while (h--) {
n = w;
p = (Uint16 *)pixels;
if (n > 1) {
if ((uintptr_t)p & 2) {
*p++ = (Uint16)color;
--n;
}
SDL_memset4(p, color, (n >> 1));
}
if (n & 1) {
p[n - 1] = (Uint16)color;
}
pixels += pitch;
}
}
static void SDL_FillSurfaceRect3(Uint8 *pixels, int pitch, Uint32 color, int w, int h)
{
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
Uint8 b1 = (Uint8)(color & 0xFF);
Uint8 b2 = (Uint8)((color >> 8) & 0xFF);
Uint8 b3 = (Uint8)((color >> 16) & 0xFF);
#elif SDL_BYTEORDER == SDL_BIG_ENDIAN
Uint8 b1 = (Uint8)((color >> 16) & 0xFF);
Uint8 b2 = (Uint8)((color >> 8) & 0xFF);
Uint8 b3 = (Uint8)(color & 0xFF);
#endif
int n;
Uint8 *p = NULL;
while (h--) {
n = w;
p = pixels;
while (n--) {
*p++ = b1;
*p++ = b2;
*p++ = b3;
}
pixels += pitch;
}
}
static void SDL_FillSurfaceRect4(Uint8 *pixels, int pitch, Uint32 color, int w, int h)
{
while (h--) {
SDL_memset4(pixels, color, w);
pixels += pitch;
}
}
/*
* This function performs a fast fill of the given rectangle with 'color'
*/
int SDL_FillSurfaceRect(SDL_Surface *dst, const SDL_Rect *rect, Uint32 color)
{
if (dst == NULL) {
return SDL_InvalidParamError("SDL_FillSurfaceRect(): dst");
}
/* If 'rect' == NULL, then fill the whole surface */
if (rect == NULL) {
rect = &dst->clip_rect;
/* Don't attempt to fill if the surface's clip_rect is empty */
if (SDL_RectEmpty(rect)) {
return 0;
}
}
return SDL_FillSurfaceRects(dst, rect, 1, color);
}
#ifdef SDL_ARM_NEON_BLITTERS
void FillSurfaceRect8ARMNEONAsm(int32_t w, int32_t h, uint8_t *dst, int32_t dst_stride, uint8_t src);
void FillSurfaceRect16ARMNEONAsm(int32_t w, int32_t h, uint16_t *dst, int32_t dst_stride, uint16_t src);
void FillSurfaceRect32ARMNEONAsm(int32_t w, int32_t h, uint32_t *dst, int32_t dst_stride, uint32_t src);
static void fill_8_neon(Uint8 *pixels, int pitch, Uint32 color, int w, int h)
{
FillSurfaceRect8ARMNEONAsm(w, h, (uint8_t *)pixels, pitch >> 0, color);
return;
}
static void fill_16_neon(Uint8 *pixels, int pitch, Uint32 color, int w, int h)
{
FillSurfaceRect16ARMNEONAsm(w, h, (uint16_t *)pixels, pitch >> 1, color);
return;
}
static void fill_32_neon(Uint8 *pixels, int pitch, Uint32 color, int w, int h)
{
FillSurfaceRect32ARMNEONAsm(w, h, (uint32_t *)pixels, pitch >> 2, color);
return;
}
#endif
#ifdef SDL_ARM_SIMD_BLITTERS
void FillSurfaceRect8ARMSIMDAsm(int32_t w, int32_t h, uint8_t *dst, int32_t dst_stride, uint8_t src);
void FillSurfaceRect16ARMSIMDAsm(int32_t w, int32_t h, uint16_t *dst, int32_t dst_stride, uint16_t src);
void FillSurfaceRect32ARMSIMDAsm(int32_t w, int32_t h, uint32_t *dst, int32_t dst_stride, uint32_t src);
static void fill_8_simd(Uint8 *pixels, int pitch, Uint32 color, int w, int h)
{
FillSurfaceRect8ARMSIMDAsm(w, h, (uint8_t *)pixels, pitch >> 0, color);
return;
}
static void fill_16_simd(Uint8 *pixels, int pitch, Uint32 color, int w, int h)
{
FillSurfaceRect16ARMSIMDAsm(w, h, (uint16_t *)pixels, pitch >> 1, color);
return;
}
static void fill_32_simd(Uint8 *pixels, int pitch, Uint32 color, int w, int h)
{
FillSurfaceRect32ARMSIMDAsm(w, h, (uint32_t *)pixels, pitch >> 2, color);
return;
}
#endif
int SDL_FillSurfaceRects(SDL_Surface *dst, const SDL_Rect *rects, int count,
Uint32 color)
{
SDL_Rect clipped;
Uint8 *pixels;
const SDL_Rect *rect;
void (*fill_function)(Uint8 * pixels, int pitch, Uint32 color, int w, int h) = NULL;
int i;
if (dst == NULL) {
return SDL_InvalidParamError("SDL_FillSurfaceRects(): dst");
}
/* Nothing to do */
if (dst->w == 0 || dst->h == 0) {
return 0;
}
/* Perform software fill */
if (!dst->pixels) {
return SDL_SetError("SDL_FillSurfaceRects(): You must lock the surface");
}
if (rects == NULL) {
return SDL_InvalidParamError("SDL_FillSurfaceRects(): rects");
}
/* This function doesn't usually work on surfaces < 8 bpp
* Except: support for 4bits, when filling full size.
*/
if (dst->format->BitsPerPixel < 8) {
if (count == 1) {
const SDL_Rect *r = &rects[0];
if (r->x == 0 && r->y == 0 && r->w == dst->w && r->h == dst->h) {
if (dst->format->BitsPerPixel == 4) {
Uint8 b = (((Uint8)color << 4) | (Uint8)color);
SDL_memset(dst->pixels, b, (size_t)dst->h * dst->pitch);
return 1;
}
}
}
return SDL_SetError("SDL_FillSurfaceRects(): Unsupported surface format");
}
#ifdef SDL_ARM_NEON_BLITTERS
if (SDL_HasNEON() && dst->format->BytesPerPixel != 3 && fill_function == NULL) {
switch (dst->format->BytesPerPixel) {
case 1:
fill_function = fill_8_neon;
break;
case 2:
fill_function = fill_16_neon;
break;
case 4:
fill_function = fill_32_neon;
break;
}
}
#endif
#ifdef SDL_ARM_SIMD_BLITTERS
if (SDL_HasARMSIMD() && dst->format->BytesPerPixel != 3 && fill_function == NULL) {
switch (dst->format->BytesPerPixel) {
case 1:
fill_function = fill_8_simd;
break;
case 2:
fill_function = fill_16_simd;
break;
case 4:
fill_function = fill_32_simd;
break;
}
}
#endif
if (fill_function == NULL) {
switch (dst->format->BytesPerPixel) {
case 1:
{
color |= (color << 8);
color |= (color << 16);
#ifdef SDL_SSE_INTRINSICS
if (SDL_HasSSE()) {
fill_function = SDL_FillSurfaceRect1SSE;
break;
}
#endif
fill_function = SDL_FillSurfaceRect1;
break;
}
case 2:
{
color |= (color << 16);
#ifdef SDL_SSE_INTRINSICS
if (SDL_HasSSE()) {
fill_function = SDL_FillSurfaceRect2SSE;
break;
}
#endif
fill_function = SDL_FillSurfaceRect2;
break;
}
case 3:
/* 24-bit RGB is a slow path, at least for now. */
{
fill_function = SDL_FillSurfaceRect3;
break;
}
case 4:
{
#ifdef SDL_SSE_INTRINSICS
if (SDL_HasSSE()) {
fill_function = SDL_FillSurfaceRect4SSE;
break;
}
#endif
fill_function = SDL_FillSurfaceRect4;
break;
}
default:
return SDL_SetError("Unsupported pixel format");
}
}
for (i = 0; i < count; ++i) {
rect = &rects[i];
/* Perform clipping */
if (!SDL_GetRectIntersection(rect, &dst->clip_rect, &clipped)) {
continue;
}
rect = &clipped;
pixels = (Uint8 *)dst->pixels + rect->y * dst->pitch +
rect->x * dst->format->BytesPerPixel;
fill_function(pixels, dst->pitch, color, rect->w, rect->h);
}
/* We're done! */
return 0;
}

1141
external/sdl/SDL/src/video/SDL_pixels.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_pixels_c_h_
#define SDL_pixels_c_h_
#include "SDL_internal.h"
/* Useful functions and variables from SDL_pixel.c */
#include "SDL_blit.h"
/* Pixel format functions */
extern int SDL_InitFormat(SDL_PixelFormat *format, Uint32 pixel_format);
extern int SDL_CalculateSize(Uint32 format, int width, int height, size_t *size, size_t *pitch, SDL_bool minimalPitch);
/* Blit mapping functions */
extern SDL_BlitMap *SDL_AllocBlitMap(void);
extern void SDL_InvalidateMap(SDL_BlitMap *map);
extern int SDL_MapSurface(SDL_Surface *src, SDL_Surface *dst);
extern void SDL_FreeBlitMap(SDL_BlitMap *map);
extern void SDL_InvalidateAllBlitMap(SDL_Surface *surface);
/* Miscellaneous functions */
extern void SDL_DitherColors(SDL_Color *colors, int bpp);
extern Uint8 SDL_FindColor(SDL_Palette *pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
extern void SDL_DetectPalette(SDL_Palette *pal, SDL_bool *is_opaque, SDL_bool *has_alpha_channel);
#endif /* SDL_pixels_c_h_ */

110
external/sdl/SDL/src/video/SDL_rect.c vendored Normal file
View File

@ -0,0 +1,110 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_rect_c.h"
/* There's no float version of this at the moment, because it's not a public API
and internally we only need the int version. */
SDL_bool SDL_GetSpanEnclosingRect(int width, int height,
int numrects, const SDL_Rect *rects, SDL_Rect *span)
{
int i;
int span_y1, span_y2;
int rect_y1, rect_y2;
if (width < 1) {
SDL_InvalidParamError("width");
return SDL_FALSE;
} else if (height < 1) {
SDL_InvalidParamError("height");
return SDL_FALSE;
} else if (rects == NULL) {
SDL_InvalidParamError("rects");
return SDL_FALSE;
} else if (span == NULL) {
SDL_InvalidParamError("span");
return SDL_FALSE;
} else if (numrects < 1) {
SDL_InvalidParamError("numrects");
return SDL_FALSE;
}
/* Initialize to empty rect */
span_y1 = height;
span_y2 = 0;
for (i = 0; i < numrects; ++i) {
rect_y1 = rects[i].y;
rect_y2 = rect_y1 + rects[i].h;
/* Clip out of bounds rectangles, and expand span rect */
if (rect_y1 < 0) {
span_y1 = 0;
} else if (rect_y1 < span_y1) {
span_y1 = rect_y1;
}
if (rect_y2 > height) {
span_y2 = height;
} else if (rect_y2 > span_y2) {
span_y2 = rect_y2;
}
}
if (span_y2 > span_y1) {
span->x = 0;
span->y = span_y1;
span->w = width;
span->h = (span_y2 - span_y1);
return SDL_TRUE;
}
return SDL_FALSE;
}
/* For use with the Cohen-Sutherland algorithm for line clipping, in SDL_rect_impl.h */
#define CODE_BOTTOM 1
#define CODE_TOP 2
#define CODE_LEFT 4
#define CODE_RIGHT 8
/* Same code twice, for float and int versions... */
#define RECTTYPE SDL_Rect
#define POINTTYPE SDL_Point
#define SCALARTYPE int
#define COMPUTEOUTCODE ComputeOutCode
#define SDL_HASINTERSECTION SDL_HasRectIntersection
#define SDL_INTERSECTRECT SDL_GetRectIntersection
#define SDL_RECTEMPTY SDL_RectEmpty
#define SDL_UNIONRECT SDL_GetRectUnion
#define SDL_ENCLOSEPOINTS SDL_GetRectEnclosingPoints
#define SDL_INTERSECTRECTANDLINE SDL_GetRectAndLineIntersection
#include "SDL_rect_impl.h"
#define RECTTYPE SDL_FRect
#define POINTTYPE SDL_FPoint
#define SCALARTYPE float
#define COMPUTEOUTCODE ComputeOutCodeFloat
#define SDL_HASINTERSECTION SDL_HasRectIntersectionFloat
#define SDL_INTERSECTRECT SDL_GetRectIntersectionFloat
#define SDL_RECTEMPTY SDL_RectEmptyFloat
#define SDL_UNIONRECT SDL_GetRectUnionFloat
#define SDL_ENCLOSEPOINTS SDL_GetRectEnclosingPointsFloat
#define SDL_INTERSECTRECTANDLINE SDL_GetRectAndLineIntersectionFloat
#include "SDL_rect_impl.h"

29
external/sdl/SDL/src/video/SDL_rect_c.h vendored Normal file
View File

@ -0,0 +1,29 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_rect_c_h_
#define SDL_rect_c_h_
#include "SDL_internal.h"
extern SDL_bool SDL_GetSpanEnclosingRect(int width, int height, int numrects, const SDL_Rect *rects, SDL_Rect *span);
#endif /* SDL_rect_c_h_ */

View File

@ -0,0 +1,436 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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.
*/
/* This file is #included twice to support int and float versions with the same code. */
SDL_bool SDL_HASINTERSECTION(const RECTTYPE *A, const RECTTYPE *B)
{
SCALARTYPE Amin, Amax, Bmin, Bmax;
if (A == NULL) {
SDL_InvalidParamError("A");
return SDL_FALSE;
} else if (B == NULL) {
SDL_InvalidParamError("B");
return SDL_FALSE;
} else if (SDL_RECTEMPTY(A) || SDL_RECTEMPTY(B)) {
return SDL_FALSE; /* Special cases for empty rects */
}
/* Horizontal intersection */
Amin = A->x;
Amax = Amin + A->w;
Bmin = B->x;
Bmax = Bmin + B->w;
if (Bmin > Amin) {
Amin = Bmin;
}
if (Bmax < Amax) {
Amax = Bmax;
}
if (Amax <= Amin) {
return SDL_FALSE;
}
/* Vertical intersection */
Amin = A->y;
Amax = Amin + A->h;
Bmin = B->y;
Bmax = Bmin + B->h;
if (Bmin > Amin) {
Amin = Bmin;
}
if (Bmax < Amax) {
Amax = Bmax;
}
if (Amax <= Amin) {
return SDL_FALSE;
}
return SDL_TRUE;
}
SDL_bool SDL_INTERSECTRECT(const RECTTYPE *A, const RECTTYPE *B, RECTTYPE *result)
{
SCALARTYPE Amin, Amax, Bmin, Bmax;
if (A == NULL) {
SDL_InvalidParamError("A");
return SDL_FALSE;
} else if (B == NULL) {
SDL_InvalidParamError("B");
return SDL_FALSE;
} else if (result == NULL) {
SDL_InvalidParamError("result");
return SDL_FALSE;
} else if (SDL_RECTEMPTY(A) || SDL_RECTEMPTY(B)) { /* Special cases for empty rects */
result->w = 0;
result->h = 0;
return SDL_FALSE;
}
/* Horizontal intersection */
Amin = A->x;
Amax = Amin + A->w;
Bmin = B->x;
Bmax = Bmin + B->w;
if (Bmin > Amin) {
Amin = Bmin;
}
result->x = Amin;
if (Bmax < Amax) {
Amax = Bmax;
}
result->w = Amax - Amin;
/* Vertical intersection */
Amin = A->y;
Amax = Amin + A->h;
Bmin = B->y;
Bmax = Bmin + B->h;
if (Bmin > Amin) {
Amin = Bmin;
}
result->y = Amin;
if (Bmax < Amax) {
Amax = Bmax;
}
result->h = Amax - Amin;
return !SDL_RECTEMPTY(result);
}
int SDL_UNIONRECT(const RECTTYPE *A, const RECTTYPE *B, RECTTYPE *result)
{
SCALARTYPE Amin, Amax, Bmin, Bmax;
if (A == NULL) {
return SDL_InvalidParamError("A");
} else if (B == NULL) {
return SDL_InvalidParamError("B");
} else if (result == NULL) {
return SDL_InvalidParamError("result");
} else 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 */
*result = *B;
}
return 0;
} else if (SDL_RECTEMPTY(B)) { /* A not empty, B empty */
*result = *A;
return 0;
}
/* Horizontal union */
Amin = A->x;
Amax = Amin + A->w;
Bmin = B->x;
Bmax = Bmin + B->w;
if (Bmin < Amin) {
Amin = Bmin;
}
result->x = Amin;
if (Bmax > Amax) {
Amax = Bmax;
}
result->w = Amax - Amin;
/* Vertical union */
Amin = A->y;
Amax = Amin + A->h;
Bmin = B->y;
Bmax = Bmin + B->h;
if (Bmin < Amin) {
Amin = Bmin;
}
result->y = Amin;
if (Bmax > Amax) {
Amax = Bmax;
}
result->h = Amax - Amin;
return 0;
}
SDL_bool SDL_ENCLOSEPOINTS(const POINTTYPE *points, int count, const RECTTYPE *clip,
RECTTYPE *result)
{
SCALARTYPE minx = 0;
SCALARTYPE miny = 0;
SCALARTYPE maxx = 0;
SCALARTYPE maxy = 0;
SCALARTYPE x, y;
int i;
if (points == NULL) {
SDL_InvalidParamError("points");
return SDL_FALSE;
} else if (count < 1) {
SDL_InvalidParamError("count");
return SDL_FALSE;
}
if (clip) {
SDL_bool added = SDL_FALSE;
const SCALARTYPE clip_minx = clip->x;
const SCALARTYPE clip_miny = clip->y;
const SCALARTYPE clip_maxx = clip->x + clip->w - 1;
const SCALARTYPE clip_maxy = clip->y + clip->h - 1;
/* Special case for empty rectangle */
if (SDL_RECTEMPTY(clip)) {
return SDL_FALSE;
}
for (i = 0; i < count; ++i) {
x = points[i].x;
y = points[i].y;
if (x < clip_minx || x > clip_maxx ||
y < clip_miny || y > clip_maxy) {
continue;
}
if (!added) {
/* Special case: if no result was requested, we are done */
if (result == NULL) {
return SDL_TRUE;
}
/* First point added */
minx = maxx = x;
miny = maxy = y;
added = SDL_TRUE;
continue;
}
if (x < minx) {
minx = x;
} else if (x > maxx) {
maxx = x;
}
if (y < miny) {
miny = y;
} else if (y > maxy) {
maxy = y;
}
}
if (!added) {
return SDL_FALSE;
}
} else {
/* Special case: if no result was requested, we are done */
if (result == NULL) {
return SDL_TRUE;
}
/* No clipping, always add the first point */
minx = maxx = points[0].x;
miny = maxy = points[0].y;
for (i = 1; i < count; ++i) {
x = points[i].x;
y = points[i].y;
if (x < minx) {
minx = x;
} else if (x > maxx) {
maxx = x;
}
if (y < miny) {
miny = y;
} else if (y > maxy) {
maxy = y;
}
}
}
if (result) {
result->x = minx;
result->y = miny;
result->w = (maxx - minx) + 1;
result->h = (maxy - miny) + 1;
}
return SDL_TRUE;
}
/* Use the Cohen-Sutherland algorithm for line clipping */
static int COMPUTEOUTCODE(const RECTTYPE *rect, SCALARTYPE x, SCALARTYPE y)
{
int code = 0;
if (y < rect->y) {
code |= CODE_TOP;
} else if (y >= rect->y + rect->h) {
code |= CODE_BOTTOM;
}
if (x < rect->x) {
code |= CODE_LEFT;
} else if (x >= rect->x + rect->w) {
code |= CODE_RIGHT;
}
return code;
}
SDL_bool SDL_INTERSECTRECTANDLINE(const RECTTYPE *rect, SCALARTYPE *X1, SCALARTYPE *Y1, SCALARTYPE *X2, SCALARTYPE *Y2)
{
SCALARTYPE x = 0;
SCALARTYPE y = 0;
SCALARTYPE x1, y1;
SCALARTYPE x2, y2;
SCALARTYPE rectx1;
SCALARTYPE recty1;
SCALARTYPE rectx2;
SCALARTYPE recty2;
int outcode1, outcode2;
if (rect == NULL) {
SDL_InvalidParamError("rect");
return SDL_FALSE;
} else if (X1 == NULL) {
SDL_InvalidParamError("X1");
return SDL_FALSE;
} else if (Y1 == NULL) {
SDL_InvalidParamError("Y1");
return SDL_FALSE;
} else if (X2 == NULL) {
SDL_InvalidParamError("X2");
return SDL_FALSE;
} else if (Y2 == NULL) {
SDL_InvalidParamError("Y2");
return SDL_FALSE;
} else if (SDL_RECTEMPTY(rect)) {
return SDL_FALSE; /* Special case for empty rect */
}
x1 = *X1;
y1 = *Y1;
x2 = *X2;
y2 = *Y2;
rectx1 = rect->x;
recty1 = rect->y;
rectx2 = rect->x + rect->w - 1;
recty2 = rect->y + rect->h - 1;
/* Check to see if entire line is inside rect */
if (x1 >= rectx1 && x1 <= rectx2 && x2 >= rectx1 && x2 <= rectx2 &&
y1 >= recty1 && y1 <= recty2 && y2 >= recty1 && y2 <= recty2) {
return SDL_TRUE;
}
/* Check to see if entire line is to one side of rect */
if ((x1 < rectx1 && x2 < rectx1) || (x1 > rectx2 && x2 > rectx2) ||
(y1 < recty1 && y2 < recty1) || (y1 > recty2 && y2 > recty2)) {
return SDL_FALSE;
}
if (y1 == y2) { /* Horizontal line, easy to clip */
if (x1 < rectx1) {
*X1 = rectx1;
} else if (x1 > rectx2) {
*X1 = rectx2;
}
if (x2 < rectx1) {
*X2 = rectx1;
} else if (x2 > rectx2) {
*X2 = rectx2;
}
return SDL_TRUE;
}
if (x1 == x2) { /* Vertical line, easy to clip */
if (y1 < recty1) {
*Y1 = recty1;
} else if (y1 > recty2) {
*Y1 = recty2;
}
if (y2 < recty1) {
*Y2 = recty1;
} else if (y2 > recty2) {
*Y2 = recty2;
}
return SDL_TRUE;
}
/* More complicated Cohen-Sutherland algorithm */
outcode1 = COMPUTEOUTCODE(rect, x1, y1);
outcode2 = COMPUTEOUTCODE(rect, x2, y2);
while (outcode1 || outcode2) {
if (outcode1 & outcode2) {
return SDL_FALSE;
}
if (outcode1) {
if (outcode1 & CODE_TOP) {
y = recty1;
x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
} else if (outcode1 & CODE_BOTTOM) {
y = recty2;
x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
} else if (outcode1 & CODE_LEFT) {
x = rectx1;
y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
} else if (outcode1 & CODE_RIGHT) {
x = rectx2;
y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
}
x1 = x;
y1 = y;
outcode1 = COMPUTEOUTCODE(rect, x, y);
} else {
if (outcode2 & CODE_TOP) {
SDL_assert(y2 != y1); /* if equal: division by zero. */
y = recty1;
x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
} else if (outcode2 & CODE_BOTTOM) {
SDL_assert(y2 != y1); /* if equal: division by zero. */
y = recty2;
x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
} else if (outcode2 & CODE_LEFT) {
/* If this assertion ever fires, here's the static analysis that warned about it:
http://buildbot.libsdl.org/sdl-static-analysis/sdl-macosx-static-analysis/sdl-macosx-static-analysis-1101/report-b0d01a.html#EndPath */
SDL_assert(x2 != x1); /* if equal: division by zero. */
x = rectx1;
y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
} else if (outcode2 & CODE_RIGHT) {
/* If this assertion ever fires, here's the static analysis that warned about it:
http://buildbot.libsdl.org/sdl-static-analysis/sdl-macosx-static-analysis/sdl-macosx-static-analysis-1101/report-39b114.html#EndPath */
SDL_assert(x2 != x1); /* if equal: division by zero. */
x = rectx2;
y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
}
x2 = x;
y2 = y;
outcode2 = COMPUTEOUTCODE(rect, x, y);
}
}
*X1 = x1;
*Y1 = y1;
*X2 = x2;
*Y2 = y2;
return SDL_TRUE;
}
#undef RECTTYPE
#undef POINTTYPE
#undef SCALARTYPE
#undef COMPUTEOUTCODE
#undef SDL_HASINTERSECTION
#undef SDL_INTERSECTRECT
#undef SDL_RECTEMPTY
#undef SDL_UNIONRECT
#undef SDL_ENCLOSEPOINTS
#undef SDL_INTERSECTRECTANDLINE

304
external/sdl/SDL/src/video/SDL_shape.c vendored Normal file
View File

@ -0,0 +1,304 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_sysvideo.h"
#include "SDL_shape_internals.h"
SDL_Window *SDL_CreateShapedWindow(const char *title, int w, int h, Uint32 flags)
{
SDL_Window *result = NULL;
result = SDL_CreateWindow(title, w, h, (flags | SDL_WINDOW_BORDERLESS | SDL_WINDOW_HIDDEN) & (~SDL_WINDOW_FULLSCREEN) & (~SDL_WINDOW_RESIZABLE));
if (result != NULL) {
if (SDL_GetVideoDevice()->shape_driver.CreateShaper == NULL) {
SDL_DestroyWindow(result);
return NULL;
}
result->shaper = SDL_GetVideoDevice()->shape_driver.CreateShaper(result);
if (result->shaper != NULL) {
result->shaper->mode.mode = ShapeModeDefault;
result->shaper->mode.parameters.binarizationCutoff = 1;
result->shaper->hasshape = SDL_FALSE;
return result;
} else {
SDL_DestroyWindow(result);
return NULL;
}
}
return NULL;
}
SDL_bool SDL_IsShapedWindow(const SDL_Window *window)
{
if (window == NULL) {
return SDL_FALSE;
}
return (SDL_bool)(window->shaper != NULL);
}
/* REQUIRES that bitmap point to a w-by-h bitmap with ppb pixels-per-byte. */
void SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode, SDL_Surface *shape, Uint8 *bitmap, Uint8 ppb)
{
int x = 0;
int y = 0;
Uint8 r = 0, g = 0, b = 0, alpha = 0;
Uint8 *pixel = NULL;
Uint32 pixel_value = 0, mask_value = 0;
size_t bytes_per_scanline = (size_t)(shape->w + (ppb - 1)) / ppb;
Uint8 *bitmap_scanline;
SDL_Color key;
if (SDL_MUSTLOCK(shape)) {
SDL_LockSurface(shape);
}
SDL_memset(bitmap, 0, shape->h * bytes_per_scanline);
for (y = 0; y < shape->h; y++) {
bitmap_scanline = bitmap + y * bytes_per_scanline;
for (x = 0; x < shape->w; x++) {
alpha = 0;
pixel_value = 0;
pixel = (Uint8 *)(shape->pixels) + (y * shape->pitch) + (x * shape->format->BytesPerPixel);
switch (shape->format->BytesPerPixel) {
case (1):
pixel_value = *pixel;
break;
case (2):
pixel_value = *(Uint16 *)pixel;
break;
case (3):
pixel_value = *(Uint32 *)pixel & (~shape->format->Amask);
break;
case (4):
pixel_value = *(Uint32 *)pixel;
break;
}
SDL_GetRGBA(pixel_value, shape->format, &r, &g, &b, &alpha);
switch (mode.mode) {
case (ShapeModeDefault):
mask_value = (alpha >= 1 ? 1 : 0);
break;
case (ShapeModeBinarizeAlpha):
mask_value = (alpha >= mode.parameters.binarizationCutoff ? 1 : 0);
break;
case (ShapeModeReverseBinarizeAlpha):
mask_value = (alpha <= mode.parameters.binarizationCutoff ? 1 : 0);
break;
case (ShapeModeColorKey):
key = mode.parameters.colorKey;
mask_value = ((key.r != r || key.g != g || key.b != b) ? 1 : 0);
break;
}
bitmap_scanline[x / ppb] |= mask_value << (x % ppb);
}
}
if (SDL_MUSTLOCK(shape)) {
SDL_UnlockSurface(shape);
}
}
static SDL_ShapeTree *RecursivelyCalculateShapeTree(SDL_WindowShapeMode mode, SDL_Surface *mask, SDL_Rect dimensions)
{
int x = 0, y = 0;
Uint8 *pixel = NULL;
Uint32 pixel_value = 0;
Uint8 r = 0, g = 0, b = 0, a = 0;
SDL_bool pixel_opaque = SDL_FALSE;
int last_opaque = -1;
SDL_Color key;
SDL_ShapeTree *result = (SDL_ShapeTree *)SDL_malloc(sizeof(SDL_ShapeTree));
SDL_Rect next = { 0, 0, 0, 0 };
if (result == NULL) {
SDL_OutOfMemory();
return NULL;
}
for (y = dimensions.y; y < dimensions.y + dimensions.h; y++) {
for (x = dimensions.x; x < dimensions.x + dimensions.w; x++) {
pixel_value = 0;
pixel = (Uint8 *)(mask->pixels) + (y * mask->pitch) + (x * mask->format->BytesPerPixel);
switch (mask->format->BytesPerPixel) {
case (1):
pixel_value = *pixel;
break;
case (2):
pixel_value = *(Uint16 *)pixel;
break;
case (3):
pixel_value = *(Uint32 *)pixel & (~mask->format->Amask);
break;
case (4):
pixel_value = *(Uint32 *)pixel;
break;
}
SDL_GetRGBA(pixel_value, mask->format, &r, &g, &b, &a);
switch (mode.mode) {
case (ShapeModeDefault):
pixel_opaque = (a >= 1 ? SDL_TRUE : SDL_FALSE);
break;
case (ShapeModeBinarizeAlpha):
pixel_opaque = (a >= mode.parameters.binarizationCutoff ? SDL_TRUE : SDL_FALSE);
break;
case (ShapeModeReverseBinarizeAlpha):
pixel_opaque = (a <= mode.parameters.binarizationCutoff ? SDL_TRUE : SDL_FALSE);
break;
case (ShapeModeColorKey):
key = mode.parameters.colorKey;
pixel_opaque = ((key.r != r || key.g != g || key.b != b) ? SDL_TRUE : SDL_FALSE);
break;
}
if (last_opaque == -1) {
last_opaque = pixel_opaque;
}
if (last_opaque != pixel_opaque) {
const int halfwidth = dimensions.w / 2;
const int halfheight = dimensions.h / 2;
result->kind = QuadShape;
next.x = dimensions.x;
next.y = dimensions.y;
next.w = halfwidth;
next.h = halfheight;
result->data.children.upleft = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode, mask, next);
next.x = dimensions.x + halfwidth;
next.w = dimensions.w - halfwidth;
result->data.children.upright = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode, mask, next);
next.x = dimensions.x;
next.w = halfwidth;
next.y = dimensions.y + halfheight;
next.h = dimensions.h - halfheight;
result->data.children.downleft = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode, mask, next);
next.x = dimensions.x + halfwidth;
next.w = dimensions.w - halfwidth;
result->data.children.downright = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode, mask, next);
return result;
}
}
}
/* If we never recursed, all the pixels in this quadrant have the same "value". */
result->kind = (last_opaque == SDL_TRUE ? OpaqueShape : TransparentShape);
result->data.shape = dimensions;
return result;
}
SDL_ShapeTree *SDL_CalculateShapeTree(SDL_WindowShapeMode mode, SDL_Surface *shape)
{
SDL_Rect dimensions;
SDL_ShapeTree *result = NULL;
dimensions.x = 0;
dimensions.y = 0;
dimensions.w = shape->w;
dimensions.h = shape->h;
if (SDL_MUSTLOCK(shape)) {
SDL_LockSurface(shape);
}
result = RecursivelyCalculateShapeTree(mode, shape, dimensions);
if (SDL_MUSTLOCK(shape)) {
SDL_UnlockSurface(shape);
}
return result;
}
void SDL_TraverseShapeTree(SDL_ShapeTree *tree, SDL_TraversalFunction function, void *closure)
{
SDL_assert(tree != NULL);
if (tree->kind == QuadShape) {
SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.upleft, function, closure);
SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.upright, function, closure);
SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.downleft, function, closure);
SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.downright, function, closure);
} else {
function(tree, closure);
}
}
void SDL_FreeShapeTree(SDL_ShapeTree **shape_tree)
{
if ((*shape_tree)->kind == QuadShape) {
SDL_FreeShapeTree((SDL_ShapeTree **)(char *)&(*shape_tree)->data.children.upleft);
SDL_FreeShapeTree((SDL_ShapeTree **)(char *)&(*shape_tree)->data.children.upright);
SDL_FreeShapeTree((SDL_ShapeTree **)(char *)&(*shape_tree)->data.children.downleft);
SDL_FreeShapeTree((SDL_ShapeTree **)(char *)&(*shape_tree)->data.children.downright);
}
SDL_free(*shape_tree);
*shape_tree = NULL;
}
int SDL_SetWindowShape(SDL_Window *window, SDL_Surface *shape, SDL_WindowShapeMode *shape_mode)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
int result;
if (window == NULL || !SDL_IsShapedWindow(window)) {
/* The window given was not a shapeable window. */
return SDL_NONSHAPEABLE_WINDOW;
}
if (shape == NULL) {
/* Invalid shape argument. */
return SDL_INVALID_SHAPE_ARGUMENT;
}
if (shape_mode != NULL) {
window->shaper->mode = *shape_mode;
}
result = _this->shape_driver.SetWindowShape(window->shaper, shape, shape_mode);
if (result == 0) {
window->shaper->hasshape = SDL_TRUE;
SDL_ShowWindow(window);
}
return result;
}
static SDL_bool SDL_WindowHasAShape(SDL_Window *window)
{
if (window == NULL || !SDL_IsShapedWindow(window)) {
return SDL_FALSE;
}
return window->shaper->hasshape;
}
int SDL_GetShapedWindowMode(SDL_Window *window, SDL_WindowShapeMode *shape_mode)
{
if (window != NULL && SDL_IsShapedWindow(window)) {
if (shape_mode == NULL) {
if (SDL_WindowHasAShape(window)) {
return 0; /* The window given has a shape. */
} else {
return SDL_WINDOW_LACKS_SHAPE; /* The window given is shapeable but lacks a shape. */
}
} else {
*shape_mode = window->shaper->mode;
return 0;
}
}
return SDL_NONSHAPEABLE_WINDOW; /* The window given is not a valid shapeable window. */
}

View File

@ -0,0 +1,59 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_shape_internals_h_
#define SDL_shape_internals_h_
struct SDL_ShapeTree;
typedef struct
{
struct SDL_ShapeTree *upleft, *upright, *downleft, *downright;
} SDL_QuadTreeChildren;
typedef union
{
SDL_QuadTreeChildren children;
SDL_Rect shape;
} SDL_ShapeUnion;
typedef enum
{
QuadShape,
TransparentShape,
OpaqueShape
} SDL_ShapeKind;
typedef struct SDL_ShapeTree
{
SDL_ShapeKind kind;
SDL_ShapeUnion data;
} SDL_ShapeTree;
typedef void (*SDL_TraversalFunction)(SDL_ShapeTree *, void *);
extern void SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode, SDL_Surface *shape, Uint8 *bitmap, Uint8 ppb);
extern SDL_ShapeTree *SDL_CalculateShapeTree(SDL_WindowShapeMode mode, SDL_Surface *shape);
extern void SDL_TraverseShapeTree(SDL_ShapeTree *tree, SDL_TraversalFunction function, void *closure);
extern void SDL_FreeShapeTree(SDL_ShapeTree **shape_tree);
#endif /* SDL_shape_internals_h_ */

945
external/sdl/SDL/src/video/SDL_stretch.c vendored Normal file
View File

@ -0,0 +1,945 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_blit.h"
static int SDL_LowerSoftStretchNearest(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect);
static int SDL_LowerSoftStretchLinear(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect);
static int SDL_UpperSoftStretch(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode);
int SDL_SoftStretch(SDL_Surface *src, const SDL_Rect *srcrect,
SDL_Surface *dst, const SDL_Rect *dstrect)
{
return SDL_UpperSoftStretch(src, srcrect, dst, dstrect, SDL_SCALEMODE_NEAREST);
}
int SDL_SoftStretchLinear(SDL_Surface *src, const SDL_Rect *srcrect,
SDL_Surface *dst, const SDL_Rect *dstrect)
{
return SDL_UpperSoftStretch(src, srcrect, dst, dstrect, SDL_SCALEMODE_LINEAR);
}
static int SDL_UpperSoftStretch(SDL_Surface *src, const SDL_Rect *srcrect,
SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode)
{
int ret;
int src_locked;
int dst_locked;
SDL_Rect full_src;
SDL_Rect full_dst;
if (src->format->format != dst->format->format) {
return SDL_SetError("Only works with same format surfaces");
}
if (scaleMode != SDL_SCALEMODE_NEAREST) {
if (src->format->BytesPerPixel != 4 || src->format->format == SDL_PIXELFORMAT_ARGB2101010) {
return SDL_SetError("Wrong format");
}
}
/* Verify the blit rectangles */
if (srcrect) {
if ((srcrect->x < 0) || (srcrect->y < 0) ||
((srcrect->x + srcrect->w) > src->w) ||
((srcrect->y + srcrect->h) > src->h)) {
return SDL_SetError("Invalid source blit rectangle");
}
} else {
full_src.x = 0;
full_src.y = 0;
full_src.w = src->w;
full_src.h = src->h;
srcrect = &full_src;
}
if (dstrect) {
if ((dstrect->x < 0) || (dstrect->y < 0) ||
((dstrect->x + dstrect->w) > dst->w) ||
((dstrect->y + dstrect->h) > dst->h)) {
return SDL_SetError("Invalid destination blit rectangle");
}
} else {
full_dst.x = 0;
full_dst.y = 0;
full_dst.w = dst->w;
full_dst.h = dst->h;
dstrect = &full_dst;
}
if (dstrect->w <= 0 || dstrect->h <= 0) {
return 0;
}
if (srcrect->w > SDL_MAX_UINT16 || srcrect->h > SDL_MAX_UINT16 ||
dstrect->w > SDL_MAX_UINT16 || dstrect->h > SDL_MAX_UINT16) {
return SDL_SetError("Size too large for scaling");
}
/* Lock the destination if it's in hardware */
dst_locked = 0;
if (SDL_MUSTLOCK(dst)) {
if (SDL_LockSurface(dst) < 0) {
return SDL_SetError("Unable to lock destination surface");
}
dst_locked = 1;
}
/* Lock the source if it's in hardware */
src_locked = 0;
if (SDL_MUSTLOCK(src)) {
if (SDL_LockSurface(src) < 0) {
if (dst_locked) {
SDL_UnlockSurface(dst);
}
return SDL_SetError("Unable to lock source surface");
}
src_locked = 1;
}
if (scaleMode == SDL_SCALEMODE_NEAREST) {
ret = SDL_LowerSoftStretchNearest(src, srcrect, dst, dstrect);
} else {
ret = SDL_LowerSoftStretchLinear(src, srcrect, dst, dstrect);
}
/* We need to unlock the surfaces if they're locked */
if (dst_locked) {
SDL_UnlockSurface(dst);
}
if (src_locked) {
SDL_UnlockSurface(src);
}
return ret;
}
/* bilinear interpolation precision must be < 8
Because with SSE: add-multiply: _mm_madd_epi16 works with signed int
so pixels 0xb1...... are negatives and false the result
same in NEON probably */
#define PRECISION 7
#define FIXED_POINT(i) ((Uint32)(i) << 16)
#define SRC_INDEX(fp) ((Uint32)(fp) >> 16)
#define INTEGER(fp) ((Uint32)(fp) >> PRECISION)
#define FRAC(fp) ((Uint32)((fp) >> (16 - PRECISION)) & ((1 << PRECISION) - 1))
#define FRAC_ZERO 0
#define FRAC_ONE (1 << PRECISION)
#define FP_ONE FIXED_POINT(1)
#define BILINEAR___START \
int i; \
int fp_sum_h, fp_step_h, left_pad_h, right_pad_h; \
int fp_sum_w, fp_step_w, left_pad_w, right_pad_w; \
int fp_sum_w_init, left_pad_w_init, right_pad_w_init, dst_gap, middle_init; \
get_scaler_datas(src_h, dst_h, &fp_sum_h, &fp_step_h, &left_pad_h, &right_pad_h); \
get_scaler_datas(src_w, dst_w, &fp_sum_w, &fp_step_w, &left_pad_w, &right_pad_w); \
fp_sum_w_init = fp_sum_w + left_pad_w * fp_step_w; \
left_pad_w_init = left_pad_w; \
right_pad_w_init = right_pad_w; \
dst_gap = dst_pitch - 4 * dst_w; \
middle_init = dst_w - left_pad_w - right_pad_w;
#define BILINEAR___HEIGHT \
int index_h, frac_h0, frac_h1, middle; \
const Uint32 *src_h0, *src_h1; \
int no_padding, incr_h0, incr_h1; \
\
no_padding = !(i < left_pad_h || i > dst_h - 1 - right_pad_h); \
index_h = SRC_INDEX(fp_sum_h); \
frac_h0 = FRAC(fp_sum_h); \
\
index_h = no_padding ? index_h : (i < left_pad_h ? 0 : src_h - 1); \
frac_h0 = no_padding ? frac_h0 : 0; \
incr_h1 = no_padding ? src_pitch : 0; \
incr_h0 = index_h * src_pitch; \
\
src_h0 = (const Uint32 *)((const Uint8 *)src + incr_h0); \
src_h1 = (const Uint32 *)((const Uint8 *)src_h0 + incr_h1); \
\
fp_sum_h += fp_step_h; \
\
frac_h1 = FRAC_ONE - frac_h0; \
fp_sum_w = fp_sum_w_init; \
right_pad_w = right_pad_w_init; \
left_pad_w = left_pad_w_init; \
middle = middle_init;
#ifdef __clang__
// Remove inlining of this function
// Compiler crash with clang 9.0.8 / android-ndk-r21d
// Compiler crash with clang 11.0.3 / Xcode
// OK with clang 11.0.5 / android-ndk-22
// OK with clang 12.0.0 / Xcode
__attribute__((noinline))
#endif
static void get_scaler_datas(int src_nb, int dst_nb, int *fp_start, int *fp_step, int *left_pad, int *right_pad)
{
int step = FIXED_POINT(src_nb) / (dst_nb); /* source step in fixed point */
int x0 = FP_ONE / 2; /* dst first pixel center at 0.5 in fixed point */
int fp_sum;
int i;
#if 0
/* scale to source coordinates */
x0 *= src_nb;
x0 /= dst_nb; /* x0 == step / 2 */
#else
/* Use this code for perfect match with pixman */
Sint64 tmp[2];
tmp[0] = (Sint64)step * (x0 >> 16);
tmp[1] = (Sint64)step * (x0 & 0xFFFF);
x0 = (int)(tmp[0] + ((tmp[1] + 0x8000) >> 16)); /* x0 == (step + 1) / 2 */
#endif
/* -= 0.5, get back the pixel origin, in source coordinates */
x0 -= FP_ONE / 2;
*fp_start = x0;
*fp_step = step;
*left_pad = 0;
*right_pad = 0;
fp_sum = x0;
for (i = 0; i < dst_nb; i++) {
if (fp_sum < 0) {
*left_pad += 1;
} else {
int index = SRC_INDEX(fp_sum);
if (index > src_nb - 2) {
*right_pad += 1;
}
}
fp_sum += step;
}
// SDL_Log("%d -> %d x0=%d step=%d left_pad=%d right_pad=%d", src_nb, dst_nb, *fp_start, *fp_step, *left_pad, *right_pad);
}
typedef struct color_t
{
Uint8 a;
Uint8 b;
Uint8 c;
Uint8 d;
} color_t;
#if 0
static void printf_64(const char *str, void *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]);
}
#endif
/* Interpolated == x0 + frac * (x1 - x0) == x0 * (1 - frac) + x1 * frac */
static SDL_INLINE void INTERPOL(const Uint32 *src_x0, const Uint32 *src_x1, int frac0, int frac1, Uint32 *dst)
{
const color_t *c0 = (const color_t *)src_x0;
const color_t *c1 = (const color_t *)src_x1;
color_t *cx = (color_t *)dst;
#if 0
cx->a = c0->a + INTEGER(frac0 * (c1->a - c0->a));
cx->b = c0->b + INTEGER(frac0 * (c1->b - c0->b));
cx->c = c0->c + INTEGER(frac0 * (c1->c - c0->c));
cx->d = c0->d + INTEGER(frac0 * (c1->d - c0->d));
#else
cx->a = (Uint8)INTEGER(frac1 * c0->a + frac0 * c1->a);
cx->b = (Uint8)INTEGER(frac1 * c0->b + frac0 * c1->b);
cx->c = (Uint8)INTEGER(frac1 * c0->c + frac0 * c1->c);
cx->d = (Uint8)INTEGER(frac1 * c0->d + frac0 * c1->d);
#endif
}
static SDL_INLINE void INTERPOL_BILINEAR(const Uint32 *s0, const Uint32 *s1, int frac_w0, int frac_h0, int frac_h1, Uint32 *dst)
{
Uint32 tmp[2];
unsigned int frac_w1 = FRAC_ONE - frac_w0;
/* Vertical first, store to 'tmp' */
INTERPOL(s0, s1, frac_h0, frac_h1, tmp);
INTERPOL(s0 + 1, s1 + 1, frac_h0, frac_h1, tmp + 1);
/* Horizontal, store to 'dst' */
INTERPOL(tmp, tmp + 1, frac_w0, frac_w1, dst);
}
static int scale_mat(const Uint32 *src, int src_w, int src_h, int src_pitch,
Uint32 *dst, int dst_w, int dst_h, int dst_pitch)
{
BILINEAR___START
for (i = 0; i < dst_h; i++) {
BILINEAR___HEIGHT
while (left_pad_w--) {
INTERPOL_BILINEAR(src_h0, src_h1, FRAC_ZERO, frac_h0, frac_h1, dst);
dst += 1;
}
while (middle--) {
const Uint32 *s_00_01;
const Uint32 *s_10_11;
int index_w = 4 * SRC_INDEX(fp_sum_w);
int frac_w = FRAC(fp_sum_w);
fp_sum_w += fp_step_w;
/*
x00 ... x0_ ..... x01
. . .
. x .
. . .
. . .
x10 ... x1_ ..... x11
*/
s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w);
s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w);
INTERPOL_BILINEAR(s_00_01, s_10_11, frac_w, frac_h0, frac_h1, dst);
dst += 1;
}
while (right_pad_w--) {
int index_w = 4 * (src_w - 2);
const Uint32 *s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w);
const Uint32 *s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w);
INTERPOL_BILINEAR(s_00_01, s_10_11, FRAC_ONE, frac_h0, frac_h1, dst);
dst += 1;
}
dst = (Uint32 *)((Uint8 *)dst + dst_gap);
}
return 0;
}
#ifdef SDL_NEON_INTRINSICS
#define CAST_uint8x8_t (uint8x8_t)
#define CAST_uint32x2_t (uint32x2_t)
#endif
#if defined(__WINRT__) || defined(_MSC_VER)
#ifdef SDL_NEON_INTRINSICS
#undef CAST_uint8x8_t
#undef CAST_uint32x2_t
#define CAST_uint8x8_t
#define CAST_uint32x2_t
#endif
#endif
#ifdef SDL_SSE2_INTRINSICS
#if 0
static void SDL_TARGETING("sse2") printf_128(const char *str, __m128i 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]);
}
#endif
static SDL_INLINE int hasSSE2(void)
{
static int val = -1;
if (val != -1) {
return val;
}
val = SDL_HasSSE2();
return val;
}
static SDL_INLINE void SDL_TARGETING("sse2") INTERPOL_BILINEAR_SSE(const Uint32 *s0, const Uint32 *s1, int frac_w, __m128i v_frac_h0, __m128i v_frac_h1, Uint32 *dst, __m128i zero)
{
__m128i x_00_01, x_10_11; /* Pixels in 4*uint8 in row */
__m128i v_frac_w0, k0, l0, d0, e0;
int f, f2;
f = frac_w;
f2 = FRAC_ONE - frac_w;
v_frac_w0 = _mm_set_epi16((short)f, (short)f2, (short)f, (short)f2, (short)f, (short)f2, (short)f, (short)f2);
x_00_01 = _mm_loadl_epi64((const __m128i *)s0); /* Load x00 and x01 */
x_10_11 = _mm_loadl_epi64((const __m128i *)s1);
/* Interpolated == x0 + frac * (x1 - x0) == x0 * (1 - frac) + x1 * frac */
/* Interpolation vertical */
k0 = _mm_mullo_epi16(_mm_unpacklo_epi8(x_00_01, zero), v_frac_h1);
l0 = _mm_mullo_epi16(_mm_unpacklo_epi8(x_10_11, zero), v_frac_h0);
k0 = _mm_add_epi16(k0, l0);
/* For perfect match, clear the factionnal part eventually. */
/*
k0 = _mm_srli_epi16(k0, PRECISION);
k0 = _mm_slli_epi16(k0, PRECISION);
*/
/* Interpolation horizontal */
l0 = _mm_unpacklo_epi64(/* unused */ l0, k0);
k0 = _mm_madd_epi16(_mm_unpackhi_epi16(l0, k0), v_frac_w0);
/* Store 1 pixel */
d0 = _mm_srli_epi32(k0, PRECISION * 2);
e0 = _mm_packs_epi32(d0, d0);
e0 = _mm_packus_epi16(e0, e0);
*dst = _mm_cvtsi128_si32(e0);
}
static int SDL_TARGETING("sse2") scale_mat_SSE(const Uint32 *src, int src_w, int src_h, int src_pitch, Uint32 *dst, int dst_w, int dst_h, int dst_pitch)
{
BILINEAR___START
for (i = 0; i < dst_h; i++) {
int nb_block2;
__m128i v_frac_h0;
__m128i v_frac_h1;
__m128i zero;
BILINEAR___HEIGHT
nb_block2 = middle / 2;
v_frac_h0 = _mm_set_epi16((short)frac_h0, (short)frac_h0, (short)frac_h0, (short)frac_h0, (short)frac_h0, (short)frac_h0, (short)frac_h0, (short)frac_h0);
v_frac_h1 = _mm_set_epi16((short)frac_h1, (short)frac_h1, (short)frac_h1, (short)frac_h1, (short)frac_h1, (short)frac_h1, (short)frac_h1, (short)frac_h1);
zero = _mm_setzero_si128();
while (left_pad_w--) {
INTERPOL_BILINEAR_SSE(src_h0, src_h1, FRAC_ZERO, v_frac_h0, v_frac_h1, dst, zero);
dst += 1;
}
while (nb_block2--) {
int index_w_0, frac_w_0;
int index_w_1, frac_w_1;
const Uint32 *s_00_01, *s_02_03, *s_10_11, *s_12_13;
__m128i x_00_01, x_10_11, x_02_03, x_12_13; /* Pixels in 4*uint8 in row */
__m128i v_frac_w0, k0, l0, d0, e0;
__m128i v_frac_w1, k1, l1, d1, e1;
int f, f2;
index_w_0 = 4 * SRC_INDEX(fp_sum_w);
frac_w_0 = FRAC(fp_sum_w);
fp_sum_w += fp_step_w;
index_w_1 = 4 * SRC_INDEX(fp_sum_w);
frac_w_1 = FRAC(fp_sum_w);
fp_sum_w += fp_step_w;
/*
x00............ x01 x02...........x03
. . . . . .
j0 f0 j1 j2 f1 j3
. . . . . .
. . . . . .
. . . . . .
x10............ x11 x12...........x13
*/
s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w_0);
s_02_03 = (const Uint32 *)((const Uint8 *)src_h0 + index_w_1);
s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w_0);
s_12_13 = (const Uint32 *)((const Uint8 *)src_h1 + index_w_1);
f = frac_w_0;
f2 = FRAC_ONE - frac_w_0;
v_frac_w0 = _mm_set_epi16((short)f, (short)f2, (short)f, (short)f2, (short)f, (short)f2, (short)f, (short)f2);
f = frac_w_1;
f2 = FRAC_ONE - frac_w_1;
v_frac_w1 = _mm_set_epi16((short)f, (short)f2, (short)f, (short)f2, (short)f, (short)f2, (short)f, (short)f2);
x_00_01 = _mm_loadl_epi64((const __m128i *)s_00_01); /* Load x00 and x01 */
x_02_03 = _mm_loadl_epi64((const __m128i *)s_02_03);
x_10_11 = _mm_loadl_epi64((const __m128i *)s_10_11);
x_12_13 = _mm_loadl_epi64((const __m128i *)s_12_13);
/* Interpolation vertical */
k0 = _mm_mullo_epi16(_mm_unpacklo_epi8(x_00_01, zero), v_frac_h1);
l0 = _mm_mullo_epi16(_mm_unpacklo_epi8(x_10_11, zero), v_frac_h0);
k0 = _mm_add_epi16(k0, l0);
k1 = _mm_mullo_epi16(_mm_unpacklo_epi8(x_02_03, zero), v_frac_h1);
l1 = _mm_mullo_epi16(_mm_unpacklo_epi8(x_12_13, zero), v_frac_h0);
k1 = _mm_add_epi16(k1, l1);
/* Interpolation horizontal */
l0 = _mm_unpacklo_epi64(/* unused */ l0, k0);
k0 = _mm_madd_epi16(_mm_unpackhi_epi16(l0, k0), v_frac_w0);
l1 = _mm_unpacklo_epi64(/* unused */ l1, k1);
k1 = _mm_madd_epi16(_mm_unpackhi_epi16(l1, k1), v_frac_w1);
/* Store 1 pixel */
d0 = _mm_srli_epi32(k0, PRECISION * 2);
e0 = _mm_packs_epi32(d0, d0);
e0 = _mm_packus_epi16(e0, e0);
*dst++ = _mm_cvtsi128_si32(e0);
/* Store 1 pixel */
d1 = _mm_srli_epi32(k1, PRECISION * 2);
e1 = _mm_packs_epi32(d1, d1);
e1 = _mm_packus_epi16(e1, e1);
*dst++ = _mm_cvtsi128_si32(e1);
}
/* Last point */
if (middle & 0x1) {
const Uint32 *s_00_01;
const Uint32 *s_10_11;
int index_w = 4 * SRC_INDEX(fp_sum_w);
int frac_w = FRAC(fp_sum_w);
fp_sum_w += fp_step_w;
s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w);
s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w);
INTERPOL_BILINEAR_SSE(s_00_01, s_10_11, frac_w, v_frac_h0, v_frac_h1, dst, zero);
dst += 1;
}
while (right_pad_w--) {
int index_w = 4 * (src_w - 2);
const Uint32 *s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w);
const Uint32 *s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w);
INTERPOL_BILINEAR_SSE(s_00_01, s_10_11, FRAC_ONE, v_frac_h0, v_frac_h1, dst, zero);
dst += 1;
}
dst = (Uint32 *)((Uint8 *)dst + dst_gap);
}
return 0;
}
#endif
#ifdef SDL_NEON_INTRINSICS
static SDL_INLINE int hasNEON(void)
{
static int val = -1;
if (val != -1) {
return val;
}
val = SDL_HasNEON();
return val;
}
static SDL_INLINE void INTERPOL_BILINEAR_NEON(const Uint32 *s0, const Uint32 *s1, int frac_w, uint8x8_t v_frac_h0, uint8x8_t v_frac_h1, Uint32 *dst)
{
uint8x8_t x_00_01, x_10_11; /* Pixels in 4*uint8 in row */
uint16x8_t k0;
uint32x4_t l0;
uint16x8_t d0;
uint8x8_t e0;
x_00_01 = CAST_uint8x8_t vld1_u32(s0); /* Load 2 pixels */
x_10_11 = CAST_uint8x8_t vld1_u32(s1);
/* Interpolated == x0 + frac * (x1 - x0) == x0 * (1 - frac) + x1 * frac */
k0 = vmull_u8(x_00_01, v_frac_h1); /* k0 := x0 * (1 - frac) */
k0 = vmlal_u8(k0, x_10_11, v_frac_h0); /* k0 += x1 * frac */
/* k0 now contains 2 interpolated pixels { j0, j1 } */
l0 = vshll_n_u16(vget_low_u16(k0), PRECISION);
l0 = vmlsl_n_u16(l0, vget_low_u16(k0), frac_w);
l0 = vmlal_n_u16(l0, vget_high_u16(k0), frac_w);
/* Shift and narrow */
d0 = vcombine_u16(
/* uint16x4_t */ vshrn_n_u32(l0, 2 * PRECISION),
/* uint16x4_t */ vshrn_n_u32(l0, 2 * PRECISION));
/* Narrow again */
e0 = vmovn_u16(d0);
/* Store 1 pixel */
*dst = vget_lane_u32(CAST_uint32x2_t e0, 0);
}
static int scale_mat_NEON(const Uint32 *src, int src_w, int src_h, int src_pitch, Uint32 *dst, int dst_w, int dst_h, int dst_pitch)
{
BILINEAR___START
for (i = 0; i < dst_h; i++) {
int nb_block4;
uint8x8_t v_frac_h0, v_frac_h1;
BILINEAR___HEIGHT
nb_block4 = middle / 4;
v_frac_h0 = vmov_n_u8(frac_h0);
v_frac_h1 = vmov_n_u8(frac_h1);
while (left_pad_w--) {
INTERPOL_BILINEAR_NEON(src_h0, src_h1, FRAC_ZERO, v_frac_h0, v_frac_h1, dst);
dst += 1;
}
while (nb_block4--) {
int index_w_0, frac_w_0;
int index_w_1, frac_w_1;
int index_w_2, frac_w_2;
int index_w_3, frac_w_3;
const Uint32 *s_00_01, *s_02_03, *s_04_05, *s_06_07;
const Uint32 *s_10_11, *s_12_13, *s_14_15, *s_16_17;
uint8x8_t x_00_01, x_10_11, x_02_03, x_12_13; /* Pixels in 4*uint8 in row */
uint8x8_t x_04_05, x_14_15, x_06_07, x_16_17;
uint16x8_t k0, k1, k2, k3;
uint32x4_t l0, l1, l2, l3;
uint16x8_t d0, d1;
uint8x8_t e0, e1;
uint32x4_t f0;
index_w_0 = 4 * SRC_INDEX(fp_sum_w);
frac_w_0 = FRAC(fp_sum_w);
fp_sum_w += fp_step_w;
index_w_1 = 4 * SRC_INDEX(fp_sum_w);
frac_w_1 = FRAC(fp_sum_w);
fp_sum_w += fp_step_w;
index_w_2 = 4 * SRC_INDEX(fp_sum_w);
frac_w_2 = FRAC(fp_sum_w);
fp_sum_w += fp_step_w;
index_w_3 = 4 * SRC_INDEX(fp_sum_w);
frac_w_3 = FRAC(fp_sum_w);
fp_sum_w += fp_step_w;
s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w_0);
s_02_03 = (const Uint32 *)((const Uint8 *)src_h0 + index_w_1);
s_04_05 = (const Uint32 *)((const Uint8 *)src_h0 + index_w_2);
s_06_07 = (const Uint32 *)((const Uint8 *)src_h0 + index_w_3);
s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w_0);
s_12_13 = (const Uint32 *)((const Uint8 *)src_h1 + index_w_1);
s_14_15 = (const Uint32 *)((const Uint8 *)src_h1 + index_w_2);
s_16_17 = (const Uint32 *)((const Uint8 *)src_h1 + index_w_3);
/* Interpolation vertical */
x_00_01 = CAST_uint8x8_t vld1_u32(s_00_01); /* Load 2 pixels */
x_02_03 = CAST_uint8x8_t vld1_u32(s_02_03);
x_04_05 = CAST_uint8x8_t vld1_u32(s_04_05);
x_06_07 = CAST_uint8x8_t vld1_u32(s_06_07);
x_10_11 = CAST_uint8x8_t vld1_u32(s_10_11);
x_12_13 = CAST_uint8x8_t vld1_u32(s_12_13);
x_14_15 = CAST_uint8x8_t vld1_u32(s_14_15);
x_16_17 = CAST_uint8x8_t vld1_u32(s_16_17);
/* Interpolated == x0 + frac * (x1 - x0) == x0 * (1 - frac) + x1 * frac */
k0 = vmull_u8(x_00_01, v_frac_h1); /* k0 := x0 * (1 - frac) */
k0 = vmlal_u8(k0, x_10_11, v_frac_h0); /* k0 += x1 * frac */
k1 = vmull_u8(x_02_03, v_frac_h1);
k1 = vmlal_u8(k1, x_12_13, v_frac_h0);
k2 = vmull_u8(x_04_05, v_frac_h1);
k2 = vmlal_u8(k2, x_14_15, v_frac_h0);
k3 = vmull_u8(x_06_07, v_frac_h1);
k3 = vmlal_u8(k3, x_16_17, v_frac_h0);
/* k0 now contains 2 interpolated pixels { j0, j1 } */
/* k1 now contains 2 interpolated pixels { j2, j3 } */
/* k2 now contains 2 interpolated pixels { j4, j5 } */
/* k3 now contains 2 interpolated pixels { j6, j7 } */
l0 = vshll_n_u16(vget_low_u16(k0), PRECISION);
l0 = vmlsl_n_u16(l0, vget_low_u16(k0), frac_w_0);
l0 = vmlal_n_u16(l0, vget_high_u16(k0), frac_w_0);
l1 = vshll_n_u16(vget_low_u16(k1), PRECISION);
l1 = vmlsl_n_u16(l1, vget_low_u16(k1), frac_w_1);
l1 = vmlal_n_u16(l1, vget_high_u16(k1), frac_w_1);
l2 = vshll_n_u16(vget_low_u16(k2), PRECISION);
l2 = vmlsl_n_u16(l2, vget_low_u16(k2), frac_w_2);
l2 = vmlal_n_u16(l2, vget_high_u16(k2), frac_w_2);
l3 = vshll_n_u16(vget_low_u16(k3), PRECISION);
l3 = vmlsl_n_u16(l3, vget_low_u16(k3), frac_w_3);
l3 = vmlal_n_u16(l3, vget_high_u16(k3), frac_w_3);
/* shift and narrow */
d0 = vcombine_u16(
/* uint16x4_t */ vshrn_n_u32(l0, 2 * PRECISION),
/* uint16x4_t */ vshrn_n_u32(l1, 2 * PRECISION));
/* narrow again */
e0 = vmovn_u16(d0);
/* Shift and narrow */
d1 = vcombine_u16(
/* uint16x4_t */ vshrn_n_u32(l2, 2 * PRECISION),
/* uint16x4_t */ vshrn_n_u32(l3, 2 * PRECISION));
/* Narrow again */
e1 = vmovn_u16(d1);
f0 = vcombine_u32(CAST_uint32x2_t e0, CAST_uint32x2_t e1);
/* Store 4 pixels */
vst1q_u32(dst, f0);
dst += 4;
}
if (middle & 0x2) {
int index_w_0, frac_w_0;
int index_w_1, frac_w_1;
const Uint32 *s_00_01, *s_02_03;
const Uint32 *s_10_11, *s_12_13;
uint8x8_t x_00_01, x_10_11, x_02_03, x_12_13; /* Pixels in 4*uint8 in row */
uint16x8_t k0, k1;
uint32x4_t l0, l1;
uint16x8_t d0;
uint8x8_t e0;
index_w_0 = 4 * SRC_INDEX(fp_sum_w);
frac_w_0 = FRAC(fp_sum_w);
fp_sum_w += fp_step_w;
index_w_1 = 4 * SRC_INDEX(fp_sum_w);
frac_w_1 = FRAC(fp_sum_w);
fp_sum_w += fp_step_w;
/*
x00............ x01 x02...........x03
. . . . . .
j0 dest0 j1 j2 dest1 j3
. . . . . .
. . . . . .
. . . . . .
x10............ x11 x12...........x13
*/
s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w_0);
s_02_03 = (const Uint32 *)((const Uint8 *)src_h0 + index_w_1);
s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w_0);
s_12_13 = (const Uint32 *)((const Uint8 *)src_h1 + index_w_1);
/* Interpolation vertical */
x_00_01 = CAST_uint8x8_t vld1_u32(s_00_01); /* Load 2 pixels */
x_02_03 = CAST_uint8x8_t vld1_u32(s_02_03);
x_10_11 = CAST_uint8x8_t vld1_u32(s_10_11);
x_12_13 = CAST_uint8x8_t vld1_u32(s_12_13);
/* Interpolated == x0 + frac * (x1 - x0) == x0 * (1 - frac) + x1 * frac */
k0 = vmull_u8(x_00_01, v_frac_h1); /* k0 := x0 * (1 - frac) */
k0 = vmlal_u8(k0, x_10_11, v_frac_h0); /* k0 += x1 * frac */
k1 = vmull_u8(x_02_03, v_frac_h1);
k1 = vmlal_u8(k1, x_12_13, v_frac_h0);
/* k0 now contains 2 interpolated pixels { j0, j1 } */
/* k1 now contains 2 interpolated pixels { j2, j3 } */
l0 = vshll_n_u16(vget_low_u16(k0), PRECISION);
l0 = vmlsl_n_u16(l0, vget_low_u16(k0), frac_w_0);
l0 = vmlal_n_u16(l0, vget_high_u16(k0), frac_w_0);
l1 = vshll_n_u16(vget_low_u16(k1), PRECISION);
l1 = vmlsl_n_u16(l1, vget_low_u16(k1), frac_w_1);
l1 = vmlal_n_u16(l1, vget_high_u16(k1), frac_w_1);
/* Shift and narrow */
d0 = vcombine_u16(
/* uint16x4_t */ vshrn_n_u32(l0, 2 * PRECISION),
/* uint16x4_t */ vshrn_n_u32(l1, 2 * PRECISION));
/* Narrow again */
e0 = vmovn_u16(d0);
/* Store 2 pixels */
vst1_u32(dst, CAST_uint32x2_t e0);
dst += 2;
}
/* Last point */
if (middle & 0x1) {
int index_w = 4 * SRC_INDEX(fp_sum_w);
int frac_w = FRAC(fp_sum_w);
const Uint32 *s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w);
const Uint32 *s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w);
INTERPOL_BILINEAR_NEON(s_00_01, s_10_11, frac_w, v_frac_h0, v_frac_h1, dst);
dst += 1;
}
while (right_pad_w--) {
int index_w = 4 * (src_w - 2);
const Uint32 *s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w);
const Uint32 *s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w);
INTERPOL_BILINEAR_NEON(s_00_01, s_10_11, FRAC_ONE, v_frac_h0, v_frac_h1, dst);
dst += 1;
}
dst = (Uint32 *)((Uint8 *)dst + dst_gap);
}
return 0;
}
#endif
int SDL_LowerSoftStretchLinear(SDL_Surface *s, const SDL_Rect *srcrect,
SDL_Surface *d, const SDL_Rect *dstrect)
{
int ret = -1;
int src_w = srcrect->w;
int src_h = srcrect->h;
int dst_w = dstrect->w;
int dst_h = dstrect->h;
int src_pitch = s->pitch;
int dst_pitch = d->pitch;
Uint32 *src = (Uint32 *)((Uint8 *)s->pixels + srcrect->x * 4 + srcrect->y * src_pitch);
Uint32 *dst = (Uint32 *)((Uint8 *)d->pixels + dstrect->x * 4 + dstrect->y * dst_pitch);
#ifdef SDL_NEON_INTRINSICS
if (ret == -1 && hasNEON()) {
ret = scale_mat_NEON(src, src_w, src_h, src_pitch, dst, dst_w, dst_h, dst_pitch);
}
#endif
#ifdef SDL_SSE2_INTRINSICS
if (ret == -1 && hasSSE2()) {
ret = scale_mat_SSE(src, src_w, src_h, src_pitch, dst, dst_w, dst_h, dst_pitch);
}
#endif
if (ret == -1) {
ret = scale_mat(src, src_w, src_h, src_pitch, dst, dst_w, dst_h, dst_pitch);
}
return ret;
}
#define SDL_SCALE_NEAREST__START \
int i; \
Uint32 posy, incy; \
Uint32 posx, incx; \
int dst_gap; \
int srcy, n; \
const Uint32 *src_h0; \
incy = (src_h << 16) / dst_h; \
incx = (src_w << 16) / dst_w; \
dst_gap = dst_pitch - bpp * dst_w; \
posy = incy / 2;
#define SDL_SCALE_NEAREST__HEIGHT \
srcy = (posy >> 16); \
src_h0 = (const Uint32 *)((const Uint8 *)src_ptr + srcy * src_pitch); \
posy += incy; \
posx = incx / 2; \
n = dst_w;
static int scale_mat_nearest_1(const Uint32 *src_ptr, int src_w, int src_h, int src_pitch,
Uint32 *dst, int dst_w, int dst_h, int dst_pitch)
{
Uint32 bpp = 1;
SDL_SCALE_NEAREST__START
for (i = 0; i < dst_h; i++) {
SDL_SCALE_NEAREST__HEIGHT
while (n--) {
const Uint8 *src;
int srcx = bpp * (posx >> 16);
posx += incx;
src = (const Uint8 *)src_h0 + srcx;
*(Uint8 *)dst = *src;
dst = (Uint32 *)((Uint8 *)dst + bpp);
}
dst = (Uint32 *)((Uint8 *)dst + dst_gap);
}
return 0;
}
static int scale_mat_nearest_2(const Uint32 *src_ptr, int src_w, int src_h, int src_pitch,
Uint32 *dst, int dst_w, int dst_h, int dst_pitch)
{
Uint32 bpp = 2;
SDL_SCALE_NEAREST__START
for (i = 0; i < dst_h; i++) {
SDL_SCALE_NEAREST__HEIGHT
while (n--) {
const Uint16 *src;
int srcx = bpp * (posx >> 16);
posx += incx;
src = (const Uint16 *)((const Uint8 *)src_h0 + srcx);
*(Uint16 *)dst = *src;
dst = (Uint32 *)((Uint8 *)dst + bpp);
}
dst = (Uint32 *)((Uint8 *)dst + dst_gap);
}
return 0;
}
static int scale_mat_nearest_3(const Uint32 *src_ptr, int src_w, int src_h, int src_pitch,
Uint32 *dst, int dst_w, int dst_h, int dst_pitch)
{
Uint32 bpp = 3;
SDL_SCALE_NEAREST__START
for (i = 0; i < dst_h; i++) {
SDL_SCALE_NEAREST__HEIGHT
while (n--) {
const Uint8 *src;
int srcx = bpp * (posx >> 16);
posx += incx;
src = (const Uint8 *)src_h0 + srcx;
((Uint8 *)dst)[0] = src[0];
((Uint8 *)dst)[1] = src[1];
((Uint8 *)dst)[2] = src[2];
dst = (Uint32 *)((Uint8 *)dst + bpp);
}
dst = (Uint32 *)((Uint8 *)dst + dst_gap);
}
return 0;
}
static int scale_mat_nearest_4(const Uint32 *src_ptr, int src_w, int src_h, int src_pitch,
Uint32 *dst, int dst_w, int dst_h, int dst_pitch)
{
Uint32 bpp = 4;
SDL_SCALE_NEAREST__START
for (i = 0; i < dst_h; i++) {
SDL_SCALE_NEAREST__HEIGHT
while (n--) {
const Uint32 *src;
int srcx = bpp * (posx >> 16);
posx += incx;
src = (const Uint32 *)((const Uint8 *)src_h0 + srcx);
*dst = *src;
dst = (Uint32 *)((Uint8 *)dst + bpp);
}
dst = (Uint32 *)((Uint8 *)dst + dst_gap);
}
return 0;
}
int SDL_LowerSoftStretchNearest(SDL_Surface *s, const SDL_Rect *srcrect,
SDL_Surface *d, const SDL_Rect *dstrect)
{
int src_w = srcrect->w;
int src_h = srcrect->h;
int dst_w = dstrect->w;
int dst_h = dstrect->h;
int src_pitch = s->pitch;
int dst_pitch = d->pitch;
const int bpp = d->format->BytesPerPixel;
Uint32 *src = (Uint32 *)((Uint8 *)s->pixels + srcrect->x * bpp + srcrect->y * src_pitch);
Uint32 *dst = (Uint32 *)((Uint8 *)d->pixels + dstrect->x * bpp + dstrect->y * dst_pitch);
if (bpp == 4) {
return scale_mat_nearest_4(src, src_w, src_h, src_pitch, dst, dst_w, dst_h, dst_pitch);
} else if (bpp == 3) {
return scale_mat_nearest_3(src, src_w, src_h, src_pitch, dst, dst_w, dst_h, dst_pitch);
} else if (bpp == 2) {
return scale_mat_nearest_2(src, src_w, src_h, src_pitch, dst, dst_w, dst_h, dst_pitch);
} else {
return scale_mat_nearest_1(src, src_w, src_h, src_pitch, dst, dst_w, dst_h, dst_pitch);
}
}

1579
external/sdl/SDL/src/video/SDL_surface.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,549 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_sysvideo_h_
#define SDL_sysvideo_h_
#include "SDL_vulkan_internal.h"
/* The SDL video driver */
typedef struct SDL_WindowShaper SDL_WindowShaper;
typedef struct SDL_ShapeDriver SDL_ShapeDriver;
typedef struct SDL_VideoDisplay SDL_VideoDisplay;
typedef struct SDL_VideoDevice SDL_VideoDevice;
typedef struct SDL_VideoData SDL_VideoData;
typedef struct SDL_DisplayData SDL_DisplayData;
typedef struct SDL_DisplayModeData SDL_DisplayModeData;
typedef struct SDL_WindowData SDL_WindowData;
/* Define the SDL window-shaper structure */
struct SDL_WindowShaper
{
/* The window associated with the shaper */
SDL_Window *window;
/* The parameters for shape calculation. */
SDL_WindowShapeMode mode;
/* Has this window been assigned a shape? */
SDL_bool hasshape;
void *driverdata;
};
/* Define the SDL shape driver structure */
struct SDL_ShapeDriver
{
SDL_WindowShaper *(*CreateShaper)(SDL_Window *window);
int (*SetWindowShape)(SDL_WindowShaper *shaper, SDL_Surface *shape, SDL_WindowShapeMode *shape_mode);
};
typedef struct SDL_WindowUserData
{
char *name;
void *data;
struct SDL_WindowUserData *next;
} SDL_WindowUserData;
/* Define the SDL window structure, corresponding to toplevel windows */
struct SDL_Window
{
const void *magic;
SDL_WindowID id;
char *title;
SDL_Surface *icon;
int x, y;
int w, h;
int min_w, min_h;
int max_w, max_h;
int last_pixel_w, last_pixel_h;
Uint32 flags;
Uint32 pending_flags;
float display_scale;
SDL_bool fullscreen_exclusive; /* The window is currently fullscreen exclusive */
SDL_DisplayID last_fullscreen_exclusive_display; /* The last fullscreen_exclusive display */
SDL_DisplayID last_displayID;
/* Stored position and size for windowed mode */
SDL_Rect windowed;
/* Whether or not the initial position was defined */
SDL_bool undefined_x;
SDL_bool undefined_y;
SDL_DisplayMode requested_fullscreen_mode;
SDL_DisplayMode current_fullscreen_mode;
float opacity;
SDL_Surface *surface;
SDL_bool surface_valid;
SDL_bool is_hiding;
SDL_bool restore_on_show; /* Child was hidden recursively by the parent, restore when shown. */
SDL_bool is_destroying;
SDL_bool is_dropping; /* drag/drop in progress, expecting SDL_SendDropComplete(). */
SDL_Rect mouse_rect;
SDL_WindowShaper *shaper;
SDL_HitTest hit_test;
void *hit_test_data;
SDL_WindowUserData *data;
SDL_WindowData *driverdata;
SDL_Window *prev;
SDL_Window *next;
SDL_Window *parent;
SDL_Window *first_child;
SDL_Window *prev_sibling;
SDL_Window *next_sibling;
};
#define SDL_WINDOW_FULLSCREEN_VISIBLE(W) \
((((W)->flags & SDL_WINDOW_FULLSCREEN) != 0) && \
(((W)->flags & SDL_WINDOW_HIDDEN) == 0) && \
(((W)->flags & SDL_WINDOW_MINIMIZED) == 0))
#define SDL_WINDOW_IS_POPUP(W) \
((((W)->flags & SDL_WINDOW_TOOLTIP) != 0) || \
(((W)->flags & SDL_WINDOW_POPUP_MENU) != 0)) \
\
/*
* Define the SDL display structure.
* This corresponds to physical monitors attached to the system.
*/
struct SDL_VideoDisplay
{
SDL_DisplayID id;
char *name;
int max_fullscreen_modes;
int num_fullscreen_modes;
SDL_DisplayMode *fullscreen_modes;
SDL_DisplayMode desktop_mode;
const SDL_DisplayMode *current_mode;
SDL_DisplayOrientation natural_orientation;
SDL_DisplayOrientation current_orientation;
float content_scale;
SDL_Window *fullscreen_window;
SDL_VideoDevice *device;
SDL_DisplayData *driverdata;
};
/* Forward declaration */
struct SDL_SysWMinfo;
/* Video device flags */
typedef enum
{
VIDEO_DEVICE_QUIRK_MODE_SWITCHING_EMULATED = 0x01,
VIDEO_DEVICE_QUIRK_DISABLE_UNSET_FULLSCREEN_ON_MINIMIZE = 0x02,
VIDEO_DEVICE_QUIRK_HAS_POPUP_WINDOW_SUPPORT = 0x04,
} DeviceQuirkFlags;
struct SDL_VideoDevice
{
/* * * */
/* The name of this video driver */
const char *name;
/* * * */
/* Initialization/Query functions */
/*
* Initialize the native video subsystem, filling in the list of
* displays for this driver, returning 0 or -1 if there's an error.
*/
int (*VideoInit)(SDL_VideoDevice *_this);
/*
* Reverse the effects VideoInit() -- called if VideoInit() fails or
* if the application is shutting down the video subsystem.
*/
void (*VideoQuit)(SDL_VideoDevice *_this);
/*
* Reinitialize the touch devices -- called if an unknown touch ID occurs.
*/
void (*ResetTouch)(SDL_VideoDevice *_this);
/* * * */
/*
* Display functions
*/
/*
* Refresh the display list
*/
void (*RefreshDisplays)(SDL_VideoDevice *_this);
/*
* Get the bounds of a display
*/
int (*GetDisplayBounds)(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
/*
* Get the usable bounds of a display (bounds minus menubar or whatever)
*/
int (*GetDisplayUsableBounds)(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
/*
* Get a list of the available display modes for a display.
*/
int (*GetDisplayModes)(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
/*
* Setting the display mode is independent of creating windows, so
* when the display mode is changed, all existing windows should have
* their data updated accordingly, including the display surfaces
* associated with them.
*/
int (*SetDisplayMode)(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
/* * * */
/*
* Window functions
*/
int (*CreateSDLWindow)(SDL_VideoDevice *_this, SDL_Window *window);
int (*CreateSDLWindowFrom)(SDL_VideoDevice *_this, SDL_Window *window, const void *data);
void (*SetWindowTitle)(SDL_VideoDevice *_this, SDL_Window *window);
int (*SetWindowIcon)(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon);
int (*SetWindowPosition)(SDL_VideoDevice *_this, SDL_Window *window);
void (*SetWindowSize)(SDL_VideoDevice *_this, SDL_Window *window);
void (*SetWindowMinimumSize)(SDL_VideoDevice *_this, SDL_Window *window);
void (*SetWindowMaximumSize)(SDL_VideoDevice *_this, SDL_Window *window);
int (*GetWindowBordersSize)(SDL_VideoDevice *_this, SDL_Window *window, int *top, int *left, int *bottom, int *right);
void (*GetWindowSizeInPixels)(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h);
int (*SetWindowOpacity)(SDL_VideoDevice *_this, SDL_Window *window, float opacity);
int (*SetWindowModalFor)(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window);
int (*SetWindowInputFocus)(SDL_VideoDevice *_this, SDL_Window *window);
void (*ShowWindow)(SDL_VideoDevice *_this, SDL_Window *window);
void (*HideWindow)(SDL_VideoDevice *_this, SDL_Window *window);
void (*RaiseWindow)(SDL_VideoDevice *_this, SDL_Window *window);
void (*MaximizeWindow)(SDL_VideoDevice *_this, SDL_Window *window);
void (*MinimizeWindow)(SDL_VideoDevice *_this, SDL_Window *window);
void (*RestoreWindow)(SDL_VideoDevice *_this, SDL_Window *window);
void (*SetWindowBordered)(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool bordered);
void (*SetWindowResizable)(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool resizable);
void (*SetWindowAlwaysOnTop)(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool on_top);
void (*SetWindowFullscreen)(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen);
void *(*GetWindowICCProfile)(SDL_VideoDevice *_this, SDL_Window *window, size_t *size);
SDL_DisplayID (*GetDisplayForWindow)(SDL_VideoDevice *_this, SDL_Window *window);
void (*SetWindowMouseRect)(SDL_VideoDevice *_this, SDL_Window *window);
void (*SetWindowMouseGrab)(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed);
void (*SetWindowKeyboardGrab)(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed);
void (*DestroyWindow)(SDL_VideoDevice *_this, SDL_Window *window);
int (*CreateWindowFramebuffer)(SDL_VideoDevice *_this, SDL_Window *window, Uint32 *format, void **pixels, int *pitch);
int (*UpdateWindowFramebuffer)(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rects, int numrects);
void (*DestroyWindowFramebuffer)(SDL_VideoDevice *_this, SDL_Window *window);
void (*OnWindowEnter)(SDL_VideoDevice *_this, SDL_Window *window);
int (*FlashWindow)(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
/* * * */
/*
* Shaped-window functions
*/
SDL_ShapeDriver shape_driver;
/* Get some platform dependent window information */
int (*GetWindowWMInfo)(SDL_VideoDevice *_this, SDL_Window *window, struct SDL_SysWMinfo *info);
/* * * */
/*
* OpenGL support
*/
int (*GL_LoadLibrary)(SDL_VideoDevice *_this, const char *path);
SDL_FunctionPointer (*GL_GetProcAddress)(SDL_VideoDevice *_this, const char *proc);
void (*GL_UnloadLibrary)(SDL_VideoDevice *_this);
SDL_GLContext (*GL_CreateContext)(SDL_VideoDevice *_this, SDL_Window *window);
int (*GL_MakeCurrent)(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
SDL_EGLSurface (*GL_GetEGLSurface)(SDL_VideoDevice *_this, SDL_Window *window);
int (*GL_SetSwapInterval)(SDL_VideoDevice *_this, int interval);
int (*GL_GetSwapInterval)(SDL_VideoDevice *_this, int *interval);
int (*GL_SwapWindow)(SDL_VideoDevice *_this, SDL_Window *window);
int (*GL_DeleteContext)(SDL_VideoDevice *_this, SDL_GLContext context);
void (*GL_DefaultProfileConfig)(SDL_VideoDevice *_this, int *mask, int *major, int *minor);
/* * * */
/*
* Vulkan support
*/
int (*Vulkan_LoadLibrary)(SDL_VideoDevice *_this, const char *path);
void (*Vulkan_UnloadLibrary)(SDL_VideoDevice *_this);
SDL_bool (*Vulkan_GetInstanceExtensions)(SDL_VideoDevice *_this, unsigned *count, const char **names);
SDL_bool (*Vulkan_CreateSurface)(SDL_VideoDevice *_this, SDL_Window *window, VkInstance instance, VkSurfaceKHR *surface);
/* * * */
/*
* Metal support
*/
SDL_MetalView (*Metal_CreateView)(SDL_VideoDevice *_this, SDL_Window *window);
void (*Metal_DestroyView)(SDL_VideoDevice *_this, SDL_MetalView view);
void *(*Metal_GetLayer)(SDL_VideoDevice *_this, SDL_MetalView view);
/* * * */
/*
* Event manager functions
*/
int (*WaitEventTimeout)(SDL_VideoDevice *_this, Sint64 timeoutNS);
void (*SendWakeupEvent)(SDL_VideoDevice *_this, SDL_Window *window);
void (*PumpEvents)(SDL_VideoDevice *_this);
/* Suspend the screensaver */
int (*SuspendScreenSaver)(SDL_VideoDevice *_this);
/* Text input */
void (*StartTextInput)(SDL_VideoDevice *_this);
void (*StopTextInput)(SDL_VideoDevice *_this);
int (*SetTextInputRect)(SDL_VideoDevice *_this, const SDL_Rect *rect);
void (*ClearComposition)(SDL_VideoDevice *_this);
SDL_bool (*IsTextInputShown)(SDL_VideoDevice *_this);
/* Screen keyboard */
SDL_bool (*HasScreenKeyboardSupport)(SDL_VideoDevice *_this);
void (*ShowScreenKeyboard)(SDL_VideoDevice *_this, SDL_Window *window);
void (*HideScreenKeyboard)(SDL_VideoDevice *_this, SDL_Window *window);
SDL_bool (*IsScreenKeyboardShown)(SDL_VideoDevice *_this, SDL_Window *window);
/* Clipboard */
const char **(*GetTextMimeTypes)(SDL_VideoDevice *_this, size_t *num_mime_types);
int (*SetClipboardData)(SDL_VideoDevice *_this);
void *(*GetClipboardData)(SDL_VideoDevice *_this, const char *mime_type, size_t *size);
SDL_bool (*HasClipboardData)(SDL_VideoDevice *_this, const char *mime_type);
/* If you implement *ClipboardData, you don't need to implement *ClipboardText */
int (*SetClipboardText)(SDL_VideoDevice *_this, const char *text);
char *(*GetClipboardText)(SDL_VideoDevice *_this);
SDL_bool (*HasClipboardText)(SDL_VideoDevice *_this);
/* These functions are only needed if the platform has a separate primary selection buffer */
int (*SetPrimarySelectionText)(SDL_VideoDevice *_this, const char *text);
char *(*GetPrimarySelectionText)(SDL_VideoDevice *_this);
SDL_bool (*HasPrimarySelectionText)(SDL_VideoDevice *_this);
/* MessageBox */
int (*ShowMessageBox)(SDL_VideoDevice *_this, const SDL_MessageBoxData *messageboxdata, int *buttonid);
/* Hit-testing */
int (*SetWindowHitTest)(SDL_Window *window, SDL_bool enabled);
/* Tell window that app enabled drag'n'drop events */
void (*AcceptDragAndDrop)(SDL_Window *window, SDL_bool accept);
/* * * */
/* Data common to all drivers */
SDL_threadID thread;
SDL_bool checked_texture_framebuffer;
SDL_bool is_dummy;
SDL_bool suspend_screensaver;
SDL_Window *wakeup_window;
SDL_Mutex *wakeup_lock; /* Initialized only if WaitEventTimeout/SendWakeupEvent are supported */
int num_displays;
SDL_VideoDisplay *displays;
SDL_Window *windows;
SDL_Window *grabbed_window;
Uint8 window_magic;
SDL_WindowID next_object_id;
Uint32 clipboard_sequence;
SDL_ClipboardDataCallback clipboard_callback;
SDL_ClipboardCleanupCallback clipboard_cleanup;
void *clipboard_userdata;
char **clipboard_mime_types;
size_t num_clipboard_mime_types;
char *primary_selection_text;
SDL_bool setting_display_mode;
Uint32 quirk_flags;
SDL_SystemTheme system_theme;
/* * * */
/* Data used by the GL drivers */
struct
{
int red_size;
int green_size;
int blue_size;
int alpha_size;
int depth_size;
int buffer_size;
int stencil_size;
int double_buffer;
int accum_red_size;
int accum_green_size;
int accum_blue_size;
int accum_alpha_size;
int stereo;
int multisamplebuffers;
int multisamplesamples;
int floatbuffers;
int accelerated;
int major_version;
int minor_version;
int flags;
int profile_mask;
int share_with_current_context;
int release_behavior;
int reset_notification;
int framebuffer_srgb_capable;
int no_error;
int retained_backing;
int egl_platform;
int driver_loaded;
char driver_path[256];
void *dll_handle;
} gl_config;
SDL_EGLAttribArrayCallback egl_platformattrib_callback;
SDL_EGLIntArrayCallback egl_surfaceattrib_callback;
SDL_EGLIntArrayCallback egl_contextattrib_callback;
/* * * */
/* Cache current GL context; don't call the OS when it hasn't changed. */
/* We have the global pointers here so Cocoa continues to work the way
it always has, and the thread-local storage for the general case.
*/
SDL_Window *current_glwin;
SDL_GLContext current_glctx;
SDL_TLSID current_glwin_tls;
SDL_TLSID current_glctx_tls;
/* Flag that stores whether it's allowed to call SDL_GL_MakeCurrent()
* with a NULL window, but a non-NULL context. (Not allowed in most cases,
* except on EGL under some circumstances.) */
SDL_bool gl_allow_no_surface;
/* * * */
/* Data used by the Vulkan drivers */
struct
{
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
int loader_loaded;
char loader_path[256];
void *loader_handle;
} vulkan_config;
/* * * */
/* Data private to this driver */
SDL_VideoData *driverdata;
struct SDL_GLDriverData *gl_data;
#ifdef SDL_VIDEO_OPENGL_EGL
struct SDL_EGL_VideoData *egl_data;
#endif
#if defined(SDL_VIDEO_OPENGL_ES) || defined(SDL_VIDEO_OPENGL_ES2)
struct SDL_PrivateGLESData *gles_data;
#endif
/* * * */
/* The function used to dispose of this structure */
void (*free)(SDL_VideoDevice *_this);
};
typedef struct VideoBootStrap
{
const char *name;
const char *desc;
SDL_VideoDevice *(*create)(void);
} VideoBootStrap;
/* Not all of these are available in a given build. Use #ifdefs, etc. */
extern VideoBootStrap COCOA_bootstrap;
extern VideoBootStrap X11_bootstrap;
extern VideoBootStrap WINDOWS_bootstrap;
extern VideoBootStrap WINRT_bootstrap;
extern VideoBootStrap HAIKU_bootstrap;
extern VideoBootStrap PND_bootstrap;
extern VideoBootStrap UIKIT_bootstrap;
extern VideoBootStrap Android_bootstrap;
extern VideoBootStrap PS2_bootstrap;
extern VideoBootStrap PSP_bootstrap;
extern VideoBootStrap VITA_bootstrap;
extern VideoBootStrap RISCOS_bootstrap;
extern VideoBootStrap N3DS_bootstrap;
extern VideoBootStrap RPI_bootstrap;
extern VideoBootStrap KMSDRM_bootstrap;
extern VideoBootStrap KMSDRM_LEGACY_bootstrap;
extern VideoBootStrap DUMMY_bootstrap;
extern VideoBootStrap DUMMY_evdev_bootstrap;
extern VideoBootStrap Wayland_bootstrap;
extern VideoBootStrap VIVANTE_bootstrap;
extern VideoBootStrap Emscripten_bootstrap;
extern VideoBootStrap OFFSCREEN_bootstrap;
extern VideoBootStrap NGAGE_bootstrap;
extern VideoBootStrap QNX_bootstrap;
/* Use SDL_OnVideoThread() sparingly, to avoid regressions in use cases that currently happen to work */
extern SDL_bool SDL_OnVideoThread(void);
extern SDL_VideoDevice *SDL_GetVideoDevice(void);
extern SDL_bool SDL_IsVideoContextExternal(void);
extern void SDL_SetSystemTheme(SDL_SystemTheme theme);
extern SDL_DisplayID SDL_AddBasicVideoDisplay(const SDL_DisplayMode *desktop_mode);
extern SDL_DisplayID SDL_AddVideoDisplay(const SDL_VideoDisplay *display, SDL_bool send_event);
extern void SDL_DelVideoDisplay(SDL_DisplayID display, SDL_bool send_event);
extern SDL_bool SDL_AddFullscreenDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode);
extern void SDL_ResetFullscreenDisplayModes(SDL_VideoDisplay *display);
extern void SDL_SetDesktopDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode);
extern void SDL_SetCurrentDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode);
extern void SDL_SetDisplayContentScale(SDL_VideoDisplay *display, float scale);
extern SDL_VideoDisplay *SDL_GetVideoDisplay(SDL_DisplayID display);
extern SDL_VideoDisplay *SDL_GetVideoDisplayForWindow(SDL_Window *window);
extern int SDL_GetDisplayIndex(SDL_DisplayID displayID);
extern SDL_DisplayData *SDL_GetDisplayDriverData(SDL_DisplayID display);
extern SDL_DisplayData *SDL_GetDisplayDriverDataForWindow(SDL_Window *window);
extern int SDL_GetMessageBoxCount(void);
extern void SDL_GL_DeduceMaxSupportedESProfile(int *major, int *minor);
extern int SDL_RecreateWindow(SDL_Window *window, Uint32 flags);
extern SDL_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);
extern void SDL_OnDisplayConnected(SDL_VideoDisplay *display);
extern void SDL_OnWindowShown(SDL_Window *window);
extern void SDL_OnWindowHidden(SDL_Window *window);
extern void SDL_OnWindowMoved(SDL_Window *window);
extern void SDL_OnWindowResized(SDL_Window *window);
extern void SDL_CheckWindowPixelSizeChanged(SDL_Window *window);
extern void SDL_OnWindowPixelSizeChanged(SDL_Window *window);
extern void SDL_OnWindowMinimized(SDL_Window *window);
extern void SDL_OnWindowMaximized(SDL_Window *window);
extern void SDL_OnWindowRestored(SDL_Window *window);
extern void SDL_OnWindowEnter(SDL_Window *window);
extern void SDL_OnWindowLeave(SDL_Window *window);
extern void SDL_OnWindowFocusGained(SDL_Window *window);
extern void SDL_OnWindowFocusLost(SDL_Window *window);
extern void SDL_OnWindowDisplayChanged(SDL_Window *window);
extern void SDL_UpdateWindowGrab(SDL_Window *window);
extern SDL_Window *SDL_GetFocusWindow(void);
extern SDL_bool SDL_ShouldAllowTopmost(void);
extern void SDL_ToggleDragAndDropSupport(void);
#endif /* SDL_sysvideo_h_ */

5252
external/sdl/SDL/src/video/SDL_video.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,60 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_video_c_h_
#define SDL_video_c_h_
#include "SDL_internal.h"
/**
* Initialize the video subsystem, optionally specifying a video driver.
*
* This function initializes the video subsystem, setting up a connection to
* the window manager, etc, and determines the available display modes and
* pixel formats, but does not initialize a window or graphics mode.
*
* If you use this function and you haven't used the SDL_INIT_VIDEO flag with
* either SDL_Init() or SDL_InitSubSystem(), you should call SDL_VideoQuit()
* before calling SDL_Quit().
*
* It is safe to call this function multiple times. SDL_VideoInit() will call
* SDL_VideoQuit() itself if the video subsystem has already been initialized.
*
* You can use SDL_GetNumVideoDrivers() and SDL_GetVideoDriver() to find a
* specific `driver_name`.
*
* \param driver_name the name of a video driver to initialize, or NULL for
* the default driver
* \returns 0 on success or a negative error code on failure; call
* SDL_GetError() for more information.
*/
extern int SDL_VideoInit(const char *driver_name);
/**
* Shut down the video subsystem, if initialized with SDL_VideoInit().
*
* This function closes all windows, and restores the original video mode.
*/
extern void SDL_VideoQuit(void);
extern int SDL_SetWindowTextureVSync(SDL_Window *window, int vsync);
#endif /* SDL_video_c_h_ */

View File

@ -0,0 +1,90 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_vulkan_internal_h_
#define SDL_vulkan_internal_h_
#include "SDL_internal.h"
#ifdef SDL_VIDEO_VULKAN
#if defined(SDL_LOADSO_DISABLED) || defined(SDL_LOADSO_DUMMY)
#error You should not be here.
#endif
#ifdef SDL_VIDEO_DRIVER_ANDROID
#define VK_USE_PLATFORM_ANDROID_KHR
#endif
#ifdef SDL_VIDEO_DRIVER_COCOA
#define VK_USE_PLATFORM_METAL_EXT
#define VK_USE_PLATFORM_MACOS_MVK
#endif
#ifdef SDL_VIDEO_DRIVER_UIKIT
#define VK_USE_PLATFORM_METAL_EXT
#define VK_USE_PLATFORM_IOS_MVK
#endif
#ifdef SDL_VIDEO_DRIVER_WAYLAND
#define VK_USE_PLATFORM_WAYLAND_KHR
#include "wayland/SDL_waylanddyn.h"
#endif
#ifdef SDL_VIDEO_DRIVER_WINDOWS
#define VK_USE_PLATFORM_WIN32_KHR
#include "../core/windows/SDL_windows.h"
#endif
#ifdef SDL_VIDEO_DRIVER_X11
#define VK_USE_PLATFORM_XLIB_KHR
#define VK_USE_PLATFORM_XCB_KHR
#endif
#define VK_NO_PROTOTYPES
#include "./khronos/vulkan/vulkan.h"
#include <SDL3/SDL_vulkan.h>
extern const char *SDL_Vulkan_GetResultString(VkResult result);
extern VkExtensionProperties *SDL_Vulkan_CreateInstanceExtensionsList(
PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties,
Uint32 *extensionCount); /* free returned list with SDL_free */
/* Implements functionality of SDL_Vulkan_GetInstanceExtensions for a list of
* names passed in nameCount and names. */
extern SDL_bool SDL_Vulkan_GetInstanceExtensions_Helper(unsigned *userCount,
const char **userNames,
unsigned nameCount,
const char *const *names);
/* Create a surface directly from a display connected to a physical device
* using the DisplayKHR extension.
* This needs to be passed an instance that was created with the VK_KHR_DISPLAY_EXTENSION_NAME
* extension. */
extern SDL_bool SDL_Vulkan_Display_CreateSurface(void *vkGetInstanceProcAddr,
VkInstance instance,
VkSurfaceKHR *surface);
#else
/* No SDL Vulkan support, just include the header for typedefs */
#include <SDL3/SDL_vulkan.h>
typedef void (*PFN_vkGetInstanceProcAddr)(void);
typedef int (*PFN_vkEnumerateInstanceExtensionProperties)(void);
#endif /* SDL_VIDEO_VULKAN */
#endif /* SDL_vulkan_internal_h_ */

View File

@ -0,0 +1,496 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_vulkan_internal.h"
#ifdef SDL_VIDEO_VULKAN
const char *SDL_Vulkan_GetResultString(VkResult result)
{
switch ((int)result) {
case VK_SUCCESS:
return "VK_SUCCESS";
case VK_NOT_READY:
return "VK_NOT_READY";
case VK_TIMEOUT:
return "VK_TIMEOUT";
case VK_EVENT_SET:
return "VK_EVENT_SET";
case VK_EVENT_RESET:
return "VK_EVENT_RESET";
case VK_INCOMPLETE:
return "VK_INCOMPLETE";
case VK_ERROR_OUT_OF_HOST_MEMORY:
return "VK_ERROR_OUT_OF_HOST_MEMORY";
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
case VK_ERROR_INITIALIZATION_FAILED:
return "VK_ERROR_INITIALIZATION_FAILED";
case VK_ERROR_DEVICE_LOST:
return "VK_ERROR_DEVICE_LOST";
case VK_ERROR_MEMORY_MAP_FAILED:
return "VK_ERROR_MEMORY_MAP_FAILED";
case VK_ERROR_LAYER_NOT_PRESENT:
return "VK_ERROR_LAYER_NOT_PRESENT";
case VK_ERROR_EXTENSION_NOT_PRESENT:
return "VK_ERROR_EXTENSION_NOT_PRESENT";
case VK_ERROR_FEATURE_NOT_PRESENT:
return "VK_ERROR_FEATURE_NOT_PRESENT";
case VK_ERROR_INCOMPATIBLE_DRIVER:
return "VK_ERROR_INCOMPATIBLE_DRIVER";
case VK_ERROR_TOO_MANY_OBJECTS:
return "VK_ERROR_TOO_MANY_OBJECTS";
case VK_ERROR_FORMAT_NOT_SUPPORTED:
return "VK_ERROR_FORMAT_NOT_SUPPORTED";
case VK_ERROR_FRAGMENTED_POOL:
return "VK_ERROR_FRAGMENTED_POOL";
case VK_ERROR_UNKNOWN:
return "VK_ERROR_UNKNOWN";
case VK_ERROR_OUT_OF_POOL_MEMORY:
return "VK_ERROR_OUT_OF_POOL_MEMORY";
case VK_ERROR_INVALID_EXTERNAL_HANDLE:
return "VK_ERROR_INVALID_EXTERNAL_HANDLE";
case VK_ERROR_FRAGMENTATION:
return "VK_ERROR_FRAGMENTATION";
case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS:
return "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS";
case VK_ERROR_SURFACE_LOST_KHR:
return "VK_ERROR_SURFACE_LOST_KHR";
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
case VK_SUBOPTIMAL_KHR:
return "VK_SUBOPTIMAL_KHR";
case VK_ERROR_OUT_OF_DATE_KHR:
return "VK_ERROR_OUT_OF_DATE_KHR";
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
case VK_ERROR_VALIDATION_FAILED_EXT:
return "VK_ERROR_VALIDATION_FAILED_EXT";
case VK_ERROR_INVALID_SHADER_NV:
return "VK_ERROR_INVALID_SHADER_NV";
#if VK_HEADER_VERSION >= 135 && VK_HEADER_VERSION < 162
case VK_ERROR_INCOMPATIBLE_VERSION_KHR:
return "VK_ERROR_INCOMPATIBLE_VERSION_KHR";
#endif
case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT:
return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT";
case VK_ERROR_NOT_PERMITTED_EXT:
return "VK_ERROR_NOT_PERMITTED_EXT";
case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT";
case VK_THREAD_IDLE_KHR:
return "VK_THREAD_IDLE_KHR";
case VK_THREAD_DONE_KHR:
return "VK_THREAD_DONE_KHR";
case VK_OPERATION_DEFERRED_KHR:
return "VK_OPERATION_DEFERRED_KHR";
case VK_OPERATION_NOT_DEFERRED_KHR:
return "VK_OPERATION_NOT_DEFERRED_KHR";
case VK_PIPELINE_COMPILE_REQUIRED_EXT:
return "VK_PIPELINE_COMPILE_REQUIRED_EXT";
default:
break;
}
if (result < 0) {
return "VK_ERROR_<Unknown>";
}
return "VK_<Unknown>";
}
VkExtensionProperties *SDL_Vulkan_CreateInstanceExtensionsList(
PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties,
Uint32 *extensionCount)
{
Uint32 count = 0;
VkResult result = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL);
VkExtensionProperties *retval;
if (result == VK_ERROR_INCOMPATIBLE_DRIVER) {
/* Avoid the ERR_MAX_STRLEN limit by passing part of the message as a string argument. */
SDL_SetError(
"You probably don't have a working Vulkan driver installed. %s %s %s(%d)",
"Getting Vulkan extensions failed:",
"vkEnumerateInstanceExtensionProperties returned",
SDL_Vulkan_GetResultString(result),
(int)result);
return NULL;
} else if (result != VK_SUCCESS) {
SDL_SetError(
"Getting Vulkan extensions failed: vkEnumerateInstanceExtensionProperties returned "
"%s(%d)",
SDL_Vulkan_GetResultString(result),
(int)result);
return NULL;
}
if (count == 0) {
retval = SDL_calloc(1, sizeof(VkExtensionProperties)); // so we can return non-null
} else {
retval = SDL_calloc(count, sizeof(VkExtensionProperties));
}
if (retval == NULL) {
SDL_OutOfMemory();
return NULL;
}
result = vkEnumerateInstanceExtensionProperties(NULL, &count, retval);
if (result != VK_SUCCESS) {
SDL_SetError(
"Getting Vulkan extensions failed: vkEnumerateInstanceExtensionProperties returned "
"%s(%d)",
SDL_Vulkan_GetResultString(result),
(int)result);
SDL_free(retval);
return NULL;
}
*extensionCount = count;
return retval;
}
SDL_bool SDL_Vulkan_GetInstanceExtensions_Helper(unsigned *userCount,
const char **userNames,
unsigned nameCount,
const char *const *names)
{
if (userNames) {
unsigned i;
if (*userCount < nameCount) {
SDL_SetError("Output array for SDL_Vulkan_GetInstanceExtensions needs to be at least %d big", nameCount);
return SDL_FALSE;
}
for (i = 0; i < nameCount; i++) {
userNames[i] = names[i];
}
}
*userCount = nameCount;
return SDL_TRUE;
}
/* Alpha modes, in order of preference */
static const VkDisplayPlaneAlphaFlagBitsKHR alphaModes[4] = {
VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR,
VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR,
VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR,
VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR,
};
SDL_bool SDL_Vulkan_Display_CreateSurface(void *vkGetInstanceProcAddr_,
VkInstance instance,
VkSurfaceKHR *surface)
{
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
(PFN_vkGetInstanceProcAddr)vkGetInstanceProcAddr_;
#define VULKAN_INSTANCE_FUNCTION(name) \
PFN_##name name = (PFN_##name)vkGetInstanceProcAddr((VkInstance)instance, #name)
VULKAN_INSTANCE_FUNCTION(vkEnumeratePhysicalDevices);
VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceDisplayPropertiesKHR);
VULKAN_INSTANCE_FUNCTION(vkGetDisplayModePropertiesKHR);
VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceDisplayPlanePropertiesKHR);
VULKAN_INSTANCE_FUNCTION(vkGetDisplayPlaneCapabilitiesKHR);
VULKAN_INSTANCE_FUNCTION(vkGetDisplayPlaneSupportedDisplaysKHR);
VULKAN_INSTANCE_FUNCTION(vkCreateDisplayPlaneSurfaceKHR);
#undef VULKAN_INSTANCE_FUNCTION
VkDisplaySurfaceCreateInfoKHR createInfo;
VkResult result;
uint32_t physicalDeviceCount = 0;
VkPhysicalDevice *physicalDevices = NULL;
uint32_t physicalDeviceIndex;
const char *chosenDisplayId;
int displayId = 0; /* Counting from physical device 0, display 0 */
if (!vkEnumeratePhysicalDevices ||
!vkGetPhysicalDeviceDisplayPropertiesKHR ||
!vkGetDisplayModePropertiesKHR ||
!vkGetPhysicalDeviceDisplayPlanePropertiesKHR ||
!vkGetDisplayPlaneCapabilitiesKHR ||
!vkGetDisplayPlaneSupportedDisplaysKHR ||
!vkCreateDisplayPlaneSurfaceKHR) {
SDL_SetError(VK_KHR_DISPLAY_EXTENSION_NAME " extension is not enabled in the Vulkan instance.");
goto error;
}
chosenDisplayId = SDL_getenv("SDL_VULKAN_DISPLAY");
if (chosenDisplayId != NULL) {
displayId = SDL_atoi(chosenDisplayId);
}
/* Enumerate physical devices */
result = vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL);
if (result != VK_SUCCESS) {
SDL_SetError("Could not enumerate Vulkan physical devices");
goto error;
}
if (physicalDeviceCount == 0) {
SDL_SetError("No Vulkan physical devices");
goto error;
}
physicalDevices = SDL_malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount);
if (physicalDevices == NULL) {
SDL_OutOfMemory();
goto error;
}
result = vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices);
if (result != VK_SUCCESS) {
SDL_SetError("Error enumerating physical devices");
goto error;
}
for (physicalDeviceIndex = 0; physicalDeviceIndex < physicalDeviceCount; physicalDeviceIndex++) {
VkPhysicalDevice physicalDevice = physicalDevices[physicalDeviceIndex];
uint32_t displayPropertiesCount = 0;
VkDisplayPropertiesKHR *displayProperties = NULL;
uint32_t displayModePropertiesCount = 0;
VkDisplayModePropertiesKHR *displayModeProperties = NULL;
int bestMatchIndex = -1;
uint32_t refreshRate = 0;
uint32_t i;
uint32_t displayPlanePropertiesCount = 0;
int planeIndex = -1;
VkDisplayKHR display;
VkDisplayPlanePropertiesKHR *displayPlaneProperties = NULL;
VkExtent2D extent;
VkDisplayPlaneCapabilitiesKHR planeCaps = { 0 };
/* Get information about the physical displays */
result = vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertiesCount, NULL);
if (result != VK_SUCCESS || displayPropertiesCount == 0) {
/* This device has no physical device display properties, move on to next. */
continue;
}
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Number of display properties for device %u: %u",
physicalDeviceIndex, displayPropertiesCount);
if (displayId < 0 || (uint32_t)displayId >= displayPropertiesCount) {
/* Display id specified was higher than number of available displays, move to next physical device. */
displayId -= displayPropertiesCount;
continue;
}
displayProperties = SDL_malloc(sizeof(VkDisplayPropertiesKHR) * displayPropertiesCount);
if (displayProperties == NULL) {
SDL_OutOfMemory();
goto error;
}
result = vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertiesCount, displayProperties);
if (result != VK_SUCCESS || displayPropertiesCount == 0) {
SDL_free(displayProperties);
SDL_SetError("Error enumerating physical device displays");
goto error;
}
display = displayProperties[displayId].display;
extent = displayProperties[displayId].physicalResolution;
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Display: %s Native resolution: %ux%u",
displayProperties[displayId].displayName, extent.width, extent.height);
SDL_free(displayProperties);
displayProperties = NULL;
/* Get display mode properties for the chosen display */
result = vkGetDisplayModePropertiesKHR(physicalDevice, display, &displayModePropertiesCount, NULL);
if (result != VK_SUCCESS || displayModePropertiesCount == 0) {
SDL_SetError("Error enumerating display modes");
goto error;
}
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Number of display modes: %u", displayModePropertiesCount);
displayModeProperties = SDL_malloc(sizeof(VkDisplayModePropertiesKHR) * displayModePropertiesCount);
if (displayModeProperties == NULL) {
SDL_OutOfMemory();
goto error;
}
result = vkGetDisplayModePropertiesKHR(physicalDevice, display, &displayModePropertiesCount, displayModeProperties);
if (result != VK_SUCCESS || displayModePropertiesCount == 0) {
SDL_SetError("Error enumerating display modes");
SDL_free(displayModeProperties);
goto error;
}
/* Try to find a display mode that matches the native resolution */
for (i = 0; i < displayModePropertiesCount; ++i) {
if (displayModeProperties[i].parameters.visibleRegion.width == extent.width &&
displayModeProperties[i].parameters.visibleRegion.height == extent.height &&
displayModeProperties[i].parameters.refreshRate > refreshRate) {
bestMatchIndex = i;
refreshRate = displayModeProperties[i].parameters.refreshRate;
}
}
if (bestMatchIndex < 0) {
SDL_SetError("Found no matching display mode");
SDL_free(displayModeProperties);
goto error;
}
SDL_zero(createInfo);
createInfo.displayMode = displayModeProperties[bestMatchIndex].displayMode;
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Matching mode %ux%u with refresh rate %u",
displayModeProperties[bestMatchIndex].parameters.visibleRegion.width,
displayModeProperties[bestMatchIndex].parameters.visibleRegion.height,
refreshRate);
SDL_free(displayModeProperties);
displayModeProperties = NULL;
/* Try to find a plane index that supports our display */
result = vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &displayPlanePropertiesCount, NULL);
if (result != VK_SUCCESS || displayPlanePropertiesCount == 0) {
SDL_SetError("Error enumerating display planes");
goto error;
}
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Number of display planes: %u", displayPlanePropertiesCount);
displayPlaneProperties = SDL_malloc(sizeof(VkDisplayPlanePropertiesKHR) * displayPlanePropertiesCount);
if (displayPlaneProperties == NULL) {
SDL_OutOfMemory();
goto error;
}
result = vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &displayPlanePropertiesCount, displayPlaneProperties);
if (result != VK_SUCCESS || displayPlanePropertiesCount == 0) {
SDL_SetError("Error enumerating display plane properties");
SDL_free(displayPlaneProperties);
goto error;
}
for (i = 0; i < displayPlanePropertiesCount; ++i) {
uint32_t planeSupportedDisplaysCount = 0;
VkDisplayKHR *planeSupportedDisplays = NULL;
uint32_t j;
/* Check if plane is attached to a display, if not, continue. */
if (displayPlaneProperties[i].currentDisplay == VK_NULL_HANDLE) {
continue;
}
/* Check supported displays for this plane. */
result = vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, i, &planeSupportedDisplaysCount, NULL);
if (result != VK_SUCCESS || planeSupportedDisplaysCount == 0) {
continue; /* No supported displays, on to next plane. */
}
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Number of supported displays for plane %u: %u", i, planeSupportedDisplaysCount);
planeSupportedDisplays = SDL_malloc(sizeof(VkDisplayKHR) * planeSupportedDisplaysCount);
if (planeSupportedDisplays == NULL) {
SDL_free(displayPlaneProperties);
SDL_OutOfMemory();
goto error;
}
result = vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, i, &planeSupportedDisplaysCount, planeSupportedDisplays);
if (result != VK_SUCCESS || planeSupportedDisplaysCount == 0) {
SDL_SetError("Error enumerating supported displays, or no supported displays");
SDL_free(planeSupportedDisplays);
SDL_free(displayPlaneProperties);
goto error;
}
for (j = 0; j < planeSupportedDisplaysCount && planeSupportedDisplays[j] != display; ++j) {
}
SDL_free(planeSupportedDisplays);
planeSupportedDisplays = NULL;
if (j == planeSupportedDisplaysCount) {
/* This display is not supported for this plane, move on. */
continue;
}
result = vkGetDisplayPlaneCapabilitiesKHR(physicalDevice, createInfo.displayMode, i, &planeCaps);
if (result != VK_SUCCESS) {
SDL_SetError("Error getting display plane capabilities");
SDL_free(displayPlaneProperties);
goto error;
}
/* Check if plane fulfills extent requirements. */
if (extent.width >= planeCaps.minDstExtent.width && extent.height >= planeCaps.minDstExtent.height &&
extent.width <= planeCaps.maxDstExtent.width && extent.height <= planeCaps.maxDstExtent.height) {
/* If it does, choose this plane. */
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Choosing plane %d, minimum extent %dx%d maximum extent %dx%d", i,
planeCaps.minDstExtent.width, planeCaps.minDstExtent.height,
planeCaps.maxDstExtent.width, planeCaps.maxDstExtent.height);
planeIndex = i;
break;
}
}
if (planeIndex < 0) {
SDL_SetError("No plane supports the selected resolution");
SDL_free(displayPlaneProperties);
goto error;
}
createInfo.planeIndex = planeIndex;
createInfo.planeStackIndex = displayPlaneProperties[planeIndex].currentStackIndex;
SDL_free(displayPlaneProperties);
displayPlaneProperties = NULL;
/* Find a supported alpha mode. Not all planes support OPAQUE */
createInfo.alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
for (i = 0; i < SDL_arraysize(alphaModes); i++) {
if (planeCaps.supportedAlpha & alphaModes[i]) {
createInfo.alphaMode = alphaModes[i];
break;
}
}
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Chose alpha mode 0x%x", createInfo.alphaMode);
/* Found a match, finally! Fill in extent, and break from loop */
createInfo.imageExtent = extent;
break;
}
SDL_free(physicalDevices);
physicalDevices = NULL;
if (physicalDeviceIndex == physicalDeviceCount) {
SDL_SetError("No usable displays found or requested display out of range");
return SDL_FALSE;
}
createInfo.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR;
createInfo.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
createInfo.globalAlpha = 1.0f;
result = vkCreateDisplayPlaneSurfaceKHR(instance, &createInfo, NULL, surface);
if (result != VK_SUCCESS) {
SDL_SetError("vkCreateDisplayPlaneSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result));
return SDL_FALSE;
}
SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Created surface");
return SDL_TRUE;
error:
SDL_free(physicalDevices);
return SDL_FALSE;
}
#endif

2375
external/sdl/SDL/src/video/SDL_yuv.c vendored Normal file

File diff suppressed because it is too large Load Diff

36
external/sdl/SDL/src/video/SDL_yuv_c.h vendored Normal file
View File

@ -0,0 +1,36 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_yuv_c_h_
#define SDL_yuv_c_h_
#include "SDL_internal.h"
/* YUV conversion functions */
extern int SDL_ConvertPixels_YUV_to_RGB(int width, int height, Uint32 src_format, const void *src, int src_pitch, Uint32 dst_format, void *dst, int dst_pitch);
extern int SDL_ConvertPixels_RGB_to_YUV(int width, int height, Uint32 src_format, const void *src, int src_pitch, Uint32 dst_format, void *dst, int dst_pitch);
extern int SDL_ConvertPixels_YUV_to_YUV(int width, int height, Uint32 src_format, const void *src, int src_pitch, Uint32 dst_format, void *dst, int dst_pitch);
extern int SDL_CalculateYUVSize(Uint32 format, int w, int h, size_t *size, size_t *pitch);
#endif /* SDL_yuv_c_h_ */

View File

@ -0,0 +1,44 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
#include "SDL_androidvideo.h"
#include "SDL_androidclipboard.h"
#include "../../core/android/SDL_android.h"
int Android_SetClipboardText(SDL_VideoDevice *_this, const char *text)
{
return Android_JNI_SetClipboardText(text);
}
char *Android_GetClipboardText(SDL_VideoDevice *_this)
{
return Android_JNI_GetClipboardText();
}
SDL_bool Android_HasClipboardText(SDL_VideoDevice *_this)
{
return Android_JNI_HasClipboardText();
}
#endif /* SDL_VIDEO_DRIVER_ANDROID */

View File

@ -0,0 +1,30 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_androidclipboard_h_
#define SDL_androidclipboard_h_
extern int Android_SetClipboardText(SDL_VideoDevice *_this, const char *text);
extern char *Android_GetClipboardText(SDL_VideoDevice *_this);
extern SDL_bool Android_HasClipboardText(SDL_VideoDevice *_this);
#endif /* SDL_androidclipboard_h_ */

View File

@ -0,0 +1,255 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
#include "SDL_androidevents.h"
#include "SDL_androidkeyboard.h"
#include "SDL_androidwindow.h"
#include "../SDL_sysvideo.h"
#include "../../events/SDL_events_c.h"
#include "../../audio/android/SDL_androidaudio.h"
#include "../../audio/aaudio/SDL_aaudio.h"
#include "../../audio/openslES/SDL_openslES.h"
/* Number of 'type' events in the event queue */
static int SDL_NumberOfEvents(Uint32 type)
{
return SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type);
}
#ifdef SDL_VIDEO_OPENGL_EGL
static void android_egl_context_restore(SDL_Window *window)
{
if (window) {
SDL_Event event;
SDL_WindowData *data = window->driverdata;
if (SDL_GL_MakeCurrent(window, (SDL_GLContext)data->egl_context) < 0) {
/* The context is no longer valid, create a new one */
data->egl_context = (EGLContext)SDL_GL_CreateContext(window);
SDL_GL_MakeCurrent(window, (SDL_GLContext)data->egl_context);
event.type = SDL_EVENT_RENDER_DEVICE_RESET;
event.common.timestamp = 0;
SDL_PushEvent(&event);
}
data->backup_done = 0;
if (data->has_swap_interval) {
SDL_GL_SetSwapInterval(data->swap_interval);
}
}
}
static void android_egl_context_backup(SDL_Window *window)
{
if (window) {
int interval = 0;
/* Keep a copy of the EGL Context so we can try to restore it when we resume */
SDL_WindowData *data = window->driverdata;
data->egl_context = SDL_GL_GetCurrentContext();
/* Save/Restore the swap interval / vsync */
if (SDL_GL_GetSwapInterval(&interval) == 0) {
data->has_swap_interval = 1;
data->swap_interval = interval;
}
/* We need to do this so the EGLSurface can be freed */
SDL_GL_MakeCurrent(window, NULL);
data->backup_done = 1;
}
}
#endif
/*
* Android_ResumeSem and Android_PauseSem are signaled from Java_org_libsdl_app_SDLActivity_nativePause and Java_org_libsdl_app_SDLActivity_nativeResume
* When the pause semaphore is signaled, if Android_PumpEvents_Blocking is used, the event loop will block until the resume signal is emitted.
*
* No polling necessary
*/
void Android_PumpEvents_Blocking(SDL_VideoDevice *_this)
{
SDL_VideoData *videodata = _this->driverdata;
if (videodata->isPaused) {
SDL_bool isContextExternal = SDL_IsVideoContextExternal();
#ifdef SDL_VIDEO_OPENGL_EGL
/* Make sure this is the last thing we do before pausing */
if (!isContextExternal) {
SDL_LockMutex(Android_ActivityMutex);
android_egl_context_backup(Android_Window);
SDL_UnlockMutex(Android_ActivityMutex);
}
#endif
ANDROIDAUDIO_PauseDevices();
openslES_PauseDevices();
aaudio_PauseDevices();
if (SDL_WaitSemaphore(Android_ResumeSem) == 0) {
videodata->isPaused = 0;
/* Android_ResumeSem was signaled */
SDL_SendAppEvent(SDL_EVENT_WILL_ENTER_FOREGROUND);
ANDROIDAUDIO_ResumeDevices();
openslES_ResumeDevices();
aaudio_ResumeDevices();
/* Restore the GL Context from here, as this operation is thread dependent */
#ifdef SDL_VIDEO_OPENGL_EGL
if (!isContextExternal && !SDL_HasEvent(SDL_EVENT_QUIT)) {
SDL_LockMutex(Android_ActivityMutex);
android_egl_context_restore(Android_Window);
SDL_UnlockMutex(Android_ActivityMutex);
}
#endif
/* Make sure SW Keyboard is restored when an app becomes foreground */
if (SDL_TextInputActive()) {
Android_StartTextInput(_this); /* Only showTextInput */
}
SDL_SendAppEvent(SDL_EVENT_DID_ENTER_FOREGROUND);
SDL_SendWindowEvent(Android_Window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
}
} else {
if (videodata->isPausing || SDL_TryWaitSemaphore(Android_PauseSem) == 0) {
/* Android_PauseSem was signaled */
if (videodata->isPausing == 0) {
SDL_SendWindowEvent(Android_Window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0);
SDL_SendAppEvent(SDL_EVENT_WILL_ENTER_BACKGROUND);
SDL_SendAppEvent(SDL_EVENT_DID_ENTER_BACKGROUND);
}
/* We've been signaled to pause (potentially several times), but before we block ourselves,
* we need to make sure that the very last event (of the first pause sequence, if several)
* has reached the app */
if (SDL_NumberOfEvents(SDL_EVENT_DID_ENTER_BACKGROUND) > SDL_GetSemaphoreValue(Android_PauseSem)) {
videodata->isPausing = 1;
} else {
videodata->isPausing = 0;
videodata->isPaused = 1;
}
}
}
if (aaudio_DetectBrokenPlayState()) {
aaudio_PauseDevices();
aaudio_ResumeDevices();
}
}
void Android_PumpEvents_NonBlocking(SDL_VideoDevice *_this)
{
SDL_VideoData *videodata = _this->driverdata;
static int backup_context = 0;
if (videodata->isPaused) {
SDL_bool isContextExternal = SDL_IsVideoContextExternal();
if (backup_context) {
#ifdef SDL_VIDEO_OPENGL_EGL
if (!isContextExternal) {
SDL_LockMutex(Android_ActivityMutex);
android_egl_context_backup(Android_Window);
SDL_UnlockMutex(Android_ActivityMutex);
}
#endif
if (videodata->pauseAudio) {
ANDROIDAUDIO_PauseDevices();
openslES_PauseDevices();
aaudio_PauseDevices();
}
backup_context = 0;
}
if (SDL_TryWaitSemaphore(Android_ResumeSem) == 0) {
videodata->isPaused = 0;
/* Android_ResumeSem was signaled */
SDL_SendAppEvent(SDL_EVENT_WILL_ENTER_FOREGROUND);
if (videodata->pauseAudio) {
ANDROIDAUDIO_ResumeDevices();
openslES_ResumeDevices();
aaudio_ResumeDevices();
}
#ifdef SDL_VIDEO_OPENGL_EGL
/* Restore the GL Context from here, as this operation is thread dependent */
if (!isContextExternal && !SDL_HasEvent(SDL_EVENT_QUIT)) {
SDL_LockMutex(Android_ActivityMutex);
android_egl_context_restore(Android_Window);
SDL_UnlockMutex(Android_ActivityMutex);
}
#endif
/* Make sure SW Keyboard is restored when an app becomes foreground */
if (SDL_TextInputActive()) {
Android_StartTextInput(_this); /* Only showTextInput */
}
SDL_SendAppEvent(SDL_EVENT_DID_ENTER_FOREGROUND);
SDL_SendWindowEvent(Android_Window, SDL_EVENT_WINDOW_RESTORED, 0, 0);
}
} else {
if (videodata->isPausing || SDL_TryWaitSemaphore(Android_PauseSem) == 0) {
/* Android_PauseSem was signaled */
if (videodata->isPausing == 0) {
SDL_SendWindowEvent(Android_Window, SDL_EVENT_WINDOW_MINIMIZED, 0, 0);
SDL_SendAppEvent(SDL_EVENT_WILL_ENTER_BACKGROUND);
SDL_SendAppEvent(SDL_EVENT_DID_ENTER_BACKGROUND);
}
/* We've been signaled to pause (potentially several times), but before we block ourselves,
* we need to make sure that the very last event (of the first pause sequence, if several)
* has reached the app */
if (SDL_NumberOfEvents(SDL_EVENT_DID_ENTER_BACKGROUND) > SDL_GetSemaphoreValue(Android_PauseSem)) {
videodata->isPausing = 1;
} else {
videodata->isPausing = 0;
videodata->isPaused = 1;
backup_context = 1;
}
}
}
if (aaudio_DetectBrokenPlayState()) {
aaudio_PauseDevices();
aaudio_ResumeDevices();
}
}
#endif /* SDL_VIDEO_DRIVER_ANDROID */

View File

@ -0,0 +1,26 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_androidvideo.h"
extern void Android_PumpEvents_Blocking(SDL_VideoDevice *_this);
extern void Android_PumpEvents_NonBlocking(SDL_VideoDevice *_this);

View File

@ -0,0 +1,85 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_DRIVER_ANDROID) && defined(SDL_VIDEO_OPENGL_EGL)
/* Android SDL video driver implementation */
#include "../SDL_egl_c.h"
#include "SDL_androidwindow.h"
#include "SDL_androidvideo.h"
#include "SDL_androidgl.h"
#include "../../core/android/SDL_android.h"
#include <android/log.h>
#include <dlfcn.h>
int Android_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context)
{
if (window && context) {
return SDL_EGL_MakeCurrent(_this, window->driverdata->egl_surface, context);
} else {
return SDL_EGL_MakeCurrent(_this, NULL, NULL);
}
}
SDL_GLContext Android_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_GLContext ret;
Android_ActivityMutex_Lock_Running();
ret = SDL_EGL_CreateContext(_this, window->driverdata->egl_surface);
SDL_UnlockMutex(Android_ActivityMutex);
return ret;
}
int Android_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
int retval;
SDL_LockMutex(Android_ActivityMutex);
/* The following two calls existed in the original Java code
* If you happen to have a device that's affected by their removal,
* please report to our bug tracker. -- Gabriel
*/
/*_this->egl_data->eglWaitNative(EGL_CORE_NATIVE_ENGINE);
_this->egl_data->eglWaitGL();*/
retval = SDL_EGL_SwapBuffers(_this, window->driverdata->egl_surface);
SDL_UnlockMutex(Android_ActivityMutex);
return retval;
}
int Android_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType)0, 0);
}
#endif /* SDL_VIDEO_DRIVER_ANDROID */

View File

@ -0,0 +1,31 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_androidgl_h_
#define SDL_androidgl_h_
SDL_GLContext Android_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
int Android_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
int Android_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
int Android_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path);
#endif /* SDL_androidgl_h_ */

View File

@ -0,0 +1,367 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
#include <android/log.h>
#include "../../events/SDL_events_c.h"
#include "SDL_androidkeyboard.h"
#include "../../core/android/SDL_android.h"
static SDL_Scancode Android_Keycodes[] = {
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_UNKNOWN */
SDL_SCANCODE_SOFTLEFT, /* AKEYCODE_SOFT_LEFT */
SDL_SCANCODE_SOFTRIGHT, /* AKEYCODE_SOFT_RIGHT */
SDL_SCANCODE_AC_HOME, /* AKEYCODE_HOME */
SDL_SCANCODE_AC_BACK, /* AKEYCODE_BACK */
SDL_SCANCODE_CALL, /* AKEYCODE_CALL */
SDL_SCANCODE_ENDCALL, /* AKEYCODE_ENDCALL */
SDL_SCANCODE_0, /* AKEYCODE_0 */
SDL_SCANCODE_1, /* AKEYCODE_1 */
SDL_SCANCODE_2, /* AKEYCODE_2 */
SDL_SCANCODE_3, /* AKEYCODE_3 */
SDL_SCANCODE_4, /* AKEYCODE_4 */
SDL_SCANCODE_5, /* AKEYCODE_5 */
SDL_SCANCODE_6, /* AKEYCODE_6 */
SDL_SCANCODE_7, /* AKEYCODE_7 */
SDL_SCANCODE_8, /* AKEYCODE_8 */
SDL_SCANCODE_9, /* AKEYCODE_9 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_STAR */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_POUND */
SDL_SCANCODE_UP, /* AKEYCODE_DPAD_UP */
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_VOLUMEUP, /* AKEYCODE_VOLUME_UP */
SDL_SCANCODE_VOLUMEDOWN, /* AKEYCODE_VOLUME_DOWN */
SDL_SCANCODE_POWER, /* AKEYCODE_POWER */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_CAMERA */
SDL_SCANCODE_CLEAR, /* AKEYCODE_CLEAR */
SDL_SCANCODE_A, /* AKEYCODE_A */
SDL_SCANCODE_B, /* AKEYCODE_B */
SDL_SCANCODE_C, /* AKEYCODE_C */
SDL_SCANCODE_D, /* AKEYCODE_D */
SDL_SCANCODE_E, /* AKEYCODE_E */
SDL_SCANCODE_F, /* AKEYCODE_F */
SDL_SCANCODE_G, /* AKEYCODE_G */
SDL_SCANCODE_H, /* AKEYCODE_H */
SDL_SCANCODE_I, /* AKEYCODE_I */
SDL_SCANCODE_J, /* AKEYCODE_J */
SDL_SCANCODE_K, /* AKEYCODE_K */
SDL_SCANCODE_L, /* AKEYCODE_L */
SDL_SCANCODE_M, /* AKEYCODE_M */
SDL_SCANCODE_N, /* AKEYCODE_N */
SDL_SCANCODE_O, /* AKEYCODE_O */
SDL_SCANCODE_P, /* AKEYCODE_P */
SDL_SCANCODE_Q, /* AKEYCODE_Q */
SDL_SCANCODE_R, /* AKEYCODE_R */
SDL_SCANCODE_S, /* AKEYCODE_S */
SDL_SCANCODE_T, /* AKEYCODE_T */
SDL_SCANCODE_U, /* AKEYCODE_U */
SDL_SCANCODE_V, /* AKEYCODE_V */
SDL_SCANCODE_W, /* AKEYCODE_W */
SDL_SCANCODE_X, /* AKEYCODE_X */
SDL_SCANCODE_Y, /* AKEYCODE_Y */
SDL_SCANCODE_Z, /* AKEYCODE_Z */
SDL_SCANCODE_COMMA, /* AKEYCODE_COMMA */
SDL_SCANCODE_PERIOD, /* AKEYCODE_PERIOD */
SDL_SCANCODE_LALT, /* AKEYCODE_ALT_LEFT */
SDL_SCANCODE_RALT, /* AKEYCODE_ALT_RIGHT */
SDL_SCANCODE_LSHIFT, /* AKEYCODE_SHIFT_LEFT */
SDL_SCANCODE_RSHIFT, /* AKEYCODE_SHIFT_RIGHT */
SDL_SCANCODE_TAB, /* AKEYCODE_TAB */
SDL_SCANCODE_SPACE, /* AKEYCODE_SPACE */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_SYM */
SDL_SCANCODE_WWW, /* AKEYCODE_EXPLORER */
SDL_SCANCODE_MAIL, /* AKEYCODE_ENVELOPE */
SDL_SCANCODE_RETURN, /* AKEYCODE_ENTER */
SDL_SCANCODE_BACKSPACE, /* AKEYCODE_DEL */
SDL_SCANCODE_GRAVE, /* AKEYCODE_GRAVE */
SDL_SCANCODE_MINUS, /* AKEYCODE_MINUS */
SDL_SCANCODE_EQUALS, /* AKEYCODE_EQUALS */
SDL_SCANCODE_LEFTBRACKET, /* AKEYCODE_LEFT_BRACKET */
SDL_SCANCODE_RIGHTBRACKET, /* AKEYCODE_RIGHT_BRACKET */
SDL_SCANCODE_BACKSLASH, /* AKEYCODE_BACKSLASH */
SDL_SCANCODE_SEMICOLON, /* AKEYCODE_SEMICOLON */
SDL_SCANCODE_APOSTROPHE, /* AKEYCODE_APOSTROPHE */
SDL_SCANCODE_SLASH, /* AKEYCODE_SLASH */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_AT */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_NUM */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_HEADSETHOOK */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_FOCUS */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_PLUS */
SDL_SCANCODE_MENU, /* AKEYCODE_MENU */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_NOTIFICATION */
SDL_SCANCODE_AC_SEARCH, /* AKEYCODE_SEARCH */
SDL_SCANCODE_AUDIOPLAY, /* AKEYCODE_MEDIA_PLAY_PAUSE */
SDL_SCANCODE_AUDIOSTOP, /* AKEYCODE_MEDIA_STOP */
SDL_SCANCODE_AUDIONEXT, /* AKEYCODE_MEDIA_NEXT */
SDL_SCANCODE_AUDIOPREV, /* AKEYCODE_MEDIA_PREVIOUS */
SDL_SCANCODE_AUDIOREWIND, /* AKEYCODE_MEDIA_REWIND */
SDL_SCANCODE_AUDIOFASTFORWARD, /* AKEYCODE_MEDIA_FAST_FORWARD */
SDL_SCANCODE_MUTE, /* AKEYCODE_MUTE */
SDL_SCANCODE_PAGEUP, /* AKEYCODE_PAGE_UP */
SDL_SCANCODE_PAGEDOWN, /* AKEYCODE_PAGE_DOWN */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_PICTSYMBOLS */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_SWITCH_CHARSET */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_A */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_B */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_C */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_X */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_Y */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_Z */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_L1 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_R1 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_L2 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_R2 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_THUMBL */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_THUMBR */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_START */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_SELECT */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_MODE */
SDL_SCANCODE_ESCAPE, /* AKEYCODE_ESCAPE */
SDL_SCANCODE_DELETE, /* AKEYCODE_FORWARD_DEL */
SDL_SCANCODE_LCTRL, /* AKEYCODE_CTRL_LEFT */
SDL_SCANCODE_RCTRL, /* AKEYCODE_CTRL_RIGHT */
SDL_SCANCODE_CAPSLOCK, /* AKEYCODE_CAPS_LOCK */
SDL_SCANCODE_SCROLLLOCK, /* AKEYCODE_SCROLL_LOCK */
SDL_SCANCODE_LGUI, /* AKEYCODE_META_LEFT */
SDL_SCANCODE_RGUI, /* AKEYCODE_META_RIGHT */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_FUNCTION */
SDL_SCANCODE_PRINTSCREEN, /* AKEYCODE_SYSRQ */
SDL_SCANCODE_PAUSE, /* AKEYCODE_BREAK */
SDL_SCANCODE_HOME, /* AKEYCODE_MOVE_HOME */
SDL_SCANCODE_END, /* AKEYCODE_MOVE_END */
SDL_SCANCODE_INSERT, /* AKEYCODE_INSERT */
SDL_SCANCODE_AC_FORWARD, /* AKEYCODE_FORWARD */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MEDIA_PLAY */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MEDIA_PAUSE */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MEDIA_CLOSE */
SDL_SCANCODE_EJECT, /* AKEYCODE_MEDIA_EJECT */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MEDIA_RECORD */
SDL_SCANCODE_F1, /* AKEYCODE_F1 */
SDL_SCANCODE_F2, /* AKEYCODE_F2 */
SDL_SCANCODE_F3, /* AKEYCODE_F3 */
SDL_SCANCODE_F4, /* AKEYCODE_F4 */
SDL_SCANCODE_F5, /* AKEYCODE_F5 */
SDL_SCANCODE_F6, /* AKEYCODE_F6 */
SDL_SCANCODE_F7, /* AKEYCODE_F7 */
SDL_SCANCODE_F8, /* AKEYCODE_F8 */
SDL_SCANCODE_F9, /* AKEYCODE_F9 */
SDL_SCANCODE_F10, /* AKEYCODE_F10 */
SDL_SCANCODE_F11, /* AKEYCODE_F11 */
SDL_SCANCODE_F12, /* AKEYCODE_F12 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_NUM_LOCK */
SDL_SCANCODE_KP_0, /* AKEYCODE_NUMPAD_0 */
SDL_SCANCODE_KP_1, /* AKEYCODE_NUMPAD_1 */
SDL_SCANCODE_KP_2, /* AKEYCODE_NUMPAD_2 */
SDL_SCANCODE_KP_3, /* AKEYCODE_NUMPAD_3 */
SDL_SCANCODE_KP_4, /* AKEYCODE_NUMPAD_4 */
SDL_SCANCODE_KP_5, /* AKEYCODE_NUMPAD_5 */
SDL_SCANCODE_KP_6, /* AKEYCODE_NUMPAD_6 */
SDL_SCANCODE_KP_7, /* AKEYCODE_NUMPAD_7 */
SDL_SCANCODE_KP_8, /* AKEYCODE_NUMPAD_8 */
SDL_SCANCODE_KP_9, /* AKEYCODE_NUMPAD_9 */
SDL_SCANCODE_KP_DIVIDE, /* AKEYCODE_NUMPAD_DIVIDE */
SDL_SCANCODE_KP_MULTIPLY, /* AKEYCODE_NUMPAD_MULTIPLY */
SDL_SCANCODE_KP_MINUS, /* AKEYCODE_NUMPAD_SUBTRACT */
SDL_SCANCODE_KP_PLUS, /* AKEYCODE_NUMPAD_ADD */
SDL_SCANCODE_KP_PERIOD, /* AKEYCODE_NUMPAD_DOT */
SDL_SCANCODE_KP_COMMA, /* AKEYCODE_NUMPAD_COMMA */
SDL_SCANCODE_KP_ENTER, /* AKEYCODE_NUMPAD_ENTER */
SDL_SCANCODE_KP_EQUALS, /* AKEYCODE_NUMPAD_EQUALS */
SDL_SCANCODE_KP_LEFTPAREN, /* AKEYCODE_NUMPAD_LEFT_PAREN */
SDL_SCANCODE_KP_RIGHTPAREN, /* AKEYCODE_NUMPAD_RIGHT_PAREN */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_VOLUME_MUTE */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_INFO */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_CHANNEL_UP */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_CHANNEL_DOWN */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_ZOOM_IN */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_ZOOM_OUT */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_WINDOW */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_GUIDE */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_DVR */
SDL_SCANCODE_AC_BOOKMARKS, /* AKEYCODE_BOOKMARK */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_CAPTIONS */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_SETTINGS */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_POWER */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_STB_POWER */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_STB_INPUT */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_AVR_POWER */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_AVR_INPUT */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_PROG_RED */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_PROG_GREEN */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_PROG_YELLOW */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_PROG_BLUE */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_APP_SWITCH */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_1 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_2 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_3 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_4 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_5 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_6 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_7 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_8 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_9 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_10 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_11 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_12 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_13 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_14 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_15 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_BUTTON_16 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_LANGUAGE_SWITCH */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MANNER_MODE */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_3D_MODE */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_CONTACTS */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_CALENDAR */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MUSIC */
SDL_SCANCODE_CALCULATOR, /* AKEYCODE_CALCULATOR */
SDL_SCANCODE_LANG5, /* AKEYCODE_ZENKAKU_HANKAKU */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_EISU */
SDL_SCANCODE_INTERNATIONAL5, /* AKEYCODE_MUHENKAN */
SDL_SCANCODE_INTERNATIONAL4, /* AKEYCODE_HENKAN */
SDL_SCANCODE_LANG3, /* AKEYCODE_KATAKANA_HIRAGANA */
SDL_SCANCODE_INTERNATIONAL3, /* AKEYCODE_YEN */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_RO */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_KANA */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_ASSIST */
SDL_SCANCODE_BRIGHTNESSDOWN, /* AKEYCODE_BRIGHTNESS_DOWN */
SDL_SCANCODE_BRIGHTNESSUP, /* AKEYCODE_BRIGHTNESS_UP */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MEDIA_AUDIO_TRACK */
SDL_SCANCODE_SLEEP, /* AKEYCODE_SLEEP */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_WAKEUP */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_PAIRING */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MEDIA_TOP_MENU */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_11 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_12 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_LAST_CHANNEL */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_DATA_SERVICE */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_VOICE_ASSIST */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_RADIO_SERVICE */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_TELETEXT */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_NUMBER_ENTRY */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_TERRESTRIAL_ANALOG */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_TERRESTRIAL_DIGITAL */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_SATELLITE */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_SATELLITE_BS */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_SATELLITE_CS */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_SATELLITE_SERVICE */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_NETWORK */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_ANTENNA_CABLE */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_HDMI_1 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_HDMI_2 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_HDMI_3 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_HDMI_4 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_COMPOSITE_1 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_COMPOSITE_2 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_COMPONENT_1 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_COMPONENT_2 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_VGA_1 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_AUDIO_DESCRIPTION */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_ZOOM_MODE */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_CONTENTS_MENU */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_MEDIA_CONTEXT_MENU */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_TIMER_PROGRAMMING */
SDL_SCANCODE_HELP, /* AKEYCODE_HELP */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_NAVIGATE_PREVIOUS */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_NAVIGATE_NEXT */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_NAVIGATE_IN */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_NAVIGATE_OUT */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_STEM_PRIMARY */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_STEM_1 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_STEM_2 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_STEM_3 */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_DPAD_UP_LEFT */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_DPAD_DOWN_LEFT */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_DPAD_UP_RIGHT */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_DPAD_DOWN_RIGHT */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MEDIA_SKIP_FORWARD */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MEDIA_SKIP_BACKWARD */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MEDIA_STEP_FORWARD */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MEDIA_STEP_BACKWARD */
SDL_SCANCODE_UNKNOWN, /* AKEYCODE_SOFT_SLEEP */
SDL_SCANCODE_CUT, /* AKEYCODE_CUT */
SDL_SCANCODE_COPY, /* AKEYCODE_COPY */
SDL_SCANCODE_PASTE, /* AKEYCODE_PASTE */
};
static SDL_Scancode TranslateKeycode(int keycode)
{
SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
if (keycode < SDL_arraysize(Android_Keycodes)) {
scancode = Android_Keycodes[keycode];
}
if (scancode == SDL_SCANCODE_UNKNOWN) {
__android_log_print(ANDROID_LOG_INFO, "SDL", "Unknown keycode %d", keycode);
}
return scancode;
}
int Android_OnKeyDown(int keycode)
{
return SDL_SendKeyboardKey(0, SDL_PRESSED, TranslateKeycode(keycode));
}
int Android_OnKeyUp(int keycode)
{
return SDL_SendKeyboardKey(0, SDL_RELEASED, TranslateKeycode(keycode));
}
SDL_bool Android_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
{
return SDL_TRUE;
}
SDL_bool Android_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window)
{
return Android_JNI_IsScreenKeyboardShown();
}
void Android_StartTextInput(SDL_VideoDevice *_this)
{
SDL_VideoData *videodata = _this->driverdata;
Android_JNI_ShowTextInput(&videodata->textRect);
}
void Android_StopTextInput(SDL_VideoDevice *_this)
{
Android_JNI_HideTextInput();
}
int Android_SetTextInputRect(SDL_VideoDevice *_this, const SDL_Rect *rect)
{
SDL_VideoData *videodata = _this->driverdata;
videodata->textRect = *rect;
return 0;
}
#endif /* SDL_VIDEO_DRIVER_ANDROID */

View File

@ -0,0 +1,33 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_androidvideo.h"
extern int Android_OnKeyDown(int keycode);
extern int Android_OnKeyUp(int keycode);
extern SDL_bool Android_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
extern SDL_bool Android_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);
extern void Android_StartTextInput(SDL_VideoDevice *_this);
extern void Android_StopTextInput(SDL_VideoDevice *_this);
extern int Android_SetTextInputRect(SDL_VideoDevice *_this, const SDL_Rect *rect);

View File

@ -0,0 +1,33 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
#include "SDL_androidmessagebox.h"
#include "../../core/android/SDL_android.h"
int Android_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
{
return Android_JNI_ShowMessageBox(messageboxdata, buttonid);
}
#endif /* SDL_VIDEO_DRIVER_ANDROID */

View File

@ -0,0 +1,27 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
extern int Android_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid);
#endif /* SDL_VIDEO_DRIVER_ANDROID */

View File

@ -0,0 +1,253 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
#include "SDL_androidmouse.h"
#include "../../events/SDL_mouse_c.h"
#include "../../core/android/SDL_android.h"
/* See Android's MotionEvent class for constants */
#define ACTION_DOWN 0
#define ACTION_UP 1
#define ACTION_MOVE 2
#define ACTION_HOVER_MOVE 7
#define ACTION_SCROLL 8
#define BUTTON_PRIMARY 1
#define BUTTON_SECONDARY 2
#define BUTTON_TERTIARY 4
#define BUTTON_BACK 8
#define BUTTON_FORWARD 16
typedef struct
{
int custom_cursor;
int system_cursor;
} SDL_AndroidCursorData;
/* Last known Android mouse button state (includes all buttons) */
static int last_state;
/* Blank cursor */
static SDL_Cursor *empty_cursor;
static SDL_Cursor *Android_WrapCursor(int custom_cursor, int system_cursor)
{
SDL_Cursor *cursor;
cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
SDL_AndroidCursorData *data = (SDL_AndroidCursorData *)SDL_calloc(1, sizeof(*data));
if (data) {
data->custom_cursor = custom_cursor;
data->system_cursor = system_cursor;
cursor->driverdata = data;
} else {
SDL_free(cursor);
cursor = NULL;
SDL_OutOfMemory();
}
} else {
SDL_OutOfMemory();
}
return cursor;
}
static SDL_Cursor *Android_CreateDefaultCursor()
{
return Android_WrapCursor(0, SDL_SYSTEM_CURSOR_ARROW);
}
static SDL_Cursor *Android_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
{
int custom_cursor;
SDL_Surface *converted;
converted = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888);
if (converted == NULL) {
return NULL;
}
custom_cursor = Android_JNI_CreateCustomCursor(converted, hot_x, hot_y);
SDL_DestroySurface(converted);
if (!custom_cursor) {
SDL_Unsupported();
return NULL;
}
return Android_WrapCursor(custom_cursor, 0);
}
static SDL_Cursor *Android_CreateSystemCursor(SDL_SystemCursor id)
{
return Android_WrapCursor(0, id);
}
static void Android_FreeCursor(SDL_Cursor *cursor)
{
SDL_AndroidCursorData *data = (SDL_AndroidCursorData *)cursor->driverdata;
if (data->custom_cursor != 0) {
Android_JNI_DestroyCustomCursor(data->custom_cursor);
}
SDL_free(cursor->driverdata);
SDL_free(cursor);
}
static SDL_Cursor *Android_CreateEmptyCursor()
{
if (empty_cursor == NULL) {
SDL_Surface *empty_surface = SDL_CreateSurface(1, 1, SDL_PIXELFORMAT_ARGB8888);
if (empty_surface) {
SDL_memset(empty_surface->pixels, 0, (size_t)empty_surface->h * empty_surface->pitch);
empty_cursor = Android_CreateCursor(empty_surface, 0, 0);
SDL_DestroySurface(empty_surface);
}
}
return empty_cursor;
}
static void Android_DestroyEmptyCursor()
{
if (empty_cursor) {
Android_FreeCursor(empty_cursor);
empty_cursor = NULL;
}
}
static int Android_ShowCursor(SDL_Cursor *cursor)
{
if (cursor == NULL) {
cursor = Android_CreateEmptyCursor();
}
if (cursor) {
SDL_AndroidCursorData *data = (SDL_AndroidCursorData *)cursor->driverdata;
if (data->custom_cursor) {
if (!Android_JNI_SetCustomCursor(data->custom_cursor)) {
return SDL_Unsupported();
}
} else {
if (!Android_JNI_SetSystemCursor(data->system_cursor)) {
return SDL_Unsupported();
}
}
return 0;
} else {
/* SDL error set inside Android_CreateEmptyCursor() */
return -1;
}
}
static int Android_SetRelativeMouseMode(SDL_bool enabled)
{
if (!Android_JNI_SupportsRelativeMouse()) {
return SDL_Unsupported();
}
if (!Android_JNI_SetRelativeMouseEnabled(enabled)) {
return SDL_Unsupported();
}
return 0;
}
void Android_InitMouse(void)
{
SDL_Mouse *mouse = SDL_GetMouse();
mouse->CreateCursor = Android_CreateCursor;
mouse->CreateSystemCursor = Android_CreateSystemCursor;
mouse->ShowCursor = Android_ShowCursor;
mouse->FreeCursor = Android_FreeCursor;
mouse->SetRelativeMouseMode = Android_SetRelativeMouseMode;
SDL_SetDefaultCursor(Android_CreateDefaultCursor());
last_state = 0;
}
void Android_QuitMouse(void)
{
Android_DestroyEmptyCursor();
}
/* Translate Android mouse button state to SDL mouse button */
static Uint8 TranslateButton(int state)
{
if (state & BUTTON_PRIMARY) {
return SDL_BUTTON_LEFT;
} else if (state & BUTTON_SECONDARY) {
return SDL_BUTTON_RIGHT;
} else if (state & BUTTON_TERTIARY) {
return SDL_BUTTON_MIDDLE;
} else if (state & BUTTON_FORWARD) {
return SDL_BUTTON_X1;
} else if (state & BUTTON_BACK) {
return SDL_BUTTON_X2;
} else {
return 0;
}
}
void Android_OnMouse(SDL_Window *window, int state, int action, float x, float y, SDL_bool relative)
{
int changes;
Uint8 button;
if (window == NULL) {
return;
}
switch (action) {
case ACTION_DOWN:
changes = state & ~last_state;
button = TranslateButton(changes);
last_state = state;
SDL_SendMouseMotion(0, window, 0, relative, x, y);
SDL_SendMouseButton(0, window, 0, SDL_PRESSED, button);
break;
case ACTION_UP:
changes = last_state & ~state;
button = TranslateButton(changes);
last_state = state;
SDL_SendMouseMotion(0, window, 0, relative, x, y);
SDL_SendMouseButton(0, window, 0, SDL_RELEASED, button);
break;
case ACTION_MOVE:
case ACTION_HOVER_MOVE:
SDL_SendMouseMotion(0, window, 0, relative, x, y);
break;
case ACTION_SCROLL:
SDL_SendMouseWheel(0, window, 0, x, y, SDL_MOUSEWHEEL_NORMAL);
break;
default:
break;
}
}
#endif /* SDL_VIDEO_DRIVER_ANDROID */

View File

@ -0,0 +1,31 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_androidmouse_h_
#define SDL_androidmouse_h_
#include "SDL_androidvideo.h"
extern void Android_InitMouse(void);
extern void Android_OnMouse(SDL_Window *window, int button, int action, float x, float y, SDL_bool relative);
extern void Android_QuitMouse(void);
#endif /* SDL_androidmouse_h_ */

View File

@ -0,0 +1,85 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
#include <android/log.h>
#include "SDL_androidtouch.h"
#include "../../events/SDL_mouse_c.h"
#include "../../events/SDL_touch_c.h"
#include "../../core/android/SDL_android.h"
#define ACTION_DOWN 0
#define ACTION_UP 1
#define ACTION_MOVE 2
/* #define ACTION_CANCEL 3 */
/* #define ACTION_OUTSIDE 4 */
#define ACTION_POINTER_DOWN 5
#define ACTION_POINTER_UP 6
void Android_InitTouch(void)
{
/* Add all touch devices */
Android_JNI_InitTouch();
}
void Android_QuitTouch(void)
{
}
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;
SDL_FingerID fingerId = 0;
if (window == NULL) {
return;
}
touchDeviceId = (SDL_TouchID)touch_device_id_in;
if (SDL_AddTouch(touchDeviceId, SDL_TOUCH_DEVICE_DIRECT, "") < 0) {
SDL_Log("error: can't add touch %s, %d", __FILE__, __LINE__);
}
fingerId = (SDL_FingerID)pointer_finger_id_in;
switch (action) {
case ACTION_DOWN:
case ACTION_POINTER_DOWN:
SDL_SendTouch(0, touchDeviceId, fingerId, window, SDL_TRUE, x, y, p);
break;
case ACTION_MOVE:
SDL_SendTouchMotion(0, touchDeviceId, fingerId, window, x, y, p);
break;
case ACTION_UP:
case ACTION_POINTER_UP:
SDL_SendTouch(0, touchDeviceId, fingerId, window, SDL_FALSE, x, y, p);
break;
default:
break;
}
}
#endif /* SDL_VIDEO_DRIVER_ANDROID */

View File

@ -0,0 +1,27 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_androidvideo.h"
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);

View File

@ -0,0 +1,302 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
/* Android SDL video driver implementation */
#include "../SDL_sysvideo.h"
#include "../SDL_pixels_c.h"
#include "../../events/SDL_events_c.h"
#include "../../events/SDL_windowevents_c.h"
#include "SDL_androidvideo.h"
#include "SDL_androidgl.h"
#include "SDL_androidclipboard.h"
#include "SDL_androidevents.h"
#include "SDL_androidkeyboard.h"
#include "SDL_androidmouse.h"
#include "SDL_androidtouch.h"
#include "SDL_androidwindow.h"
#include "SDL_androidvulkan.h"
#define ANDROID_VID_DRIVER_NAME "Android"
/* Initialization/Query functions */
static int Android_VideoInit(SDL_VideoDevice *_this);
static void Android_VideoQuit(SDL_VideoDevice *_this);
#include "../SDL_egl_c.h"
#define Android_GLES_GetProcAddress SDL_EGL_GetProcAddressInternal
#define Android_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
#define Android_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
#define Android_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
#define Android_GLES_DeleteContext SDL_EGL_DeleteContext
/* Android driver bootstrap functions */
/* These are filled in with real values in Android_SetScreenResolution on init (before SDL_main()) */
int Android_SurfaceWidth = 0;
int Android_SurfaceHeight = 0;
static int Android_DeviceWidth = 0;
static int Android_DeviceHeight = 0;
static Uint32 Android_ScreenFormat = SDL_PIXELFORMAT_RGB565; /* Default SurfaceView format, in case this is queried before being filled */
float Android_ScreenDensity = 1.0f;
static float Android_ScreenRate = 0.0f;
SDL_Semaphore *Android_PauseSem = NULL;
SDL_Semaphore *Android_ResumeSem = NULL;
SDL_Mutex *Android_ActivityMutex = NULL;
static SDL_SystemTheme Android_SystemTheme;
static int Android_SuspendScreenSaver(SDL_VideoDevice *_this)
{
return Android_JNI_SuspendScreenSaver(_this->suspend_screensaver);
}
static void Android_DeleteDevice(SDL_VideoDevice *device)
{
SDL_free(device->driverdata);
SDL_free(device);
}
static SDL_VideoDevice *Android_CreateDevice(void)
{
SDL_VideoDevice *device;
SDL_VideoData *data;
SDL_bool block_on_pause;
/* Initialize all variables that we clean on shutdown */
device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
if (device == NULL) {
SDL_OutOfMemory();
return NULL;
}
data = (SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData));
if (data == NULL) {
SDL_OutOfMemory();
SDL_free(device);
return NULL;
}
device->driverdata = data;
device->system_theme = Android_SystemTheme;
/* Set the function pointers */
device->VideoInit = Android_VideoInit;
device->VideoQuit = Android_VideoQuit;
block_on_pause = SDL_GetHintBoolean(SDL_HINT_ANDROID_BLOCK_ON_PAUSE, SDL_TRUE);
if (block_on_pause) {
device->PumpEvents = Android_PumpEvents_Blocking;
} else {
device->PumpEvents = Android_PumpEvents_NonBlocking;
}
device->CreateSDLWindow = Android_CreateWindow;
device->SetWindowTitle = Android_SetWindowTitle;
device->SetWindowFullscreen = Android_SetWindowFullscreen;
device->MinimizeWindow = Android_MinimizeWindow;
device->SetWindowResizable = Android_SetWindowResizable;
device->DestroyWindow = Android_DestroyWindow;
device->GetWindowWMInfo = Android_GetWindowWMInfo;
device->free = Android_DeleteDevice;
/* GL pointers */
#ifdef SDL_VIDEO_OPENGL_EGL
device->GL_LoadLibrary = Android_GLES_LoadLibrary;
device->GL_GetProcAddress = Android_GLES_GetProcAddress;
device->GL_UnloadLibrary = Android_GLES_UnloadLibrary;
device->GL_CreateContext = Android_GLES_CreateContext;
device->GL_MakeCurrent = Android_GLES_MakeCurrent;
device->GL_SetSwapInterval = Android_GLES_SetSwapInterval;
device->GL_GetSwapInterval = Android_GLES_GetSwapInterval;
device->GL_SwapWindow = Android_GLES_SwapWindow;
device->GL_DeleteContext = Android_GLES_DeleteContext;
#endif
#ifdef SDL_VIDEO_VULKAN
device->Vulkan_LoadLibrary = Android_Vulkan_LoadLibrary;
device->Vulkan_UnloadLibrary = Android_Vulkan_UnloadLibrary;
device->Vulkan_GetInstanceExtensions = Android_Vulkan_GetInstanceExtensions;
device->Vulkan_CreateSurface = Android_Vulkan_CreateSurface;
#endif
/* Screensaver */
device->SuspendScreenSaver = Android_SuspendScreenSaver;
/* Text input */
device->StartTextInput = Android_StartTextInput;
device->StopTextInput = Android_StopTextInput;
device->SetTextInputRect = Android_SetTextInputRect;
/* Screen keyboard */
device->HasScreenKeyboardSupport = Android_HasScreenKeyboardSupport;
device->IsScreenKeyboardShown = Android_IsScreenKeyboardShown;
/* Clipboard */
device->SetClipboardText = Android_SetClipboardText;
device->GetClipboardText = Android_GetClipboardText;
device->HasClipboardText = Android_HasClipboardText;
return device;
}
VideoBootStrap Android_bootstrap = {
ANDROID_VID_DRIVER_NAME, "SDL Android video driver",
Android_CreateDevice
};
int Android_VideoInit(SDL_VideoDevice *_this)
{
SDL_VideoData *videodata = _this->driverdata;
SDL_DisplayID displayID;
SDL_VideoDisplay *display;
SDL_DisplayMode mode;
videodata->isPaused = SDL_FALSE;
videodata->isPausing = SDL_FALSE;
videodata->pauseAudio = SDL_GetHintBoolean(SDL_HINT_ANDROID_BLOCK_ON_PAUSE_PAUSEAUDIO, SDL_TRUE);
SDL_zero(mode);
mode.format = Android_ScreenFormat;
mode.w = Android_DeviceWidth;
mode.h = Android_DeviceHeight;
mode.refresh_rate = Android_ScreenRate;
mode.driverdata = NULL;
displayID = SDL_AddBasicVideoDisplay(&mode);
if (displayID == 0) {
return -1;
}
display = SDL_GetVideoDisplay(displayID);
display->natural_orientation = Android_JNI_GetDisplayNaturalOrientation();
display->current_orientation = Android_JNI_GetDisplayCurrentOrientation();
display->content_scale = Android_ScreenDensity;
Android_InitTouch();
Android_InitMouse();
/* We're done! */
return 0;
}
void Android_VideoQuit(SDL_VideoDevice *_this)
{
Android_QuitMouse();
Android_QuitTouch();
}
void Android_SetScreenResolution(int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, float density, float rate)
{
Android_SurfaceWidth = surfaceWidth;
Android_SurfaceHeight = surfaceHeight;
Android_DeviceWidth = deviceWidth;
Android_DeviceHeight = deviceHeight;
Android_ScreenDensity = (density > 0.0f) ? density : 1.0f;
Android_ScreenRate = rate;
}
static Uint32 format_to_pixelFormat(int format)
{
Uint32 pf;
if (format == AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM) { /* 1 */
pf = SDL_PIXELFORMAT_RGBA8888;
} else if (format == AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM) { /* 2 */
pf = SDL_PIXELFORMAT_RGBX8888;
} else if (format == AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM) { /* 3 */
pf = SDL_PIXELFORMAT_RGB24;
} else if (format == AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM) { /* 4*/
pf = SDL_PIXELFORMAT_RGB565;
} else if (format == 5) {
pf = SDL_PIXELFORMAT_BGRA8888;
} else if (format == 6) {
pf = SDL_PIXELFORMAT_RGBA5551;
} else if (format == 7) {
pf = SDL_PIXELFORMAT_RGBA4444;
} else if (format == 0x115) {
/* HAL_PIXEL_FORMAT_BGR_565 */
pf = SDL_PIXELFORMAT_RGB565;
} else {
pf = SDL_PIXELFORMAT_UNKNOWN;
}
return pf;
}
void Android_SetFormat(int format_wanted, int format_got)
{
Uint32 pf_wanted;
Uint32 pf_got;
pf_wanted = format_to_pixelFormat(format_wanted);
pf_got = format_to_pixelFormat(format_got);
Android_ScreenFormat = pf_got;
SDL_Log("pixel format wanted %s (%d), got %s (%d)",
SDL_GetPixelFormatName(pf_wanted), format_wanted,
SDL_GetPixelFormatName(pf_got), format_got);
}
void Android_SendResize(SDL_Window *window)
{
/*
Update the resolution of the desktop mode, so that the window
can be properly resized. The screen resolution change can for
example happen when the Activity enters or exits immersive mode,
which can happen after VideoInit().
*/
SDL_VideoDevice *device = SDL_GetVideoDevice();
if (device && device->num_displays > 0) {
SDL_VideoDisplay *display = &device->displays[0];
SDL_DisplayMode desktop_mode;
SDL_zero(desktop_mode);
desktop_mode.format = Android_ScreenFormat;
desktop_mode.w = Android_DeviceWidth;
desktop_mode.h = Android_DeviceHeight;
desktop_mode.refresh_rate = Android_ScreenRate;
SDL_SetDesktopDisplayMode(display, &desktop_mode);
}
if (window) {
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, Android_SurfaceWidth, Android_SurfaceHeight);
}
}
void Android_SetDarkMode(SDL_bool enabled)
{
SDL_VideoDevice *device = SDL_GetVideoDevice();
if (enabled) {
Android_SystemTheme = SDL_SYSTEM_THEME_DARK;
} else {
Android_SystemTheme = SDL_SYSTEM_THEME_LIGHT;
}
if (device) {
SDL_SetSystemTheme(Android_SystemTheme);
}
}
#endif /* SDL_VIDEO_DRIVER_ANDROID */

View File

@ -0,0 +1,50 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_androidvideo_h_
#define SDL_androidvideo_h_
#include "../SDL_sysvideo.h"
/* Called by the JNI layer when the screen changes size or format */
extern void Android_SetScreenResolution(int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, float density, float rate);
extern void Android_SetFormat(int format_wanted, int format_got);
extern void Android_SendResize(SDL_Window *window);
extern void Android_SetDarkMode(SDL_bool enabled);
/* Private display data */
struct SDL_VideoData
{
SDL_Rect textRect;
int isPaused;
int isPausing;
int pauseAudio;
};
extern int Android_SurfaceWidth;
extern int Android_SurfaceHeight;
extern float Android_ScreenDensity;
extern SDL_Semaphore *Android_PauseSem, *Android_ResumeSem;
extern SDL_Mutex *Android_ActivityMutex;
#endif /* SDL_androidvideo_h_ */

View File

@ -0,0 +1,168 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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.
*/
/*
* @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's
* SDL_x11vulkan.c.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_ANDROID)
#include "SDL_androidvideo.h"
#include "SDL_androidwindow.h"
#include "SDL_androidvulkan.h"
#include <SDL3/SDL_syswm.h>
int Android_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
VkExtensionProperties *extensions = NULL;
Uint32 i, extensionCount = 0;
SDL_bool hasSurfaceExtension = SDL_FALSE;
SDL_bool hasAndroidSurfaceExtension = SDL_FALSE;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
if (_this->vulkan_config.loader_handle) {
return SDL_SetError("Vulkan already loaded");
}
/* Load the Vulkan loader library */
if (path == NULL) {
path = SDL_getenv("SDL_VULKAN_LIBRARY");
}
if (path == NULL) {
path = "libvulkan.so";
}
_this->vulkan_config.loader_handle = SDL_LoadObject(path);
if (!_this->vulkan_config.loader_handle) {
return -1;
}
SDL_strlcpy(_this->vulkan_config.loader_path, path,
SDL_arraysize(_this->vulkan_config.loader_path));
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction(
_this->vulkan_config.loader_handle, "vkGetInstanceProcAddr");
if (!vkGetInstanceProcAddr) {
goto fail;
}
_this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr;
_this->vulkan_config.vkEnumerateInstanceExtensionProperties =
(void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)(
VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties");
if (!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) {
goto fail;
}
extensions = SDL_Vulkan_CreateInstanceExtensionsList(
(PFN_vkEnumerateInstanceExtensionProperties)
_this->vulkan_config.vkEnumerateInstanceExtensionProperties,
&extensionCount);
if (extensions == NULL) {
goto fail;
}
for (i = 0; i < extensionCount; i++) {
if (SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
hasSurfaceExtension = SDL_TRUE;
} else if (SDL_strcmp(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
hasAndroidSurfaceExtension = SDL_TRUE;
}
}
SDL_free(extensions);
if (!hasSurfaceExtension) {
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");
goto fail;
}
return 0;
fail:
SDL_UnloadObject(_this->vulkan_config.loader_handle);
_this->vulkan_config.loader_handle = NULL;
return -1;
}
void Android_Vulkan_UnloadLibrary(SDL_VideoDevice *_this)
{
if (_this->vulkan_config.loader_handle) {
SDL_UnloadObject(_this->vulkan_config.loader_handle);
_this->vulkan_config.loader_handle = NULL;
}
}
SDL_bool Android_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
unsigned *count,
const char **names)
{
static const char *const extensionsForAndroid[] = {
VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
};
if (!_this->vulkan_config.loader_handle) {
SDL_SetError("Vulkan is not loaded");
return SDL_FALSE;
}
return SDL_Vulkan_GetInstanceExtensions_Helper(
count, names, SDL_arraysize(extensionsForAndroid),
extensionsForAndroid);
}
SDL_bool Android_Vulkan_CreateSurface(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
VkSurfaceKHR *surface)
{
SDL_WindowData *windowData = window->driverdata;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
(PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR =
(PFN_vkCreateAndroidSurfaceKHR)vkGetInstanceProcAddr(
instance,
"vkCreateAndroidSurfaceKHR");
VkAndroidSurfaceCreateInfoKHR createInfo;
VkResult result;
if (!_this->vulkan_config.loader_handle) {
SDL_SetError("Vulkan is not loaded");
return SDL_FALSE;
}
if (!vkCreateAndroidSurfaceKHR) {
SDL_SetError(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
" extension is not enabled in the Vulkan instance.");
return SDL_FALSE;
}
SDL_zero(createInfo);
createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = NULL;
createInfo.flags = 0;
createInfo.window = windowData->native_window;
result = vkCreateAndroidSurfaceKHR(instance, &createInfo,
NULL, surface);
if (result != VK_SUCCESS) {
SDL_SetError("vkCreateAndroidSurfaceKHR failed: %s",
SDL_Vulkan_GetResultString(result));
return SDL_FALSE;
}
return SDL_TRUE;
}
#endif

View File

@ -0,0 +1,49 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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.
*/
/*
* @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's
* SDL_x11vulkan.h.
*/
#include "SDL_internal.h"
#ifndef SDL_androidvulkan_h_
#define SDL_androidvulkan_h_
#include "../SDL_vulkan_internal.h"
#include "../SDL_sysvideo.h"
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_ANDROID)
int Android_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
void Android_Vulkan_UnloadLibrary(SDL_VideoDevice *_this);
SDL_bool Android_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
unsigned *count,
const char **names);
SDL_bool Android_Vulkan_CreateSurface(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
VkSurfaceKHR *surface);
#endif
#endif /* SDL_androidvulkan_h_ */

View File

@ -0,0 +1,211 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
#include "../SDL_sysvideo.h"
#include "../../events/SDL_keyboard_c.h"
#include "../../events/SDL_mouse_c.h"
#include "../../events/SDL_windowevents_c.h"
#include "../../core/android/SDL_android.h"
#include "SDL_androidvideo.h"
#include "SDL_androidwindow.h"
#include <SDL3/SDL_syswm.h>
/* Currently only one window */
SDL_Window *Android_Window = NULL;
int Android_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *data;
int retval = 0;
Android_ActivityMutex_Lock_Running();
if (Android_Window) {
retval = SDL_SetError("Android only supports one window");
goto endfunction;
}
/* Set orientation */
Android_JNI_SetOrientation(window->w, window->h, window->flags & SDL_WINDOW_RESIZABLE, SDL_GetHint(SDL_HINT_ORIENTATIONS));
/* Adjust the window data to match the screen */
window->x = 0;
window->y = 0;
window->w = Android_SurfaceWidth;
window->h = Android_SurfaceHeight;
/* One window, it always has focus */
SDL_SetMouseFocus(window);
SDL_SetKeyboardFocus(window);
data = (SDL_WindowData *)SDL_calloc(1, sizeof(*data));
if (data == NULL) {
retval = SDL_OutOfMemory();
goto endfunction;
}
data->native_window = Android_JNI_GetNativeWindow();
if (!data->native_window) {
SDL_free(data);
retval = SDL_SetError("Could not fetch native window");
goto endfunction;
}
/* Do not create EGLSurface for Vulkan window since it will then make the window
incompatible with vkCreateAndroidSurfaceKHR */
#ifdef SDL_VIDEO_OPENGL_EGL
if (window->flags & SDL_WINDOW_OPENGL) {
data->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)data->native_window);
if (data->egl_surface == EGL_NO_SURFACE) {
ANativeWindow_release(data->native_window);
SDL_free(data);
retval = -1;
goto endfunction;
}
}
#endif
window->driverdata = data;
Android_Window = window;
endfunction:
SDL_UnlockMutex(Android_ActivityMutex);
return retval;
}
void Android_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window)
{
Android_JNI_SetActivityTitle(window->title);
}
void Android_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen)
{
SDL_LockMutex(Android_ActivityMutex);
if (window == Android_Window) {
SDL_WindowData *data;
int old_w, old_h, new_w, new_h;
/* If the window is being destroyed don't change visible state */
if (!window->is_destroying) {
Android_JNI_SetWindowStyle(fullscreen);
}
/* 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
* still not be the full display size.
*/
if (!SDL_IsDeXMode() && !SDL_IsChromebook()) {
goto endfunction;
}
data = window->driverdata;
if (data == NULL || !data->native_window) {
if (data && !data->native_window) {
SDL_SetError("Missing native window");
}
goto endfunction;
}
old_w = window->w;
old_h = window->h;
new_w = ANativeWindow_getWidth(data->native_window);
new_h = ANativeWindow_getHeight(data->native_window);
if (new_w < 0 || new_h < 0) {
SDL_SetError("ANativeWindow_getWidth/Height() fails");
}
if (old_w != new_w || old_h != new_h) {
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, new_w, new_h);
}
}
endfunction:
SDL_UnlockMutex(Android_ActivityMutex);
}
void Android_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
Android_JNI_MinizeWindow();
}
void Android_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool resizable)
{
/* Set orientation */
Android_JNI_SetOrientation(window->w, window->h, window->flags & SDL_WINDOW_RESIZABLE, SDL_GetHint(SDL_HINT_ORIENTATIONS));
}
void Android_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_LockMutex(Android_ActivityMutex);
if (window == Android_Window) {
Android_Window = NULL;
if (window->driverdata) {
SDL_WindowData *data = window->driverdata;
#ifdef SDL_VIDEO_OPENGL_EGL
if (data->egl_surface != EGL_NO_SURFACE) {
SDL_EGL_DestroySurface(_this, data->egl_surface);
}
#endif
if (data->native_window) {
ANativeWindow_release(data->native_window);
}
SDL_free(window->driverdata);
window->driverdata = NULL;
}
}
SDL_UnlockMutex(Android_ActivityMutex);
}
int Android_GetWindowWMInfo(SDL_VideoDevice *_this, SDL_Window *window, SDL_SysWMinfo *info)
{
SDL_WindowData *data = window->driverdata;
info->subsystem = SDL_SYSWM_ANDROID;
info->info.android.window = data->native_window;
#ifdef SDL_VIDEO_OPENGL_EGL
info->info.android.surface = data->egl_surface;
#endif
return 0;
}
#endif /* SDL_VIDEO_DRIVER_ANDROID */

View File

@ -0,0 +1,52 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_androidwindow_h_
#define SDL_androidwindow_h_
#include "../../core/android/SDL_android.h"
#include "../SDL_egl_c.h"
extern int Android_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void Android_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
extern void Android_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen);
extern void Android_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void Android_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool resizable);
extern void Android_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int Android_GetWindowWMInfo(SDL_VideoDevice *_this, SDL_Window *window, struct SDL_SysWMinfo *info);
extern SDL_Window *Android_Window;
struct SDL_WindowData
{
#ifdef SDL_VIDEO_OPENGL_EGL
EGLSurface egl_surface;
EGLContext egl_context; /* We use this to preserve the context when losing focus */
int has_swap_interval; /* Save/Restore the swap interval / vsync */
int swap_interval;
#endif
SDL_bool backup_done;
ANativeWindow *native_window;
};
#endif /* SDL_androidwindow_h_ */

View File

@ -0,0 +1,36 @@
/*
* Copyright © 2010 Nokia Corporation
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Mozilla Corporation not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Mozilla Corporation makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*
* Author: Siarhei Siamashka (siarhei.siamashka@nokia.com)
*
*/
/* Supplementary macro for setting function attributes */
.macro pixman_asm_function fname
.func fname
.global fname
#ifdef __ELF__
.hidden fname
.type fname, %function
#endif
fname:
.endm

View File

@ -0,0 +1,375 @@
/*
* Copyright © 2009 Nokia Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Author: Siarhei Siamashka (siarhei.siamashka@nokia.com)
*/
/*
* Copyright (c) 2018 RISC OS Open Ltd
*
* 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.
*/
/* Prevent the stack from becoming executable for no reason... */
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif
.text
.fpu neon
.arch armv7a
.object_arch armv4
.eabi_attribute 10, 0 /* suppress Tag_FP_arch */
.eabi_attribute 12, 0 /* suppress Tag_Advanced_SIMD_arch */
.arm
.altmacro
.p2align 2
#include "pixman-arm-asm.h"
#include "pixman-arm-neon-asm.h"
/* Global configuration options and preferences */
/*
* The code can optionally make use of unaligned memory accesses to improve
* performance of handling leading/trailing pixels for each scanline.
* Configuration variable RESPECT_STRICT_ALIGNMENT can be set to 0 for
* example in linux if unaligned memory accesses are not configured to
* generate.exceptions.
*/
.set RESPECT_STRICT_ALIGNMENT, 1
/*
* Set default prefetch type. There is a choice between the following options:
*
* PREFETCH_TYPE_NONE (may be useful for the ARM cores where PLD is set to work
* as NOP to workaround some HW bugs or for whatever other reason)
*
* PREFETCH_TYPE_SIMPLE (may be useful for simple single-issue ARM cores where
* advanced prefetch introduces heavy overhead)
*
* PREFETCH_TYPE_ADVANCED (useful for superscalar cores such as ARM Cortex-A8
* which can run ARM and NEON instructions simultaneously so that extra ARM
* instructions do not add (many) extra cycles, but improve prefetch efficiency)
*
* Note: some types of function can't support advanced prefetch and fallback
* to simple one (those which handle 24bpp pixels)
*/
.set PREFETCH_TYPE_DEFAULT, PREFETCH_TYPE_ADVANCED
/* Prefetch distance in pixels for simple prefetch */
.set PREFETCH_DISTANCE_SIMPLE, 64
/******************************************************************************/
/* We can actually do significantly better than the Pixman macros, at least for
* the case of fills, by using a carefully scheduled inner loop. Cortex-A53
* shows an improvement of up to 78% in ideal cases (large fills to L1 cache).
*/
.macro generate_fillrect_function name, bpp, log2Bpp
/*
* void name(int32_t w, int32_t h, uint8_t *dst, int32_t dst_stride, uint8_t src);
* On entry:
* a1 = width, pixels
* a2 = height, rows
* a3 = pointer to top-left destination pixel
* a4 = stride, pixels
* [sp] = pixel value to fill with
* Within the function:
* v1 = width remaining
* v2 = vst offset
* v3 = alternate pointer
* ip = data ARM register
*/
pixman_asm_function name
vld1.\bpp {d0[],d1[]}, [sp]
sub a4, a1
vld1.\bpp {d2[],d3[]}, [sp]
cmp a1, #(15+64) >> \log2Bpp
push {v1-v3,lr}
vmov ip, s0
blo 51f
/* Long-row case */
mov v2, #64
1: mov v1, a1
ands v3, a3, #15
beq 2f
/* Leading pixels */
rsb v3, v3, #16 /* number of leading bytes until 16-byte aligned */
sub v1, v1, v3, lsr #\log2Bpp
rbit v3, v3
.if bpp <= 16
.if bpp == 8
tst a3, #1 /* bit 0 unaffected by rsb so can avoid register interlock */
strneb ip, [a3], #1
tst v3, #1<<30
.else
tst a3, #2 /* bit 1 unaffected by rsb (assuming halfword alignment) so can avoid register interlock */
.endif
strneh ip, [a3], #2
.endif
movs v3, v3, lsl #3
vstmcs a3!, {s0}
vstmmi a3!, {d0}
2: sub v1, v1, #64 >> \log2Bpp /* simplifies inner loop termination */
add v3, a3, #32
/* Inner loop */
3: vst1.\bpp {q0-q1}, [a3 :128], v2
subs v1, v1, #64 >> \log2Bpp
vst1.\bpp {q0-q1}, [v3 :128], v2
bhs 3b
/* Trailing pixels */
4: movs v1, v1, lsl #27 + \log2Bpp
bcc 5f
vst1.\bpp {q0-q1}, [a3 :128]!
5: bpl 6f
vst1.\bpp {q0}, [a3 :128]!
6: movs v1, v1, lsl #2
vstmcs a3!, {d0}
vstmmi a3!, {s0}
.if bpp <= 16
movs v1, v1, lsl #2
strcsh ip, [a3], #2
.if bpp == 8
strmib ip, [a3], #1
.endif
.endif
subs a2, a2, #1
add a3, a3, a4, lsl #\log2Bpp
bhi 1b
pop {v1-v3,pc}
/* Short-row case */
51: movs v1, a1
.if bpp == 8
tst a3, #3
beq 53f
52: subs v1, v1, #1
blo 57f
strb ip, [a3], #1
tst a3, #3
bne 52b
.elseif bpp == 16
tstne a3, #2
subne v1, v1, #1
strneh ip, [a3], #2
.endif
53: cmp v1, #32 >> \log2Bpp
bcc 54f
vst1.\bpp {q0-q1}, [a3]!
sub v1, v1, #32 >> \log2Bpp
/* Trailing pixels */
54: movs v1, v1, lsl #27 + \log2Bpp
bcc 55f
vst1.\bpp {q0-q1}, [a3]!
55: bpl 56f
vst1.\bpp {q0}, [a3]!
56: movs v1, v1, lsl #2
vstmcs a3!, {d0}
vstmmi a3!, {s0}
.if bpp <= 16
movs v1, v1, lsl #2
strcsh ip, [a3], #2
.if bpp == 8
strmib ip, [a3], #1
.endif
.endif
subs a2, a2, #1
add a3, a3, a4, lsl #\log2Bpp
bhi 51b
57: pop {v1-v3,pc}
.endfunc
.endm
generate_fillrect_function FillSurfaceRect32ARMNEONAsm, 32, 2
generate_fillrect_function FillSurfaceRect16ARMNEONAsm, 16, 1
generate_fillrect_function FillSurfaceRect8ARMNEONAsm, 8, 0
/******************************************************************************/
.macro RGBtoRGBPixelAlpha_process_pixblock_head
vmvn d30, d3 /* get inverted source alpha */
vmov d31, d7 /* dest alpha is always unchanged */
vmull.u8 q14, d0, d3
vmlal.u8 q14, d4, d30
vmull.u8 q0, d1, d3
vmlal.u8 q0, d5, d30
vmull.u8 q1, d2, d3
vmlal.u8 q1, d6, d30
vrshr.u16 q2, q14, #8
vrshr.u16 q3, q0, #8
vraddhn.u16 d28, q14, q2
vrshr.u16 q2, q1, #8
vraddhn.u16 d29, q0, q3
vraddhn.u16 d30, q1, q2
.endm
.macro RGBtoRGBPixelAlpha_process_pixblock_tail
/* nothing */
.endm
.macro RGBtoRGBPixelAlpha_process_pixblock_tail_head
vld4.8 {d0-d3}, [SRC]!
PF add PF_X, PF_X, #8
vst4.8 {d28-d31}, [DST_W :128]!
PF tst PF_CTL, #0xF
vld4.8 {d4-d7}, [DST_R :128]!
PF addne PF_X, PF_X, #8
vmvn d30, d3 /* get inverted source alpha */
vmov d31, d7 /* dest alpha is always unchanged */
vmull.u8 q14, d0, d3
PF subne PF_CTL, PF_CTL, #1
vmlal.u8 q14, d4, d30
PF cmp PF_X, ORIG_W
vmull.u8 q0, d1, d3
PF pld, [PF_SRC, PF_X, lsl #src_bpp_shift]
vmlal.u8 q0, d5, d30
PF pld, [PF_DST, PF_X, lsl #dst_bpp_shift]
vmull.u8 q1, d2, d3
PF subge PF_X, PF_X, ORIG_W
vmlal.u8 q1, d6, d30
PF subges PF_CTL, PF_CTL, #0x10
vrshr.u16 q2, q14, #8
PF ldrgeb DUMMY, [PF_SRC, SRC_STRIDE, lsl #src_bpp_shift]!
vrshr.u16 q3, q0, #8
PF ldrgeb DUMMY, [PF_DST, DST_STRIDE, lsl #dst_bpp_shift]!
vraddhn.u16 d28, q14, q2
vrshr.u16 q2, q1, #8
vraddhn.u16 d29, q0, q3
vraddhn.u16 d30, q1, q2
.endm
generate_composite_function \
BlitRGBtoRGBPixelAlphaARMNEONAsm, 32, 0, 32, \
FLAG_DST_READWRITE | FLAG_DEINTERLEAVE_32BPP, \
8, /* number of pixels, processed in a single block */ \
5, /* prefetch distance */ \
default_init, \
default_cleanup, \
RGBtoRGBPixelAlpha_process_pixblock_head, \
RGBtoRGBPixelAlpha_process_pixblock_tail, \
RGBtoRGBPixelAlpha_process_pixblock_tail_head
/******************************************************************************/
.macro ARGBto565PixelAlpha_process_pixblock_head
vmvn d6, d3
vshr.u8 d1, #2
vshr.u8 d3, #3
vshr.u8 d0, #3
vshrn.u16 d7, q2, #3
vshrn.u16 d25, q2, #8
vbic.i16 q2, #0xe0
vshr.u8 d6, #3
vshr.u8 d7, #2
vshr.u8 d2, #3
vmovn.u16 d24, q2
vshr.u8 d25, #3
vmull.u8 q13, d1, d3
vmlal.u8 q13, d7, d6
vmull.u8 q14, d0, d3
vmlal.u8 q14, d24, d6
vmull.u8 q15, d2, d3
vmlal.u8 q15, d25, d6
.endm
.macro ARGBto565PixelAlpha_process_pixblock_tail
vsra.u16 q13, #5
vsra.u16 q14, #5
vsra.u16 q15, #5
vrshr.u16 q13, #5
vrshr.u16 q14, #5
vrshr.u16 q15, #5
vsli.u16 q14, q13, #5
vsli.u16 q14, q15, #11
.endm
.macro ARGBto565PixelAlpha_process_pixblock_tail_head
vld4.8 {d0-d3}, [SRC]!
PF add PF_X, PF_X, #8
vsra.u16 q13, #5
PF tst PF_CTL, #0xF
vsra.u16 q14, #5
PF addne PF_X, PF_X, #8
vsra.u16 q15, #5
PF subne PF_CTL, PF_CTL, #1
vrshr.u16 q13, #5
PF cmp PF_X, ORIG_W
vrshr.u16 q14, #5
PF pld, [PF_SRC, PF_X, lsl #src_bpp_shift]
vrshr.u16 q15, #5
PF pld, [PF_DST, PF_X, lsl #dst_bpp_shift]
vld1.8 {d4-d5}, [DST_R]!
PF subge PF_X, PF_X, ORIG_W
vsli.u16 q14, q13, #5
PF subges PF_CTL, PF_CTL, #0x10
vsli.u16 q14, q15, #11
PF ldrgeb DUMMY, [PF_SRC, SRC_STRIDE, lsl #src_bpp_shift]!
vst1.8 {q14}, [DST_W :128]!
vmvn d6, d3
vshr.u8 d1, #2
vshr.u8 d3, #3
vshr.u8 d0, #3
vshrn.u16 d7, q2, #3
vshrn.u16 d25, q2, #8
vbic.i16 q2, #0xe0
PF ldrgeb DUMMY, [PF_DST, DST_STRIDE, lsl #dst_bpp_shift]!
vshr.u8 d6, #3
vshr.u8 d7, #2
vshr.u8 d2, #3
vmovn.u16 d24, q2
vshr.u8 d25, #3
vmull.u8 q13, d1, d3
vmlal.u8 q13, d7, d6
vmull.u8 q14, d0, d3
vmlal.u8 q14, d24, d6
vmull.u8 q15, d2, d3
vmlal.u8 q15, d25, d6
.endm
generate_composite_function \
BlitARGBto565PixelAlphaARMNEONAsm, 32, 0, 16, \
FLAG_DST_READWRITE | FLAG_DEINTERLEAVE_32BPP, \
8, /* number of pixels, processed in a single block */ \
6, /* prefetch distance */ \
default_init, \
default_cleanup, \
ARGBto565PixelAlpha_process_pixblock_head, \
ARGBto565PixelAlpha_process_pixblock_tail, \
ARGBto565PixelAlpha_process_pixblock_tail_head

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,532 @@
/*
* Copyright (c) 2016 RISC OS Open Ltd
*
* 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.
*/
/* Prevent the stack from becoming executable */
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif
.text
.arch armv6
.object_arch armv4
.arm
.altmacro
.p2align 2
#include "pixman-arm-asm.h"
#include "pixman-arm-simd-asm.h"
/* A head macro should do all processing which results in an output of up to
* 16 bytes, as far as the final load instruction. The corresponding tail macro
* should complete the processing of the up-to-16 bytes. The calling macro will
* sometimes choose to insert a preload or a decrement of X between them.
* cond ARM condition code for code block
* numbytes Number of output bytes that should be generated this time
* firstreg First WK register in which to place output
* unaligned_src Whether to use non-wordaligned loads of source image
* unaligned_mask Whether to use non-wordaligned loads of mask image
* preload If outputting 16 bytes causes 64 bytes to be read, whether an extra preload should be output
*/
/******************************************************************************/
.macro FillRect32_init
ldr SRC, [sp, #ARGS_STACK_OFFSET]
mov STRIDE_S, SRC
mov MASK, SRC
mov STRIDE_M, SRC
.endm
.macro FillRect16_init
ldrh SRC, [sp, #ARGS_STACK_OFFSET]
orr SRC, SRC, lsl #16
mov STRIDE_S, SRC
mov MASK, SRC
mov STRIDE_M, SRC
.endm
.macro FillRect8_init
ldrb SRC, [sp, #ARGS_STACK_OFFSET]
orr SRC, SRC, lsl #8
orr SRC, SRC, lsl #16
mov STRIDE_S, SRC
mov MASK, SRC
mov STRIDE_M, SRC
.endm
.macro FillRect_process_tail cond, numbytes, firstreg
WK4 .req SRC
WK5 .req STRIDE_S
WK6 .req MASK
WK7 .req STRIDE_M
pixst cond, numbytes, 4, DST
.unreq WK4
.unreq WK5
.unreq WK6
.unreq WK7
.endm
generate_composite_function \
FillSurfaceRect32ARMSIMDAsm, 0, 0, 32, \
FLAG_DST_WRITEONLY | FLAG_COND_EXEC | FLAG_PROCESS_PRESERVES_PSR | FLAG_PROCESS_DOES_STORE | FLAG_PROCESS_PRESERVES_SCRATCH \
0, /* prefetch distance doesn't apply */ \
FillRect32_init \
nop_macro, /* newline */ \
nop_macro /* cleanup */ \
nop_macro /* process head */ \
FillRect_process_tail
generate_composite_function \
FillSurfaceRect16ARMSIMDAsm, 0, 0, 16, \
FLAG_DST_WRITEONLY | FLAG_COND_EXEC | FLAG_PROCESS_PRESERVES_PSR | FLAG_PROCESS_DOES_STORE | FLAG_PROCESS_PRESERVES_SCRATCH \
0, /* prefetch distance doesn't apply */ \
FillRect16_init \
nop_macro, /* newline */ \
nop_macro /* cleanup */ \
nop_macro /* process head */ \
FillRect_process_tail
generate_composite_function \
FillSurfaceRect8ARMSIMDAsm, 0, 0, 8, \
FLAG_DST_WRITEONLY | FLAG_COND_EXEC | FLAG_PROCESS_PRESERVES_PSR | FLAG_PROCESS_DOES_STORE | FLAG_PROCESS_PRESERVES_SCRATCH \
0, /* prefetch distance doesn't apply */ \
FillRect8_init \
nop_macro, /* newline */ \
nop_macro /* cleanup */ \
nop_macro /* process head */ \
FillRect_process_tail
/******************************************************************************/
/* This differs from the over_8888_8888 routine in Pixman in that the destination
* alpha component is always left unchanged, and RGB components are not
* premultiplied by alpha. It differs from BlitRGBtoRGBPixelAlpha in that
* renormalisation is done by multiplying by 257/256 (with rounding) rather than
* simply shifting right by 8 bits - removing the need to special-case alpha=0xff.
*/
.macro RGBtoRGBPixelAlpha_init
line_saved_regs STRIDE_S, ORIG_W
mov MASK, #0x80
.endm
.macro RGBtoRGBPixelAlpha_1pixel_translucent s, d, tmp0, tmp1, tmp2, tmp3, half
uxtb tmp3, s
uxtb tmp0, d
sub tmp0, tmp3, tmp0
uxtb tmp3, s, ror #16
uxtb tmp1, d, ror #16
sub tmp1, tmp3, tmp1
uxtb tmp3, s, ror #8
mov s, s, lsr #24
uxtb tmp2, d, ror #8
sub tmp2, tmp3, tmp2
smlabb tmp0, tmp0, s, half
smlabb tmp1, tmp1, s, half
smlabb tmp2, tmp2, s, half
add tmp0, tmp0, asr #8
add tmp1, tmp1, asr #8
add tmp2, tmp2, asr #8
pkhbt tmp0, tmp0, tmp1, lsl #16
and tmp2, tmp2, #0xff00
uxtb16 tmp0, tmp0, ror #8
orr tmp0, tmp0, tmp2
uadd8 d, d, tmp0
.endm
.macro RGBtoRGBPixelAlpha_1pixel_opaque s, d
and d, d, #0xff000000
bic s, s, #0xff000000
orr d, d, s
.endm
.macro RGBtoRGBPixelAlpha_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload
.if numbytes == 16
ldm SRC!, {WK0, WK1}
ldm SRC!, {STRIDE_S, STRIDE_M}
ldrd WK2, WK3, [DST], #16
orr SCRATCH, WK0, WK1
and ORIG_W, WK0, WK1
orr SCRATCH, SCRATCH, STRIDE_S
and ORIG_W, ORIG_W, STRIDE_S
orr SCRATCH, SCRATCH, STRIDE_M
and ORIG_W, ORIG_W, STRIDE_M
tst SCRATCH, #0xff000000
.elseif numbytes == 8
ldm SRC!, {WK0, WK1}
ldm DST!, {WK2, WK3}
orr SCRATCH, WK0, WK1
and ORIG_W, WK0, WK1
tst SCRATCH, #0xff000000
.else // numbytes == 4
ldr WK0, [SRC], #4
ldr WK2, [DST], #4
tst WK0, #0xff000000
.endif
.endm
.macro RGBtoRGBPixelAlpha_process_tail cond, numbytes, firstreg
beq 20f @ all transparent
.if numbytes == 16
cmp ORIG_W, #0xff000000
bhs 10f @ all opaque
RGBtoRGBPixelAlpha_1pixel_translucent WK0, WK2, STRIDE_S, STRIDE_M, SCRATCH, ORIG_W, MASK
RGBtoRGBPixelAlpha_1pixel_translucent WK1, WK3, STRIDE_S, STRIDE_M, SCRATCH, ORIG_W, MASK
strd WK2, WK3, [DST, #-16]
ldrd WK0, WK1, [SRC, #-8]
ldrd WK2, WK3, [DST, #-8]
RGBtoRGBPixelAlpha_1pixel_translucent WK0, WK2, STRIDE_S, STRIDE_M, SCRATCH, ORIG_W, MASK
RGBtoRGBPixelAlpha_1pixel_translucent WK1, WK3, STRIDE_S, STRIDE_M, SCRATCH, ORIG_W, MASK
b 19f
10: RGBtoRGBPixelAlpha_1pixel_opaque WK0, WK2
RGBtoRGBPixelAlpha_1pixel_opaque WK1, WK3
strd WK2, WK3, [DST, #-16]
ldrd WK0, WK1, [SRC, #-8]
ldrd WK2, WK3, [DST, #-8]
RGBtoRGBPixelAlpha_1pixel_opaque WK0, WK2
RGBtoRGBPixelAlpha_1pixel_opaque WK1, WK3
19: strd WK2, WK3, [DST, #-8]
.elseif numbytes == 8
cmp ORIG_W, #0xff000000
bhs 10f @ all opaque
RGBtoRGBPixelAlpha_1pixel_translucent WK0, WK2, STRIDE_S, STRIDE_M, SCRATCH, ORIG_W, MASK
RGBtoRGBPixelAlpha_1pixel_translucent WK1, WK3, STRIDE_S, STRIDE_M, SCRATCH, ORIG_W, MASK
b 19f
10: RGBtoRGBPixelAlpha_1pixel_opaque WK0, WK2
RGBtoRGBPixelAlpha_1pixel_opaque WK1, WK3
19: strd WK2, WK3, [DST, #-8]
.else // numbytes == 4
cmp WK0, #0xff000000
bhs 10f @ opaque
RGBtoRGBPixelAlpha_1pixel_translucent WK0, WK2, STRIDE_S, STRIDE_M, SCRATCH, ORIG_W, MASK
b 19f
10: RGBtoRGBPixelAlpha_1pixel_opaque WK0, WK2
19: str WK2, [DST, #-4]
.endif
20:
.endm
generate_composite_function \
BlitRGBtoRGBPixelAlphaARMSIMDAsm, 32, 0, 32, \
FLAG_DST_READWRITE | FLAG_BRANCH_OVER | FLAG_PROCESS_CORRUPTS_PSR | FLAG_PROCESS_DOES_STORE | FLAG_SPILL_LINE_VARS | FLAG_PROCESS_CORRUPTS_WK0, \
2, /* prefetch distance */ \
RGBtoRGBPixelAlpha_init, \
nop_macro, /* newline */ \
nop_macro, /* cleanup */ \
RGBtoRGBPixelAlpha_process_head, \
RGBtoRGBPixelAlpha_process_tail
/******************************************************************************/
.macro ARGBto565PixelAlpha_init
line_saved_regs STRIDE_D, STRIDE_S, ORIG_W
mov MASK, #0x001f
mov STRIDE_M, #0x0010
orr MASK, MASK, MASK, lsl #16
orr STRIDE_M, STRIDE_M, STRIDE_M, lsl #16
.endm
.macro ARGBto565PixelAlpha_newline
mov STRIDE_S, #0x0200
.endm
/* On entry:
* s1 holds 1 32bpp source pixel
* d holds 1 16bpp destination pixel
* rbmask, rbhalf, ghalf hold 0x001f001f, 0x00100010, 0x00000200 respectively
* other registers are temporaries
* On exit:
* Constant registers preserved
*/
.macro ARGBto565PixelAlpha_1pixel_translucent s, d, rbmask, rbhalf, ghalf, alpha, rb, g, misc
mov alpha, s, lsr #27
and misc, s, #0xfc00
and g, d, #0x07e0
pkhbt rb, d, d, lsl #5
rsb misc, g, misc, lsr #5
and s, rbmask, s, lsr #3
and rb, rbmask, rb
sub s, s, rb
smlabb misc, misc, alpha, ghalf
mla s, s, alpha, rbhalf
add misc, misc, misc, lsl #5
add g, g, misc, asr #10
add s, s, s, lsl #5
and g, g, #0x07e0
add rb, rb, s, asr #10
and rb, rb, rbmask
pkhbt rb, rb, rb, lsl #11
orr d, rb, g
orr d, d, rb, lsr #16
.endm
/* On entry:
* s1 holds 1 32bpp source pixel
* d holds 1 16bpp destination pixel
* rbmask holds 0x001f001f
* On exit:
* Constant registers preserved
*/
.macro ARGBto565PixelAlpha_1pixel_opaque s, d, rbmask
and d, rbmask, s, lsr #3
and s, s, #0xfc00
orr d, d, d, lsr #5
orr d, d, s, lsr #5
.endm
/* On entry:
* s1, s2 hold 2 32bpp source pixels
* d holds 2 16bpp destination pixels
* rbmask, rbhalf, ghalf hold 0x001f001f, 0x00100010, 0x00000200 respectively
* other registers are temporaries
* On exit:
* Constant registers preserved
* Blended results have been written through destination pointer
*/
.macro ARGBto565PixelAlpha_2pixels_translucent s1, s2, d, rbmask, rbhalf, ghalf, alpha, rb, g, misc
mov alpha, s1, lsr #27
and misc, s1, #0xfc00
and g, d, #0x07e0
pkhbt rb, d, d, lsl #5
rsb misc, g, misc, lsr #5
and s1, rbmask, s1, lsr #3
and rb, rbmask, rb
sub s1, s1, rb
smlabb misc, misc, alpha, ghalf
mla s1, s1, alpha, rbhalf
uxth d, d, ror #16
add misc, misc, misc, lsl #5
mov alpha, s2, lsr #27
add g, g, misc, asr #10
add s1, s1, s1, lsl #5
and g, g, #0x07e0
add rb, rb, s1, asr #10
and rb, rb, rbmask
and misc, s2, #0xfc00
pkhbt rb, rb, rb, lsl #11
and s1, d, #0x07e0
pkhbt d, d, d, lsl #5
rsb misc, s1, misc, lsr #5
and s2, rbmask, s2, lsr #3
and d, rbmask, d
sub s2, s2, d
smlabb misc, misc, alpha, ghalf
mla s2, s2, alpha, rbhalf
orr alpha, rb, g
add misc, misc, misc, lsl #5
orr alpha, alpha, rb, lsr #16
add s1, s1, misc, asr #10
add s2, s2, s2, lsl #5
and s1, s1, #0x07e0
add d, d, s2, asr #10
and d, d, rbmask
strh alpha, [DST, #-4]
pkhbt d, d, d, lsl #11
orr alpha, d, s1
orr alpha, alpha, d, lsr #16
strh alpha, [DST, #-2]
.endm
/* On entry:
* s1, s2 hold 2 32bpp source pixels
* rbmask holds 0x001f001f
* other registers are temporaries
* On exit:
* Constant registers preserved
* Blended results have been written through destination pointer
*/
.macro ARGBto565PixelAlpha_2pixels_opaque s1, s2, d, rbmask, g
and g, s1, #0xfc00
and d, rbmask, s1, lsr #3
and s1, rbmask, s2, lsr #3
orr d, d, d, lsr #5
orr d, d, g, lsr #5
and g, s2, #0xfc00
strh d, [DST, #-4]
orr s1, s1, s1, lsr #5
orr s1, s1, g, lsr #5
strh s1, [DST, #-2]
.endm
.macro ARGBto565PixelAlpha_2pixels_head
ldrd WK0, WK1, [SRC], #8
ldr WK2, [DST], #4
orr SCRATCH, WK0, WK1
and ORIG_W, WK0, WK1
tst SCRATCH, #0xff000000
.endm
.macro ARGBto565PixelAlpha_2pixels_tail
beq 20f @ all transparent
cmp ORIG_W, #0xff000000
bhs 10f @ all opaque
ARGBto565PixelAlpha_2pixels_translucent WK0, WK1, WK2, MASK, STRIDE_M, STRIDE_S, STRIDE_D, WK3, SCRATCH, ORIG_W
b 20f
10: ARGBto565PixelAlpha_2pixels_opaque WK0, WK1, WK2, MASK, SCRATCH
20:
.endm
.macro ARGBto565PixelAlpha_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload
.if numbytes == 16
ARGBto565PixelAlpha_2pixels_head
ARGBto565PixelAlpha_2pixels_tail
ARGBto565PixelAlpha_2pixels_head
ARGBto565PixelAlpha_2pixels_tail
.endif
.if numbytes >= 8
ARGBto565PixelAlpha_2pixels_head
ARGBto565PixelAlpha_2pixels_tail
.endif
.if numbytes >= 4
ARGBto565PixelAlpha_2pixels_head
.else // numbytes == 2
ldr WK0, [SRC], #4
ldrh WK2, [DST], #2
tst WK0, #0xff000000
.endif
.endm
.macro ARGBto565PixelAlpha_process_tail cond, numbytes, firstreg
.if numbytes >= 4
ARGBto565PixelAlpha_2pixels_tail
.else // numbytes == 2
beq 20f @ all transparent
cmp WK0, #0xff000000
bhs 10f @ opaque
ARGBto565PixelAlpha_1pixel_translucent WK0, WK2, MASK, STRIDE_M, STRIDE_S, STRIDE_D, WK3, SCRATCH, ORIG_W
b 19f
10: ARGBto565PixelAlpha_1pixel_opaque WK0, WK2, MASK
19: strh WK2, [DST, #-2]
20:
.endif
.endm
generate_composite_function \
BlitARGBto565PixelAlphaARMSIMDAsm, 32, 0, 16, \
FLAG_DST_READWRITE | FLAG_BRANCH_OVER | FLAG_PROCESS_CORRUPTS_PSR | FLAG_PROCESS_DOES_STORE | FLAG_SPILL_LINE_VARS | FLAG_PROCESS_CORRUPTS_WK0, \
2, /* prefetch distance */ \
ARGBto565PixelAlpha_init, \
ARGBto565PixelAlpha_newline, \
nop_macro, /* cleanup */ \
ARGBto565PixelAlpha_process_head, \
ARGBto565PixelAlpha_process_tail
/******************************************************************************/
.macro BGR888toRGB888_1pixel cond, reg, tmp
uxtb16&cond tmp, WK&reg, ror #8
uxtb16&cond WK&reg, WK&reg, ror #16
orr&cond WK&reg, WK&reg, tmp, lsl #8
.endm
.macro BGR888toRGB888_2pixels cond, reg1, reg2, tmp1, tmp2
uxtb16&cond tmp1, WK&reg1, ror #8
uxtb16&cond WK&reg1, WK&reg1, ror #16
uxtb16&cond tmp2, WK&reg2, ror #8
uxtb16&cond WK&reg2, WK&reg2, ror #16
orr&cond WK&reg1, WK&reg1, tmp1, lsl #8
orr&cond WK&reg2, WK&reg2, tmp2, lsl #8
.endm
.macro BGR888toRGB888_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload
pixld cond, numbytes, firstreg, SRC, unaligned_src
.endm
.macro BGR888toRGB888_process_tail cond, numbytes, firstreg
.if numbytes >= 8
BGR888toRGB888_2pixels cond, %(firstreg+0), %(firstreg+1), MASK, STRIDE_M
.if numbytes == 16
BGR888toRGB888_2pixels cond, %(firstreg+2), %(firstreg+3), MASK, STRIDE_M
.endif
.else @ numbytes == 4
BGR888toRGB888_1pixel cond, %(firstreg+0), MASK
.endif
.endm
generate_composite_function \
Blit_XBGR8888_XRGB8888ARMSIMDAsm, 32, 0, 32, \
FLAG_DST_WRITEONLY | FLAG_COND_EXEC | FLAG_PROCESS_PRESERVES_SCRATCH, \
2, /* prefetch distance */ \
nop_macro, /* init */ \
nop_macro, /* newline */ \
nop_macro, /* cleanup */ \
BGR888toRGB888_process_head, \
BGR888toRGB888_process_tail
/******************************************************************************/
.macro RGB444toRGB888_init
ldr MASK, =0x0f0f0f0f
/* Set GE[3:0] to 0101 so SEL instructions do what we want */
msr CPSR_s, #0x50000
.endm
.macro RGB444toRGB888_1pixel reg, mask, tmp
pkhbt WK&reg, WK&reg, WK&reg, lsl #12 @ 0000aaaarrrrggggaaaarrrrggggbbbb
and WK&reg, mask, WK&reg @ 0000aaaa0000gggg0000rrrr0000bbbb
orr WK&reg, WK&reg, WK&reg, lsl #4 @ aaaaaaaaggggggggrrrrrrrrbbbbbbbb
pkhtb tmp, WK&reg, WK&reg, asr #8 @ aaaaaaaaggggggggggggggggrrrrrrrr
pkhbt WK&reg, WK&reg, WK&reg, lsl #8 @ ggggggggrrrrrrrrrrrrrrrrbbbbbbbb
sel WK&reg, WK&reg, tmp @ aaaaaaaarrrrrrrrggggggggbbbbbbbb
.endm
.macro RGB444toRGB888_2pixels in, out1, out2, mask, tmp1, tmp2
and tmp1, mask, WK&in @ 0000RRRR0000BBBB0000rrrr0000bbbb
and tmp2, mask, WK&in, lsr #4 @ 0000AAAA0000GGGG0000aaaa0000gggg
orr tmp1, tmp1, tmp1, lsl #4 @ RRRRRRRRBBBBBBBBrrrrrrrrbbbbbbbb
orr tmp2, tmp2, tmp2, lsl #4 @ AAAAAAAAGGGGGGGGaaaaaaaagggggggg
pkhtb WK&out2, tmp2, tmp1, asr #16 @ AAAAAAAAGGGGGGGGRRRRRRRRBBBBBBBB
pkhbt WK&out1, tmp1, tmp2, lsl #16 @ aaaaaaaaggggggggrrrrrrrrbbbbbbbb
pkhtb tmp2, WK&out2, WK&out2, asr #8 @ AAAAAAAAGGGGGGGGGGGGGGGGRRRRRRRR
pkhtb tmp1, WK&out1, WK&out1, asr #8 @ aaaaaaaaggggggggggggggggrrrrrrrr
pkhbt WK&out1, WK&out1, WK&out1, lsl #8 @ ggggggggrrrrrrrrrrrrrrrrbbbbbbbb
pkhbt WK&out2, WK&out2, WK&out2, lsl #8 @ GGGGGGGGRRRRRRRRRRRRRRRRBBBBBBBB
sel WK&out1, WK&out1, tmp1 @ aaaaaaaarrrrrrrrggggggggbbbbbbbb
sel WK&out2, WK&out2, tmp2 @ AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB
.endm
.macro RGB444toRGB888_process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, preload
pixld cond, numbytes/2, firstreg, SRC, unaligned_src
.endm
.macro RGB444toRGB888_process_tail cond, numbytes, firstreg
.if numbytes >= 8
.if numbytes == 16
RGB444toRGB888_2pixels %(firstreg+1), %(firstreg+2), %(firstreg+3), MASK, STRIDE_M, SCRATCH
.endif
RGB444toRGB888_2pixels %(firstreg+0), %(firstreg+0), %(firstreg+1), MASK, STRIDE_M, SCRATCH
.else @ numbytes == 4
RGB444toRGB888_1pixel %(firstreg+0), MASK, SCRATCH
.endif
.endm
generate_composite_function \
Blit_RGB444_XRGB8888ARMSIMDAsm, 16, 0, 32, \
FLAG_DST_WRITEONLY | FLAG_BRANCH_OVER, \
2, /* prefetch distance */ \
RGB444toRGB888_init, \
nop_macro, /* newline */ \
nop_macro, /* cleanup */ \
RGB444toRGB888_process_head, \
RGB444toRGB888_process_tail

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_cocoaclipboard_h_
#define SDL_cocoaclipboard_h_
/* Forward declaration */
@class SDL_CocoaVideoData;
extern int Cocoa_SetClipboardText(SDL_VideoDevice *_this, const char *text);
extern char *Cocoa_GetClipboardText(SDL_VideoDevice *_this);
extern SDL_bool Cocoa_HasClipboardText(SDL_VideoDevice *_this);
extern void Cocoa_CheckClipboardUpdate(SDL_CocoaVideoData *data);
extern int Cocoa_SetClipboardData(SDL_VideoDevice *_this);
extern void *Cocoa_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size);
extern SDL_bool Cocoa_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type);
#endif /* SDL_cocoaclipboard_h_ */

View File

@ -0,0 +1,178 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_COCOA
#include "SDL_cocoavideo.h"
#include "../../events/SDL_clipboardevents_c.h"
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101300
typedef NSString *NSPasteboardType; /* Defined in macOS 10.13+ */
#endif
@interface Cocoa_PasteboardDataProvider : NSObject<NSPasteboardItemDataProvider>
{
SDL_ClipboardDataCallback m_callback;
void *m_userdata;
}
@end
@implementation Cocoa_PasteboardDataProvider
- (nullable instancetype)initWith:(SDL_ClipboardDataCallback)callback
userData:(void *)userdata
{
self = [super init];
if (!self) {
return self;
}
m_callback = callback;
m_userdata = userdata;
return self;
}
- (void)pasteboard:(NSPasteboard *)pasteboard
item:(NSPasteboardItem *)item
provideDataForType:(NSPasteboardType)type
{
@autoreleasepool {
size_t size = 0;
CFStringRef mimeType;
const void *callbackData;
NSData *data;
mimeType = UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)type, kUTTagClassMIMEType);
callbackData = m_callback(m_userdata, [(__bridge NSString *)mimeType UTF8String], &size);
CFRelease(mimeType);
if (callbackData == NULL || size == 0) {
return;
}
data = [NSData dataWithBytes: callbackData length: size];
[item setData: data forType: type];
}
}
@end
void Cocoa_CheckClipboardUpdate(SDL_CocoaVideoData *data)
{
@autoreleasepool {
NSPasteboard *pasteboard;
NSInteger count;
pasteboard = [NSPasteboard generalPasteboard];
count = [pasteboard changeCount];
if (count != data.clipboard_count) {
if (data.clipboard_count) {
SDL_SendClipboardUpdate();
}
data.clipboard_count = count;
}
}
}
int Cocoa_SetClipboardData(SDL_VideoDevice *_this)
{
@autoreleasepool {
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
NSPasteboardItem *newItem = [NSPasteboardItem new];
NSMutableArray *utiTypes = [NSMutableArray new];
Cocoa_PasteboardDataProvider *provider = [[Cocoa_PasteboardDataProvider alloc] initWith: _this->clipboard_callback userData: _this->clipboard_userdata];
BOOL itemResult = FALSE;
BOOL writeResult = FALSE;
if (_this->clipboard_callback) {
for (int i = 0; i < _this->num_clipboard_mime_types; i++) {
CFStringRef mimeType = CFStringCreateWithCString(NULL, _this->clipboard_mime_types[i], kCFStringEncodingUTF8);
CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
CFRelease(mimeType);
[utiTypes addObject: (__bridge NSString *)utiType];
CFRelease(utiType);
}
itemResult = [newItem setDataProvider: provider forTypes: utiTypes];
if (itemResult == FALSE) {
return SDL_SetError("Unable to set clipboard item data");
}
[pasteboard clearContents];
writeResult = [pasteboard writeObjects: @[newItem]];
if (writeResult == FALSE) {
return SDL_SetError("Unable to set clipboard data");
}
} else {
[pasteboard clearContents];
}
data.clipboard_count = [pasteboard changeCount];
}
return 0;
}
void *Cocoa_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *size)
{
@autoreleasepool {
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
void *data = NULL;
*size = 0;
for (NSPasteboardItem *item in [pasteboard pasteboardItems]) {
NSData *itemData;
CFStringRef mimeType = CFStringCreateWithCString(NULL, mime_type, kCFStringEncodingUTF8);
CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
CFRelease(mimeType);
itemData = [item dataForType: (__bridge NSString *)utiType];
CFRelease(utiType);
if (itemData != nil) {
NSUInteger length = [itemData length];
*size = (size_t)length;
data = SDL_malloc(*size + sizeof(Uint32));
if (data) {
[itemData getBytes: data length: length];
SDL_memset((Uint8 *)data + length, 0, sizeof(Uint32));
} else {
SDL_OutOfMemory();
}
break;
}
}
return data;
}
}
SDL_bool Cocoa_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
{
SDL_bool result = SDL_FALSE;
@autoreleasepool {
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
CFStringRef mimeType = CFStringCreateWithCString(NULL, mime_type, kCFStringEncodingUTF8);
CFStringRef utiType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType, NULL);
CFRelease(mimeType);
if ([pasteboard canReadItemWithDataConformingToTypes: @[(__bridge NSString *)utiType]]) {
result = SDL_TRUE;
}
CFRelease(utiType);
}
return result;
}
#endif /* SDL_VIDEO_DRIVER_COCOA */

View File

@ -0,0 +1,33 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_cocoaevents_h_
#define SDL_cocoaevents_h_
extern void Cocoa_RegisterApp(void);
extern Uint64 Cocoa_GetEventTimestamp(NSTimeInterval nsTimestamp);
extern void Cocoa_PumpEvents(SDL_VideoDevice *_this);
extern int Cocoa_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS);
extern void Cocoa_SendWakeupEvent(SDL_VideoDevice *_this, SDL_Window *window);
extern int Cocoa_SuspendScreenSaver(SDL_VideoDevice *_this);
#endif /* SDL_cocoaevents_h_ */

View File

@ -0,0 +1,616 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_COCOA
#include "SDL_cocoavideo.h"
#include "../../events/SDL_events_c.h"
#ifndef MAC_OS_X_VERSION_10_12
#define NSEventTypeApplicationDefined NSApplicationDefined
#endif
static SDL_Window *FindSDLWindowForNSWindow(NSWindow *win)
{
SDL_Window *sdlwindow = NULL;
SDL_VideoDevice *device = SDL_GetVideoDevice();
if (device && device->windows) {
for (sdlwindow = device->windows; sdlwindow; sdlwindow = sdlwindow->next) {
NSWindow *nswindow = ((__bridge SDL_CocoaWindowData *)sdlwindow->driverdata).nswindow;
if (win == nswindow) {
return sdlwindow;
}
}
}
return sdlwindow;
}
@interface SDLApplication : NSApplication
- (void)terminate:(id)sender;
- (void)sendEvent:(NSEvent *)theEvent;
+ (void)registerUserDefaults;
@end
@implementation SDLApplication
// Override terminate to handle Quit and System Shutdown smoothly.
- (void)terminate:(id)sender
{
SDL_SendQuit();
}
static SDL_bool s_bShouldHandleEventsInSDLApplication = SDL_FALSE;
static void Cocoa_DispatchEvent(NSEvent *theEvent)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
switch ([theEvent type]) {
case NSEventTypeLeftMouseDown:
case NSEventTypeOtherMouseDown:
case NSEventTypeRightMouseDown:
case NSEventTypeLeftMouseUp:
case NSEventTypeOtherMouseUp:
case NSEventTypeRightMouseUp:
case NSEventTypeLeftMouseDragged:
case NSEventTypeRightMouseDragged:
case NSEventTypeOtherMouseDragged: /* usually middle mouse dragged */
case NSEventTypeMouseMoved:
case NSEventTypeScrollWheel:
Cocoa_HandleMouseEvent(_this, theEvent);
break;
case NSEventTypeKeyDown:
case NSEventTypeKeyUp:
case NSEventTypeFlagsChanged:
Cocoa_HandleKeyEvent(_this, theEvent);
break;
default:
break;
}
}
// Dispatch events here so that we can handle events caught by
// nextEventMatchingMask in SDL, as well as events caught by other
// processes (such as CEF) that are passed down to NSApp.
- (void)sendEvent:(NSEvent *)theEvent
{
if (s_bShouldHandleEventsInSDLApplication) {
Cocoa_DispatchEvent(theEvent);
}
[super sendEvent:theEvent];
}
+ (void)registerUserDefaults
{
NSDictionary *appDefaults = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithBool:NO], @"AppleMomentumScrollSupported",
[NSNumber numberWithBool:NO], @"ApplePressAndHoldEnabled",
[NSNumber numberWithBool:YES], @"ApplePersistenceIgnoreState",
nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
}
@end // SDLApplication
/* setAppleMenu disappeared from the headers in 10.4 */
@interface NSApplication (NSAppleMenu)
- (void)setAppleMenu:(NSMenu *)menu;
@end
@interface SDLAppDelegate : NSObject <NSApplicationDelegate>
{
@public
BOOL seenFirstActivate;
}
- (id)init;
- (void)localeDidChange:(NSNotification *)notification;
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context;
@end
@implementation SDLAppDelegate : NSObject
- (id)init
{
self = [super init];
if (self) {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
seenFirstActivate = NO;
[center addObserver:self
selector:@selector(windowWillClose:)
name:NSWindowWillCloseNotification
object:nil];
[center addObserver:self
selector:@selector(focusSomeWindow:)
name:NSApplicationDidBecomeActiveNotification
object:nil];
[center addObserver:self
selector:@selector(localeDidChange:)
name:NSCurrentLocaleDidChangeNotification
object:nil];
[NSApp addObserver:self
forKeyPath:@"effectiveAppearance"
options:NSKeyValueObservingOptionInitial
context:nil];
}
return self;
}
- (void)dealloc
{
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center removeObserver:self name:NSWindowWillCloseNotification object:nil];
[center removeObserver:self name:NSApplicationDidBecomeActiveNotification object:nil];
[center removeObserver:self name:NSCurrentLocaleDidChangeNotification object:nil];
[NSApp removeObserver:self forKeyPath:@"effectiveAppearance"];
/* Remove our URL event handler only if we set it */
if ([NSApp delegate] == self) {
[[NSAppleEventManager sharedAppleEventManager]
removeEventHandlerForEventClass:kInternetEventClass
andEventID:kAEGetURL];
}
}
- (void)windowWillClose:(NSNotification *)notification;
{
NSWindow *win = (NSWindow *)[notification object];
if (![win isKeyWindow]) {
return;
}
/* Don't do anything if this was not an SDL window that was closed */
if (FindSDLWindowForNSWindow(win) == NULL) {
return;
}
/* HACK: Make the next window in the z-order key when the key window is
* closed. The custom event loop and/or windowing code we have seems to
* prevent the normal behavior: https://bugzilla.libsdl.org/show_bug.cgi?id=1825
*/
/* +[NSApp orderedWindows] never includes the 'About' window, but we still
* want to try its list first since the behavior in other apps is to only
* make the 'About' window key if no other windows are on-screen.
*/
for (NSWindow *window in [NSApp orderedWindows]) {
if (window != win && [window canBecomeKeyWindow]) {
if (![window isOnActiveSpace]) {
continue;
}
[window makeKeyAndOrderFront:self];
return;
}
}
/* If a window wasn't found above, iterate through all visible windows in
* the active Space in z-order (including the 'About' window, if it's shown)
* and make the first one key.
*/
for (NSNumber *num in [NSWindow windowNumbersWithOptions:0]) {
NSWindow *window = [NSApp windowWithWindowNumber:[num integerValue]];
if (window && window != win && [window canBecomeKeyWindow]) {
[window makeKeyAndOrderFront:self];
return;
}
}
}
- (void)focusSomeWindow:(NSNotification *)aNotification
{
SDL_VideoDevice *device;
/* HACK: Ignore the first call. The application gets a
* applicationDidBecomeActive: a little bit after the first window is
* created, and if we don't ignore it, a window that has been created with
* SDL_WINDOW_MINIMIZED will ~immediately be restored.
*/
if (!seenFirstActivate) {
seenFirstActivate = YES;
return;
}
/* Don't do anything if the application already has a key window
* that is not an SDL window.
*/
if ([NSApp keyWindow] && FindSDLWindowForNSWindow([NSApp keyWindow]) == NULL) {
return;
}
device = SDL_GetVideoDevice();
if (device && device->windows) {
SDL_Window *window = device->windows;
int i;
for (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) {
SDL_RestoreWindow(fullscreen_window);
}
return;
}
}
if (window->flags & SDL_WINDOW_MINIMIZED) {
SDL_RestoreWindow(window);
} else {
SDL_RaiseWindow(window);
}
}
}
- (void)localeDidChange:(NSNotification *)notification
{
SDL_SendLocaleChangedEvent();
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
SDL_SetSystemTheme(Cocoa_GetSystemTheme());
}
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
return (BOOL)SDL_SendDropFile(NULL, [filename UTF8String]) && SDL_SendDropComplete(NULL);
}
- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
/* The menu bar of SDL apps which don't have the typical .app bundle
* structure fails to work the first time a window is created (until it's
* de-focused and re-focused), if this call is in Cocoa_RegisterApp instead
* of here. https://bugzilla.libsdl.org/show_bug.cgi?id=3051
*/
if (!SDL_GetHintBoolean(SDL_HINT_MAC_BACKGROUND_APP, SDL_FALSE)) {
/* Get more aggressive for Catalina: activate the Dock first so we definitely reset all activation state. */
for (NSRunningApplication *i in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.dock"]) {
[i activateWithOptions:NSApplicationActivateIgnoringOtherApps];
break;
}
SDL_Delay(300); /* !!! FIXME: this isn't right. */
[NSApp activateIgnoringOtherApps:YES];
}
/* If we call this before NSApp activation, macOS might print a complaint
* about ApplePersistenceIgnoreState. */
[SDLApplication registerUserDefaults];
}
- (void)handleURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
NSString *path = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
SDL_SendDropFile(NULL, [path UTF8String]);
SDL_SendDropComplete(NULL);
}
@end
static SDLAppDelegate *appDelegate = nil;
static NSString *GetApplicationName(void)
{
NSString *appName;
/* Determine the application name */
appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
if (!appName) {
appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
}
if (![appName length]) {
appName = [[NSProcessInfo processInfo] processName];
}
return appName;
}
static bool LoadMainMenuNibIfAvailable(void)
{
NSDictionary *infoDict;
NSString *mainNibFileName;
bool success = false;
infoDict = [[NSBundle mainBundle] infoDictionary];
if (infoDict) {
mainNibFileName = [infoDict valueForKey:@"NSMainNibFile"];
if (mainNibFileName) {
success = [[NSBundle mainBundle] loadNibNamed:mainNibFileName owner:[NSApplication sharedApplication] topLevelObjects:nil];
}
}
return success;
}
static void CreateApplicationMenus(void)
{
NSString *appName;
NSString *title;
NSMenu *appleMenu;
NSMenu *serviceMenu;
NSMenu *windowMenu;
NSMenuItem *menuItem;
NSMenu *mainMenu;
if (NSApp == nil) {
return;
}
mainMenu = [[NSMenu alloc] init];
/* Create the main menu bar */
[NSApp setMainMenu:mainMenu];
/* Create the application menu */
appName = GetApplicationName();
appleMenu = [[NSMenu alloc] initWithTitle:@""];
/* Add menu items */
title = [@"About " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
[appleMenu addItem:[NSMenuItem separatorItem]];
[appleMenu addItemWithTitle:@"Preferences…" action:nil keyEquivalent:@","];
[appleMenu addItem:[NSMenuItem separatorItem]];
serviceMenu = [[NSMenu alloc] initWithTitle:@""];
menuItem = [appleMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""];
[menuItem setSubmenu:serviceMenu];
[NSApp setServicesMenu:serviceMenu];
[appleMenu addItem:[NSMenuItem separatorItem]];
title = [@"Hide " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
menuItem = [appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
[menuItem setKeyEquivalentModifierMask:(NSEventModifierFlagOption | NSEventModifierFlagCommand)];
[appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
[appleMenu addItem:[NSMenuItem separatorItem]];
title = [@"Quit " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
/* Put menu into the menubar */
menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
[menuItem setSubmenu:appleMenu];
[[NSApp mainMenu] addItem:menuItem];
/* Tell the application object that this is now the application menu */
[NSApp setAppleMenu:appleMenu];
/* Create the window menu */
windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
/* Add menu items */
[windowMenu addItemWithTitle:@"Close" action:@selector(performClose:) keyEquivalent:@"w"];
[windowMenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
[windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
/* Add the fullscreen toggle menu option. */
/* Cocoa should update the title to Enter or Exit Full Screen automatically.
* But if not, then just fallback to Toggle Full Screen.
*/
menuItem = [[NSMenuItem alloc] initWithTitle:@"Toggle Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"];
[menuItem setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
[windowMenu addItem:menuItem];
/* Put menu into the menubar */
menuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
[menuItem setSubmenu:windowMenu];
[[NSApp mainMenu] addItem:menuItem];
/* Tell the application object that this is now the window menu */
[NSApp setWindowsMenu:windowMenu];
}
void Cocoa_RegisterApp(void)
{
@autoreleasepool {
/* This can get called more than once! Be careful what you initialize! */
if (NSApp == nil) {
[SDLApplication sharedApplication];
SDL_assert(NSApp != nil);
s_bShouldHandleEventsInSDLApplication = SDL_TRUE;
if (!SDL_GetHintBoolean(SDL_HINT_MAC_BACKGROUND_APP, SDL_FALSE)) {
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
}
/* If there aren't already menus in place, look to see if there's
* a nib we should use. If not, then manually create the basic
* menus we meed.
*/
if ([NSApp mainMenu] == nil) {
bool nibLoaded;
nibLoaded = LoadMainMenuNibIfAvailable();
if (!nibLoaded) {
CreateApplicationMenus();
}
}
[NSApp finishLaunching];
if ([NSApp delegate]) {
/* The SDL app delegate calls this in didFinishLaunching if it's
* attached to the NSApp, otherwise we need to call it manually.
*/
[SDLApplication registerUserDefaults];
}
}
if (NSApp && !appDelegate) {
appDelegate = [[SDLAppDelegate alloc] init];
/* If someone else has an app delegate, it means we can't turn a
* termination into SDL_Quit, and we can't handle application:openFile:
*/
if (![NSApp delegate]) {
/* Only register the URL event handler if we are being set as the
* app delegate to avoid replacing any existing event handler.
*/
[[NSAppleEventManager sharedAppleEventManager]
setEventHandler:appDelegate
andSelector:@selector(handleURLEvent:withReplyEvent:)
forEventClass:kInternetEventClass
andEventID:kAEGetURL];
[(NSApplication *)NSApp setDelegate:appDelegate];
} else {
appDelegate->seenFirstActivate = YES;
}
}
}
}
Uint64 Cocoa_GetEventTimestamp(NSTimeInterval nsTimestamp)
{
static Uint64 timestamp_offset;
Uint64 timestamp = (Uint64)(nsTimestamp * SDL_NS_PER_SECOND);
Uint64 now = SDL_GetTicksNS();
if (!timestamp_offset) {
timestamp_offset = (now - timestamp);
}
timestamp += timestamp_offset;
if (timestamp > now) {
timestamp_offset -= (timestamp - now);
timestamp = now;
}
return timestamp;
}
int Cocoa_PumpEventsUntilDate(SDL_VideoDevice *_this, NSDate *expiration, bool accumulate)
{
for (;;) {
NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:expiration inMode:NSDefaultRunLoopMode dequeue:YES];
if (event == nil) {
return 0;
}
if (!s_bShouldHandleEventsInSDLApplication) {
Cocoa_DispatchEvent(event);
}
// Pass events down to SDLApplication to be handled in sendEvent:
[NSApp sendEvent:event];
if (!accumulate) {
break;
}
}
return 1;
}
int Cocoa_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS)
{
@autoreleasepool {
if (timeoutNS > 0) {
NSDate *limitDate = [NSDate dateWithTimeIntervalSinceNow:(double)timeoutNS / SDL_NS_PER_SECOND];
return Cocoa_PumpEventsUntilDate(_this, limitDate, false);
} else if (timeoutNS == 0) {
return Cocoa_PumpEventsUntilDate(_this, [NSDate distantPast], false);
} else {
while (Cocoa_PumpEventsUntilDate(_this, [NSDate distantFuture], false) == 0) {
}
}
return 1;
}
}
void Cocoa_PumpEvents(SDL_VideoDevice *_this)
{
@autoreleasepool {
Cocoa_PumpEventsUntilDate(_this, [NSDate distantPast], true);
}
}
void Cocoa_SendWakeupEvent(SDL_VideoDevice *_this, SDL_Window *window)
{
@autoreleasepool {
NSEvent *event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
location:NSMakePoint(0, 0)
modifierFlags:0
timestamp:0.0
windowNumber:((__bridge SDL_CocoaWindowData *)window->driverdata).window_number
context:nil
subtype:0
data1:0
data2:0];
[NSApp postEvent:event atStart:YES];
}
}
int Cocoa_SuspendScreenSaver(SDL_VideoDevice *_this)
{
@autoreleasepool {
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
if (data.screensaver_assertion) {
IOPMAssertionRelease(data.screensaver_assertion);
data.screensaver_assertion = kIOPMNullAssertionID;
}
if (_this->suspend_screensaver) {
/* FIXME: this should ideally describe the real reason why the game
* called SDL_DisableScreenSaver. Note that the name is only meant to be
* seen by macOS power users. there's an additional optional human-readable
* (localized) reason parameter which we don't set.
*/
IOPMAssertionID assertion = kIOPMNullAssertionID;
NSString *name = [GetApplicationName() stringByAppendingString:@" using SDL_DisableScreenSaver"];
IOPMAssertionCreateWithDescription(kIOPMAssertPreventUserIdleDisplaySleep,
(__bridge CFStringRef)name,
NULL, NULL, NULL, 0, NULL,
&assertion);
data.screensaver_assertion = assertion;
}
}
return 0;
}
#endif /* SDL_VIDEO_DRIVER_COCOA */

View File

@ -0,0 +1,36 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_cocoakeyboard_h_
#define SDL_cocoakeyboard_h_
extern void Cocoa_InitKeyboard(SDL_VideoDevice *_this);
extern void Cocoa_HandleKeyEvent(SDL_VideoDevice *_this, NSEvent *event);
extern void Cocoa_QuitKeyboard(SDL_VideoDevice *_this);
extern void Cocoa_StartTextInput(SDL_VideoDevice *_this);
extern void Cocoa_StopTextInput(SDL_VideoDevice *_this);
extern int Cocoa_SetTextInputRect(SDL_VideoDevice *_this, const SDL_Rect *rect);
extern void Cocoa_SetWindowKeyboardGrab(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed);
#endif /* SDL_cocoakeyboard_h_ */

View File

@ -0,0 +1,467 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_COCOA
#include "SDL_cocoavideo.h"
#include "../../events/SDL_events_c.h"
#include "../../events/SDL_keyboard_c.h"
#include "../../events/scancodes_darwin.h"
#include <Carbon/Carbon.h>
/*#define DEBUG_IME NSLog */
#define DEBUG_IME(...)
@interface SDLTranslatorResponder : NSView <NSTextInputClient>
{
NSString *_markedText;
NSRange _markedRange;
NSRange _selectedRange;
SDL_Rect _inputRect;
}
- (void)doCommandBySelector:(SEL)myselector;
- (void)setInputRect:(const SDL_Rect *)rect;
@end
@implementation SDLTranslatorResponder
- (void)setInputRect:(const SDL_Rect *)rect
{
_inputRect = *rect;
}
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
{
/* TODO: Make use of replacementRange? */
const char *str;
DEBUG_IME(@"insertText: %@", aString);
/* Could be NSString or NSAttributedString, so we have
* to test and convert it before return as SDL event */
if ([aString isKindOfClass:[NSAttributedString class]]) {
str = [[aString string] UTF8String];
} else {
str = [aString UTF8String];
}
/* We're likely sending the composed text, so we reset the IME status. */
if ([self hasMarkedText]) {
[self unmarkText];
}
SDL_SendKeyboardText(str);
}
- (void)doCommandBySelector:(SEL)myselector
{
/* No need to do anything since we are not using Cocoa
selectors to handle special keys, instead we use SDL
key events to do the same job.
*/
}
- (BOOL)hasMarkedText
{
return _markedText != nil;
}
- (NSRange)markedRange
{
return _markedRange;
}
- (NSRange)selectedRange
{
return _selectedRange;
}
- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
{
if ([aString isKindOfClass:[NSAttributedString class]]) {
aString = [aString string];
}
if ([aString length] == 0) {
[self unmarkText];
return;
}
if (_markedText != aString) {
_markedText = aString;
}
_selectedRange = selectedRange;
_markedRange = NSMakeRange(0, [aString length]);
SDL_SendEditingText([aString UTF8String],
(int)selectedRange.location, (int)selectedRange.length);
DEBUG_IME(@"setMarkedText: %@, (%d, %d)", _markedText,
selectedRange.location, selectedRange.length);
}
- (void)unmarkText
{
_markedText = nil;
SDL_SendEditingText("", 0, 0);
}
- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
{
NSWindow *window = [self window];
NSRect contentRect = [window contentRectForFrameRect:[window frame]];
float windowHeight = contentRect.size.height;
NSRect rect = NSMakeRect(_inputRect.x, windowHeight - _inputRect.y - _inputRect.h,
_inputRect.w, _inputRect.h);
if (actualRange) {
*actualRange = aRange;
}
DEBUG_IME(@"firstRectForCharacterRange: (%d, %d): windowHeight = %g, rect = %@",
aRange.location, aRange.length, windowHeight,
NSStringFromRect(rect));
rect = [window convertRectToScreen:rect];
return rect;
}
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
{
DEBUG_IME(@"attributedSubstringFromRange: (%d, %d)", aRange.location, aRange.length);
return nil;
}
- (NSInteger)conversationIdentifier
{
return (NSInteger)self;
}
/* This method returns the index for character that is
* nearest to thePoint. thPoint is in screen coordinate system.
*/
- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
{
DEBUG_IME(@"characterIndexForPoint: (%g, %g)", thePoint.x, thePoint.y);
return 0;
}
/* This method is the key to attribute extension.
* We could add new attributes through this method.
* NSInputServer examines the return value of this
* method & constructs appropriate attributed string.
*/
- (NSArray *)validAttributesForMarkedText
{
return [NSArray array];
}
@end
static bool IsModifierKeyPressed(unsigned int flags,
unsigned int target_mask,
unsigned int other_mask,
unsigned int either_mask)
{
bool target_pressed = (flags & target_mask) != 0;
bool other_pressed = (flags & other_mask) != 0;
bool either_pressed = (flags & either_mask) != 0;
if (either_pressed != (target_pressed || other_pressed))
return either_pressed;
return target_pressed;
}
static void HandleModifiers(SDL_VideoDevice *_this, SDL_Scancode code, unsigned int modifierFlags)
{
bool pressed = false;
if (code == SDL_SCANCODE_LSHIFT) {
pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICELSHIFTKEYMASK,
NX_DEVICERSHIFTKEYMASK, NX_SHIFTMASK);
} else if (code == SDL_SCANCODE_LCTRL) {
pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICELCTLKEYMASK,
NX_DEVICERCTLKEYMASK, NX_CONTROLMASK);
} else if (code == SDL_SCANCODE_LALT) {
pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICELALTKEYMASK,
NX_DEVICERALTKEYMASK, NX_ALTERNATEMASK);
} else if (code == SDL_SCANCODE_LGUI) {
pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICELCMDKEYMASK,
NX_DEVICERCMDKEYMASK, NX_COMMANDMASK);
} else if (code == SDL_SCANCODE_RSHIFT) {
pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICERSHIFTKEYMASK,
NX_DEVICELSHIFTKEYMASK, NX_SHIFTMASK);
} else if (code == SDL_SCANCODE_RCTRL) {
pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICERCTLKEYMASK,
NX_DEVICELCTLKEYMASK, NX_CONTROLMASK);
} else if (code == SDL_SCANCODE_RALT) {
pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICERALTKEYMASK,
NX_DEVICELALTKEYMASK, NX_ALTERNATEMASK);
} else if (code == SDL_SCANCODE_RGUI) {
pressed = IsModifierKeyPressed(modifierFlags, NX_DEVICERCMDKEYMASK,
NX_DEVICELCMDKEYMASK, NX_COMMANDMASK);
} else {
return;
}
if (pressed) {
SDL_SendKeyboardKey(0, SDL_PRESSED, code);
} else {
SDL_SendKeyboardKey(0, SDL_RELEASED, code);
}
}
static void UpdateKeymap(SDL_CocoaVideoData *data, SDL_bool send_event)
{
TISInputSourceRef key_layout;
const void *chr_data;
int i;
SDL_Scancode scancode;
SDL_Keycode keymap[SDL_NUM_SCANCODES];
CFDataRef uchrDataRef;
/* See if the keymap needs to be updated */
key_layout = TISCopyCurrentKeyboardLayoutInputSource();
if (key_layout == data.key_layout) {
return;
}
data.key_layout = key_layout;
SDL_GetDefaultKeymap(keymap);
/* Try Unicode data first */
uchrDataRef = TISGetInputSourceProperty(key_layout, kTISPropertyUnicodeKeyLayoutData);
if (uchrDataRef) {
chr_data = CFDataGetBytePtr(uchrDataRef);
} else {
goto cleanup;
}
if (chr_data) {
UInt32 keyboard_type = LMGetKbdType();
OSStatus err;
for (i = 0; i < SDL_arraysize(darwin_scancode_table); i++) {
UniChar s[8];
UniCharCount len;
UInt32 dead_key_state;
/* Make sure this scancode is a valid character scancode */
scancode = darwin_scancode_table[i];
if (scancode == SDL_SCANCODE_UNKNOWN ||
(keymap[scancode] & SDLK_SCANCODE_MASK)) {
continue;
}
/*
* Swap the scancode for these two wrongly translated keys
* UCKeyTranslate() function does not do its job properly for ISO layout keyboards, where the key '@',
* which is located in the top left corner of the keyboard right under the Escape key, and the additional
* key '<', which is on the right of the Shift key, are inverted
*/
if ((scancode == SDL_SCANCODE_NONUSBACKSLASH || scancode == SDL_SCANCODE_GRAVE) && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) {
/* see comments in scancodes_darwin.h */
scancode = (SDL_Scancode)((SDL_SCANCODE_NONUSBACKSLASH + SDL_SCANCODE_GRAVE) - scancode);
}
dead_key_state = 0;
err = UCKeyTranslate((UCKeyboardLayout *)chr_data,
i, kUCKeyActionDown,
0, keyboard_type,
kUCKeyTranslateNoDeadKeysMask,
&dead_key_state, 8, &len, s);
if (err != noErr) {
continue;
}
if (len > 0 && s[0] != 0x10) {
keymap[scancode] = s[0];
}
}
SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES, send_event);
return;
}
cleanup:
CFRelease(key_layout);
}
void Cocoa_InitKeyboard(SDL_VideoDevice *_this)
{
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
UpdateKeymap(data, SDL_FALSE);
/* Set our own names for the platform-dependent but layout-independent keys */
/* This key is NumLock on the MacBook keyboard. :) */
/*SDL_SetScancodeName(SDL_SCANCODE_NUMLOCKCLEAR, "Clear");*/
SDL_SetScancodeName(SDL_SCANCODE_LALT, "Left Option");
SDL_SetScancodeName(SDL_SCANCODE_LGUI, "Left Command");
SDL_SetScancodeName(SDL_SCANCODE_RALT, "Right Option");
SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Command");
data.modifierFlags = (unsigned int)[NSEvent modifierFlags];
SDL_ToggleModState(SDL_KMOD_CAPS, (data.modifierFlags & NSEventModifierFlagCapsLock) ? SDL_TRUE : SDL_FALSE);
}
void Cocoa_StartTextInput(SDL_VideoDevice *_this)
{
@autoreleasepool {
NSView *parentView;
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
SDL_Window *window = SDL_GetKeyboardFocus();
NSWindow *nswindow = nil;
if (window) {
nswindow = ((__bridge SDL_CocoaWindowData *)window->driverdata).nswindow;
}
parentView = [nswindow contentView];
/* We only keep one field editor per process, since only the front most
* window can receive text input events, so it make no sense to keep more
* than one copy. When we switched to another window and requesting for
* text input, simply remove the field editor from its superview then add
* it to the front most window's content view */
if (!data.fieldEdit) {
data.fieldEdit =
[[SDLTranslatorResponder alloc] initWithFrame:NSMakeRect(0.0, 0.0, 0.0, 0.0)];
}
if (![[data.fieldEdit superview] isEqual:parentView]) {
/* DEBUG_IME(@"add fieldEdit to window contentView"); */
[data.fieldEdit removeFromSuperview];
[parentView addSubview:data.fieldEdit];
[nswindow makeFirstResponder:data.fieldEdit];
}
}
}
void Cocoa_StopTextInput(SDL_VideoDevice *_this)
{
@autoreleasepool {
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
if (data && data.fieldEdit) {
[data.fieldEdit removeFromSuperview];
data.fieldEdit = nil;
}
}
}
int Cocoa_SetTextInputRect(SDL_VideoDevice *_this, const SDL_Rect *rect)
{
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
[data.fieldEdit setInputRect:rect];
return 0;
}
void Cocoa_HandleKeyEvent(SDL_VideoDevice *_this, NSEvent *event)
{
unsigned short scancode;
SDL_Scancode code;
SDL_CocoaVideoData *data = _this ? ((__bridge SDL_CocoaVideoData *)_this->driverdata) : nil;
if (!data) {
return; /* can happen when returning from fullscreen Space on shutdown */
}
scancode = [event keyCode];
#if 0
const char *text;
#endif
if ((scancode == 10 || scancode == 50) && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO) {
/* see comments in scancodes_darwin.h */
scancode = 60 - scancode;
}
if (scancode < SDL_arraysize(darwin_scancode_table)) {
code = darwin_scancode_table[scancode];
} else {
/* Hmm, does this ever happen? If so, need to extend the keymap... */
code = SDL_SCANCODE_UNKNOWN;
}
switch ([event type]) {
case NSEventTypeKeyDown:
if (![event isARepeat]) {
/* See if we need to rebuild the keyboard layout */
UpdateKeymap(data, SDL_TRUE);
}
SDL_SendKeyboardKey(Cocoa_GetEventTimestamp([event timestamp]), SDL_PRESSED, code);
#ifdef DEBUG_SCANCODES
if (code == SDL_SCANCODE_UNKNOWN) {
SDL_Log("The key you just pressed is not recognized by SDL. To help get this fixed, report this to the SDL forums/mailing list <https://discourse.libsdl.org/> or to Christian Walther <cwalther@gmx.ch>. Mac virtual key code is %d.\n", scancode);
}
#endif
if (SDL_EventEnabled(SDL_EVENT_TEXT_INPUT)) {
/* FIXME CW 2007-08-16: only send those events to the field editor for which we actually want text events, not e.g. esc or function keys. Arrow keys in particular seem to produce crashes sometimes. */
[data.fieldEdit interpretKeyEvents:[NSArray arrayWithObject:event]];
#if 0
text = [[event characters] UTF8String];
if(text && *text) {
SDL_SendKeyboardText(text);
[data->fieldEdit setString:@""];
}
#endif
}
break;
case NSEventTypeKeyUp:
SDL_SendKeyboardKey(Cocoa_GetEventTimestamp([event timestamp]), SDL_RELEASED, code);
break;
case NSEventTypeFlagsChanged:
HandleModifiers(_this, code, (unsigned int)[event modifierFlags]);
break;
default: /* just to avoid compiler warnings */
break;
}
}
void Cocoa_QuitKeyboard(SDL_VideoDevice *_this)
{
}
typedef int CGSConnection;
typedef enum
{
CGSGlobalHotKeyEnable = 0,
CGSGlobalHotKeyDisable = 1,
} CGSGlobalHotKeyOperatingMode;
extern CGSConnection _CGSDefaultConnection(void);
extern CGError CGSSetGlobalHotKeyOperatingMode(CGSConnection connection, CGSGlobalHotKeyOperatingMode mode);
void Cocoa_SetWindowKeyboardGrab(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed)
{
#ifdef SDL_MAC_NO_SANDBOX
CGSSetGlobalHotKeyOperatingMode(_CGSDefaultConnection(), grabbed ? CGSGlobalHotKeyDisable : CGSGlobalHotKeyEnable);
#endif
}
#endif /* SDL_VIDEO_DRIVER_COCOA */

View File

@ -0,0 +1,27 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_COCOA
extern int Cocoa_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid);
#endif /* SDL_VIDEO_DRIVER_COCOA */

View File

@ -0,0 +1,145 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_COCOA
#include "SDL_cocoavideo.h"
@interface SDLMessageBoxPresenter : NSObject
{
@public
NSInteger clicked;
NSWindow *nswindow;
}
- (id)initWithParentWindow:(SDL_Window *)window;
@end
@implementation SDLMessageBoxPresenter
- (id)initWithParentWindow:(SDL_Window *)window
{
self = [super init];
if (self) {
clicked = -1;
/* Retain the NSWindow because we'll show the alert later on the main thread */
if (window) {
nswindow = ((__bridge SDL_CocoaWindowData *)window->driverdata).nswindow;
} else {
nswindow = nil;
}
}
return self;
}
- (void)showAlert:(NSAlert *)alert
{
if (nswindow) {
[alert beginSheetModalForWindow:nswindow
completionHandler:^(NSModalResponse returnCode) {
[NSApp stopModalWithCode:returnCode];
}];
clicked = [NSApp runModalForWindow:nswindow];
nswindow = nil;
} else {
clicked = [alert runModal];
}
}
@end
static void Cocoa_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int *buttonid, int *returnValue)
{
NSAlert *alert;
const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons;
SDLMessageBoxPresenter *presenter;
NSInteger clicked;
int i;
Cocoa_RegisterApp();
alert = [[NSAlert alloc] init];
if (messageboxdata->flags & SDL_MESSAGEBOX_ERROR) {
[alert setAlertStyle:NSAlertStyleCritical];
} else if (messageboxdata->flags & SDL_MESSAGEBOX_WARNING) {
[alert setAlertStyle:NSAlertStyleWarning];
} else {
[alert setAlertStyle:NSAlertStyleInformational];
}
[alert setMessageText:[NSString stringWithUTF8String:messageboxdata->title]];
[alert setInformativeText:[NSString stringWithUTF8String:messageboxdata->message]];
for (i = 0; i < messageboxdata->numbuttons; ++i) {
const SDL_MessageBoxButtonData *sdlButton;
NSButton *button;
if (messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT) {
sdlButton = &messageboxdata->buttons[messageboxdata->numbuttons - 1 - i];
} else {
sdlButton = &messageboxdata->buttons[i];
}
button = [alert addButtonWithTitle:[NSString stringWithUTF8String:sdlButton->text]];
if (sdlButton->flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) {
[button setKeyEquivalent:@"\r"];
} else if (sdlButton->flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) {
[button setKeyEquivalent:@"\033"];
} else {
[button setKeyEquivalent:@""];
}
}
presenter = [[SDLMessageBoxPresenter alloc] initWithParentWindow:messageboxdata->window];
[presenter showAlert:alert];
clicked = presenter->clicked;
if (clicked >= NSAlertFirstButtonReturn) {
clicked -= NSAlertFirstButtonReturn;
if (messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT) {
clicked = messageboxdata->numbuttons - 1 - clicked;
}
*buttonid = buttons[clicked].buttonid;
*returnValue = 0;
} else {
*returnValue = SDL_SetError("Did not get a valid `clicked button' id: %ld", (long)clicked);
}
}
/* Display a Cocoa message box */
int Cocoa_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
{
@autoreleasepool {
__block int returnValue = 0;
if ([NSThread isMainThread]) {
Cocoa_ShowMessageBoxImpl(messageboxdata, buttonid, &returnValue);
} else {
dispatch_sync(dispatch_get_main_queue(), ^{
Cocoa_ShowMessageBoxImpl(messageboxdata, buttonid, &returnValue);
});
}
return returnValue;
}
}
#endif /* SDL_VIDEO_DRIVER_COCOA */

View File

@ -0,0 +1,66 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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.
*/
/*
* @author Mark Callow, www.edgewise-consulting.com.
*
* Thanks to @slime73 on GitHub for their gist showing how to add a CAMetalLayer
* backed view.
*/
#include "SDL_internal.h"
#ifndef SDL_cocoametalview_h_
#define SDL_cocoametalview_h_
#if defined(SDL_VIDEO_DRIVER_COCOA) && (defined(SDL_VIDEO_VULKAN) || defined(SDL_VIDEO_METAL))
#import "../SDL_sysvideo.h"
#import "SDL_cocoawindow.h"
#import <Cocoa/Cocoa.h>
#import <Metal/Metal.h>
#import <QuartzCore/CAMetalLayer.h>
@interface SDL_cocoametalview : NSView
- (instancetype)initWithFrame:(NSRect)frame
highDPI:(BOOL)highDPI
windowID:(Uint32)windowID
opaque:(BOOL)opaque;
- (void)updateDrawableSize;
- (NSView *)hitTest:(NSPoint)point;
/* Override superclass tag so this class can set it. */
@property(assign, readonly) NSInteger tag;
@property(nonatomic) BOOL highDPI;
@property(nonatomic) Uint32 sdlWindowID;
@end
SDL_MetalView Cocoa_Metal_CreateView(SDL_VideoDevice *_this, SDL_Window *window);
void Cocoa_Metal_DestroyView(SDL_VideoDevice *_this, SDL_MetalView view);
void *Cocoa_Metal_GetLayer(SDL_VideoDevice *_this, SDL_MetalView view);
#endif /* SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) */
#endif /* SDL_cocoametalview_h_ */

View File

@ -0,0 +1,182 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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.
*/
/*
* @author Mark Callow, www.edgewise-consulting.com.
*
* Thanks to @slime73 on GitHub for their gist showing how to add a CAMetalLayer
* backed view.
*/
#include "SDL_internal.h"
#import "SDL_cocoametalview.h"
#if defined(SDL_VIDEO_DRIVER_COCOA) && (defined(SDL_VIDEO_VULKAN) || defined(SDL_VIDEO_METAL))
#include <SDL3/SDL_syswm.h>
static int SDLCALL SDL_MetalViewEventWatch(void *userdata, SDL_Event *event)
{
/* Update the drawable size when SDL receives a size changed event for
* the window that contains the metal view. It would be nice to use
* - (void)resizeWithOldSuperviewSize:(NSSize)oldSize and
* - (void)viewDidChangeBackingProperties instead, but SDL's size change
* events don't always happen in the same frame (for example when a
* resizable window exits a fullscreen Space via the user pressing the OS
* exit-space button). */
if (event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) {
@autoreleasepool {
SDL_cocoametalview *view = (__bridge SDL_cocoametalview *)userdata;
if (view.sdlWindowID == event->window.windowID) {
[view updateDrawableSize];
}
}
}
return 0;
}
@implementation SDL_cocoametalview
/* Return a Metal-compatible layer. */
+ (Class)layerClass
{
return NSClassFromString(@"CAMetalLayer");
}
/* Indicate the view wants to draw using a backing layer instead of drawRect. */
- (BOOL)wantsUpdateLayer
{
return YES;
}
/* When the wantsLayer property is set to YES, this method will be invoked to
* return a layer instance.
*/
- (CALayer *)makeBackingLayer
{
return [self.class.layerClass layer];
}
- (instancetype)initWithFrame:(NSRect)frame
highDPI:(BOOL)highDPI
windowID:(Uint32)windowID
opaque:(BOOL)opaque
{
self = [super initWithFrame:frame];
if (self != nil) {
self.highDPI = highDPI;
self.sdlWindowID = windowID;
self.wantsLayer = YES;
/* Allow resize. */
self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
self.layer.opaque = opaque;
SDL_AddEventWatch(SDL_MetalViewEventWatch, (__bridge void *)(self));
[self updateDrawableSize];
}
return self;
}
- (void)dealloc
{
SDL_DelEventWatch(SDL_MetalViewEventWatch, (__bridge void *)(self));
}
- (NSInteger)tag
{
return SDL_METALVIEW_TAG;
}
- (void)updateDrawableSize
{
CAMetalLayer *metalLayer = (CAMetalLayer *)self.layer;
NSSize size = self.bounds.size;
NSSize backingSize = size;
if (self.highDPI) {
/* Note: NSHighResolutionCapable must be set to true in the app's
* Info.plist in order for the backing size to be high res.
*/
backingSize = [self convertSizeToBacking:size];
}
metalLayer.contentsScale = backingSize.height / size.height;
metalLayer.drawableSize = NSSizeToCGSize(backingSize);
}
- (NSView *)hitTest:(NSPoint)point
{
return nil;
}
@end
SDL_MetalView Cocoa_Metal_CreateView(SDL_VideoDevice *_this, SDL_Window *window)
{
@autoreleasepool {
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->driverdata;
NSView *view = data.nswindow.contentView;
BOOL highDPI = (window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) != 0;
BOOL opaque = (window->flags & SDL_WINDOW_TRANSPARENT) == 0;
Uint32 windowID = SDL_GetWindowID(window);
SDL_cocoametalview *newview;
SDL_MetalView metalview;
newview = [[SDL_cocoametalview alloc] initWithFrame:view.frame
highDPI:highDPI
windowID:windowID
opaque:opaque];
if (newview == nil) {
SDL_OutOfMemory();
return NULL;
}
[view addSubview:newview];
/* Make sure the drawable size is up to date after attaching the view. */
[newview updateDrawableSize];
metalview = (SDL_MetalView)CFBridgingRetain(newview);
return metalview;
}
}
void Cocoa_Metal_DestroyView(SDL_VideoDevice *_this, SDL_MetalView view)
{
@autoreleasepool {
SDL_cocoametalview *metalview = CFBridgingRelease(view);
[metalview removeFromSuperview];
}
}
void *Cocoa_Metal_GetLayer(SDL_VideoDevice *_this, SDL_MetalView view)
{
@autoreleasepool {
SDL_cocoametalview *cocoaview = (__bridge SDL_cocoametalview *)view;
return (__bridge void *)cocoaview.layer;
}
}
#endif /* SDL_VIDEO_DRIVER_COCOA && (SDL_VIDEO_VULKAN || SDL_VIDEO_METAL) */

View File

@ -0,0 +1,43 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_cocoamodes_h_
#define SDL_cocoamodes_h_
struct SDL_DisplayData
{
CGDirectDisplayID display;
};
struct SDL_DisplayModeData
{
CFMutableArrayRef modes;
};
extern void Cocoa_InitModes(SDL_VideoDevice *_this);
extern int Cocoa_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
extern int Cocoa_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect);
extern int Cocoa_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
extern int Cocoa_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
extern void Cocoa_QuitModes(SDL_VideoDevice *_this);
#endif /* SDL_cocoamodes_h_ */

View File

@ -0,0 +1,540 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_COCOA
#include "SDL_cocoavideo.h"
/* We need this for IODisplayCreateInfoDictionary and kIODisplayOnlyPreferredName */
#include <IOKit/graphics/IOGraphicsLib.h>
/* We need this for CVDisplayLinkGetNominalOutputVideoRefreshPeriod */
#include <CoreVideo/CVBase.h>
#include <CoreVideo/CVDisplayLink.h>
/* This gets us MAC_OS_X_VERSION_MIN_REQUIRED... */
#include <AvailabilityMacros.h>
#ifndef MAC_OS_X_VERSION_10_13
#define NSAppKitVersionNumber10_12 1504
#endif
#if (IOGRAPHICSTYPES_REV < 40)
#define kDisplayModeNativeFlag 0x02000000
#endif
static int CG_SetError(const char *prefix, CGDisplayErr result)
{
const char *error;
switch (result) {
case kCGErrorFailure:
error = "kCGErrorFailure";
break;
case kCGErrorIllegalArgument:
error = "kCGErrorIllegalArgument";
break;
case kCGErrorInvalidConnection:
error = "kCGErrorInvalidConnection";
break;
case kCGErrorInvalidContext:
error = "kCGErrorInvalidContext";
break;
case kCGErrorCannotComplete:
error = "kCGErrorCannotComplete";
break;
case kCGErrorNotImplemented:
error = "kCGErrorNotImplemented";
break;
case kCGErrorRangeCheck:
error = "kCGErrorRangeCheck";
break;
case kCGErrorTypeCheck:
error = "kCGErrorTypeCheck";
break;
case kCGErrorInvalidOperation:
error = "kCGErrorInvalidOperation";
break;
case kCGErrorNoneAvailable:
error = "kCGErrorNoneAvailable";
break;
default:
error = "Unknown Error";
break;
}
return SDL_SetError("%s: %s", prefix, error);
}
static float GetDisplayModeRefreshRate(CGDisplayModeRef vidmode, CVDisplayLinkRef link)
{
double refreshRate = CGDisplayModeGetRefreshRate(vidmode);
/* CGDisplayModeGetRefreshRate can return 0 (eg for built-in displays). */
if (refreshRate == 0 && link != NULL) {
CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link);
if ((time.flags & kCVTimeIsIndefinite) == 0 && time.timeValue != 0) {
refreshRate = (double)time.timeScale / time.timeValue;
}
}
return (int)(refreshRate * 100) / 100.0f;
}
static SDL_bool HasValidDisplayModeFlags(CGDisplayModeRef vidmode)
{
uint32_t ioflags = CGDisplayModeGetIOFlags(vidmode);
/* Filter out modes which have flags that we don't want. */
if (ioflags & (kDisplayModeNeverShowFlag | kDisplayModeNotGraphicsQualityFlag)) {
return SDL_FALSE;
}
/* Filter out modes which don't have flags that we want. */
if (!(ioflags & kDisplayModeValidFlag) || !(ioflags & kDisplayModeSafeFlag)) {
return SDL_FALSE;
}
return SDL_TRUE;
}
static Uint32 GetDisplayModePixelFormat(CGDisplayModeRef vidmode)
{
/* This API is deprecated in 10.11 with no good replacement (as of 10.15). */
CFStringRef fmt = CGDisplayModeCopyPixelEncoding(vidmode);
Uint32 pixelformat = SDL_PIXELFORMAT_UNKNOWN;
if (CFStringCompare(fmt, CFSTR(IO32BitDirectPixels),
kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
pixelformat = SDL_PIXELFORMAT_ARGB8888;
} else if (CFStringCompare(fmt, CFSTR(IO16BitDirectPixels),
kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
pixelformat = SDL_PIXELFORMAT_ARGB1555;
} else if (CFStringCompare(fmt, CFSTR(kIO30BitDirectPixels),
kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
pixelformat = SDL_PIXELFORMAT_ARGB2101010;
} else {
/* ignore 8-bit and such for now. */
}
CFRelease(fmt);
return pixelformat;
}
static SDL_bool GetDisplayMode(SDL_VideoDevice *_this, CGDisplayModeRef vidmode, SDL_bool vidmodeCurrent, CFArrayRef modelist, CVDisplayLinkRef link, SDL_DisplayMode *mode)
{
SDL_DisplayModeData *data;
bool usableForGUI = CGDisplayModeIsUsableForDesktopGUI(vidmode);
size_t width = CGDisplayModeGetWidth(vidmode);
size_t height = CGDisplayModeGetHeight(vidmode);
size_t pixelW = width;
size_t pixelH = height;
uint32_t ioflags = CGDisplayModeGetIOFlags(vidmode);
float refreshrate = GetDisplayModeRefreshRate(vidmode, link);
Uint32 format = GetDisplayModePixelFormat(vidmode);
bool interlaced = (ioflags & kDisplayModeInterlacedFlag) != 0;
CFMutableArrayRef modes;
if (format == SDL_PIXELFORMAT_UNKNOWN) {
return SDL_FALSE;
}
/* Don't fail the current mode based on flags because this could prevent Cocoa_InitModes from
* succeeding if the current mode lacks certain flags (esp kDisplayModeSafeFlag). */
if (!vidmodeCurrent && !HasValidDisplayModeFlags(vidmode)) {
return SDL_FALSE;
}
modes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(modes, vidmode);
/* If a list of possible display modes is passed in, use it to filter out
* modes that have duplicate sizes. We don't just rely on SDL's higher level
* duplicate filtering because this code can choose what properties are
* preferred, and it can add CGDisplayModes to the DisplayModeData's list of
* modes to try (see comment below for why that's necessary). */
pixelW = CGDisplayModeGetPixelWidth(vidmode);
pixelH = CGDisplayModeGetPixelHeight(vidmode);
if (modelist != NULL) {
CFIndex modescount = CFArrayGetCount(modelist);
int i;
for (i = 0; i < modescount; i++) {
size_t otherW, otherH, otherpixelW, otherpixelH;
float otherrefresh;
Uint32 otherformat;
bool otherGUI;
CGDisplayModeRef othermode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modelist, i);
uint32_t otherioflags = CGDisplayModeGetIOFlags(othermode);
if (CFEqual(vidmode, othermode)) {
continue;
}
if (!HasValidDisplayModeFlags(othermode)) {
continue;
}
otherW = CGDisplayModeGetWidth(othermode);
otherH = CGDisplayModeGetHeight(othermode);
otherpixelW = CGDisplayModeGetPixelWidth(othermode);
otherpixelH = CGDisplayModeGetPixelHeight(othermode);
otherrefresh = GetDisplayModeRefreshRate(othermode, link);
otherformat = GetDisplayModePixelFormat(othermode);
otherGUI = CGDisplayModeIsUsableForDesktopGUI(othermode);
/* Ignore this mode if it's interlaced and there's a non-interlaced
* mode in the list with the same properties.
*/
if (interlaced && ((otherioflags & kDisplayModeInterlacedFlag) == 0) && width == otherW && height == otherH && pixelW == otherpixelW && pixelH == otherpixelH && refreshrate == otherrefresh && format == otherformat && usableForGUI == otherGUI) {
CFRelease(modes);
return SDL_FALSE;
}
/* Ignore this mode if it's not usable for desktop UI and its
* properties are equal to another GUI-capable mode in the list.
*/
if (width == otherW && height == otherH && pixelW == otherpixelW && pixelH == otherpixelH && !usableForGUI && otherGUI && refreshrate == otherrefresh && format == otherformat) {
CFRelease(modes);
return SDL_FALSE;
}
/* If multiple modes have the exact same properties, they'll all
* go in the list of modes to try when SetDisplayMode is called.
* This is needed because kCGDisplayShowDuplicateLowResolutionModes
* (which is used to expose highdpi display modes) can make the
* list of modes contain duplicates (according to their properties
* obtained via public APIs) which don't work with SetDisplayMode.
* Those duplicate non-functional modes *do* have different pixel
* formats according to their internal data structure viewed with
* NSLog, but currently no public API can detect that.
* https://bugzilla.libsdl.org/show_bug.cgi?id=4822
*
* As of macOS 10.15.0, those duplicates have the exact same
* properties via public APIs in every way (even their IO flags and
* CGDisplayModeGetIODisplayModeID is the same), so we could test
* those for equality here too, but I'm intentionally not doing that
* in case there are duplicate modes with different IO flags or IO
* display mode IDs in the future. In that case I think it's better
* to try them all in SetDisplayMode than to risk one of them being
* correct but it being filtered out by SDL_AddFullscreenDisplayMode
* as being a duplicate.
*/
if (width == otherW && height == otherH && pixelW == otherpixelW && pixelH == otherpixelH && usableForGUI == otherGUI && refreshrate == otherrefresh && format == otherformat) {
CFArrayAppendValue(modes, othermode);
}
}
}
SDL_zerop(mode);
data = (SDL_DisplayModeData *)SDL_malloc(sizeof(*data));
if (!data) {
CFRelease(modes);
return SDL_FALSE;
}
data->modes = modes;
mode->format = format;
mode->w = (int)width;
mode->h = (int)height;
mode->pixel_density = (float)pixelW / width;
mode->refresh_rate = refreshrate;
mode->driverdata = data;
return SDL_TRUE;
}
static const char *Cocoa_GetDisplayName(CGDirectDisplayID displayID)
{
/* This API is deprecated in 10.9 with no good replacement (as of 10.15). */
io_service_t servicePort = CGDisplayIOServicePort(displayID);
CFDictionaryRef deviceInfo = IODisplayCreateInfoDictionary(servicePort, kIODisplayOnlyPreferredName);
NSDictionary *localizedNames = [(__bridge NSDictionary *)deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]];
const char *displayName = NULL;
if ([localizedNames count] > 0) {
displayName = SDL_strdup([[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] UTF8String]);
}
CFRelease(deviceInfo);
return displayName;
}
void Cocoa_InitModes(SDL_VideoDevice *_this)
{
@autoreleasepool {
CGDisplayErr result;
CGDirectDisplayID *displays;
CGDisplayCount numDisplays;
SDL_bool isstack;
int pass, i;
result = CGGetOnlineDisplayList(0, NULL, &numDisplays);
if (result != kCGErrorSuccess) {
CG_SetError("CGGetOnlineDisplayList()", result);
return;
}
displays = SDL_small_alloc(CGDirectDisplayID, numDisplays, &isstack);
result = CGGetOnlineDisplayList(numDisplays, displays, &numDisplays);
if (result != kCGErrorSuccess) {
CG_SetError("CGGetOnlineDisplayList()", result);
SDL_small_free(displays, isstack);
return;
}
/* Pick up the primary display in the first pass, then get the rest */
for (pass = 0; pass < 2; ++pass) {
for (i = 0; i < numDisplays; ++i) {
SDL_VideoDisplay display;
SDL_DisplayData *displaydata;
SDL_DisplayMode mode;
CGDisplayModeRef moderef = NULL;
CVDisplayLinkRef link = NULL;
if (pass == 0) {
if (!CGDisplayIsMain(displays[i])) {
continue;
}
} else {
if (CGDisplayIsMain(displays[i])) {
continue;
}
}
if (CGDisplayMirrorsDisplay(displays[i]) != kCGNullDirectDisplay) {
continue;
}
moderef = CGDisplayCopyDisplayMode(displays[i]);
if (!moderef) {
continue;
}
displaydata = (SDL_DisplayData *)SDL_malloc(sizeof(*displaydata));
if (!displaydata) {
CGDisplayModeRelease(moderef);
continue;
}
displaydata->display = displays[i];
CVDisplayLinkCreateWithCGDisplay(displays[i], &link);
SDL_zero(display);
/* this returns a stddup'ed string */
display.name = (char *)Cocoa_GetDisplayName(displays[i]);
if (!GetDisplayMode(_this, moderef, SDL_TRUE, NULL, link, &mode)) {
CVDisplayLinkRelease(link);
CGDisplayModeRelease(moderef);
SDL_free(display.name);
SDL_free(displaydata);
continue;
}
CVDisplayLinkRelease(link);
CGDisplayModeRelease(moderef);
display.desktop_mode = mode;
display.driverdata = displaydata;
SDL_AddVideoDisplay(&display, SDL_FALSE);
SDL_free(display.name);
}
}
SDL_small_free(displays, isstack);
}
}
int Cocoa_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect)
{
SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
CGRect cgrect;
cgrect = CGDisplayBounds(displaydata->display);
rect->x = (int)cgrect.origin.x;
rect->y = (int)cgrect.origin.y;
rect->w = (int)cgrect.size.width;
rect->h = (int)cgrect.size.height;
return 0;
}
int Cocoa_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect)
{
SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
const CGDirectDisplayID cgdisplay = displaydata->display;
NSArray *screens = [NSScreen screens];
NSScreen *screen = nil;
/* !!! FIXME: maybe track the NSScreen in SDL_DisplayData? */
for (NSScreen *i in screens) {
const CGDirectDisplayID thisDisplay = (CGDirectDisplayID)[[[i deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
if (thisDisplay == cgdisplay) {
screen = i;
break;
}
}
SDL_assert(screen != nil); /* didn't find it?! */
if (screen == nil) {
return -1;
}
{
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 0;
}
int Cocoa_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display)
{
SDL_DisplayData *data = (SDL_DisplayData *)display->driverdata;
CVDisplayLinkRef link = NULL;
CFArrayRef modes;
CFDictionaryRef dict = NULL;
const CFStringRef dictkeys[] = { kCGDisplayShowDuplicateLowResolutionModes };
const CFBooleanRef dictvalues[] = { kCFBooleanTrue };
CVDisplayLinkCreateWithCGDisplay(data->display, &link);
/* By default, CGDisplayCopyAllDisplayModes will only get a subset of the
* system's available modes. For example on a 15" 2016 MBP, users can
* choose 1920x1080@2x in System Preferences but it won't show up here,
* unless we specify the option below.
* The display modes returned by CGDisplayCopyAllDisplayModes are also not
* high dpi-capable unless this option is set.
* macOS 10.15 also seems to have a bug where entering, exiting, and
* re-entering exclusive fullscreen with a low dpi display mode can cause
* the content of the screen to move up, which this setting avoids:
* https://bugzilla.libsdl.org/show_bug.cgi?id=4822
*/
dict = CFDictionaryCreate(NULL,
(const void **)dictkeys,
(const void **)dictvalues,
1,
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
modes = CGDisplayCopyAllDisplayModes(data->display, dict);
if (dict) {
CFRelease(dict);
}
if (modes) {
CFIndex i;
const CFIndex count = CFArrayGetCount(modes);
for (i = 0; i < count; i++) {
CGDisplayModeRef moderef = (CGDisplayModeRef)CFArrayGetValueAtIndex(modes, i);
SDL_DisplayMode mode;
if (GetDisplayMode(_this, moderef, SDL_FALSE, modes, link, &mode)) {
if (!SDL_AddFullscreenDisplayMode(display, &mode)) {
CFRelease(((SDL_DisplayModeData *)mode.driverdata)->modes);
SDL_free(mode.driverdata);
}
}
}
CFRelease(modes);
}
CVDisplayLinkRelease(link);
return 0;
}
static CGError SetDisplayModeForDisplay(CGDirectDisplayID display, SDL_DisplayModeData *data)
{
/* SDL_DisplayModeData can contain multiple CGDisplayModes to try (with
* identical properties), some of which might not work. See GetDisplayMode.
*/
CGError result = kCGErrorFailure;
for (CFIndex i = 0; i < CFArrayGetCount(data->modes); i++) {
CGDisplayModeRef moderef = (CGDisplayModeRef)CFArrayGetValueAtIndex(data->modes, i);
result = CGDisplaySetDisplayMode(display, moderef, NULL);
if (result == kCGErrorSuccess) {
/* If this mode works, try it first next time. */
CFArrayExchangeValuesAtIndices(data->modes, i, 0);
break;
}
}
return result;
}
int Cocoa_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
{
SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
SDL_DisplayModeData *data = (SDL_DisplayModeData *)mode->driverdata;
CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
CGError result = kCGErrorSuccess;
/* Fade to black to hide resolution-switching flicker */
if (CGAcquireDisplayFadeReservation(5, &fade_token) == kCGErrorSuccess) {
CGDisplayFade(fade_token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
}
if (data == display->desktop_mode.driverdata) {
/* Restoring desktop mode */
SetDisplayModeForDisplay(displaydata->display, data);
} else {
/* Do the physical switch */
result = SetDisplayModeForDisplay(displaydata->display, data);
}
/* Fade in again (asynchronously) */
if (fade_token != kCGDisplayFadeReservationInvalidToken) {
CGDisplayFade(fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
CGReleaseDisplayFadeReservation(fade_token);
}
if (result != kCGErrorSuccess) {
CG_SetError("CGDisplaySwitchToMode()", result);
return -1;
}
return 0;
}
void Cocoa_QuitModes(SDL_VideoDevice *_this)
{
int i, j;
for (i = 0; i < _this->num_displays; ++i) {
SDL_VideoDisplay *display = &_this->displays[i];
SDL_DisplayModeData *mode;
if (display->current_mode->driverdata != display->desktop_mode.driverdata) {
Cocoa_SetDisplayMode(_this, display, &display->desktop_mode);
}
mode = (SDL_DisplayModeData *)display->desktop_mode.driverdata;
CFRelease(mode->modes);
for (j = 0; j < display->num_fullscreen_modes; j++) {
mode = (SDL_DisplayModeData *)display->fullscreen_modes[j].driverdata;
CFRelease(mode->modes);
}
}
}
#endif /* SDL_VIDEO_DRIVER_COCOA */

View File

@ -0,0 +1,50 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_cocoamouse_h_
#define SDL_cocoamouse_h_
#include "SDL_cocoavideo.h"
extern int Cocoa_InitMouse(SDL_VideoDevice *_this);
extern void Cocoa_HandleMouseEvent(SDL_VideoDevice *_this, NSEvent *event);
extern void Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event);
extern void Cocoa_HandleMouseWarp(CGFloat x, CGFloat y);
extern void Cocoa_QuitMouse(SDL_VideoDevice *_this);
typedef struct
{
/* Whether we've seen a cursor warp since the last move event. */
SDL_bool seenWarp;
/* What location our last cursor warp was to. */
CGFloat lastWarpX;
CGFloat lastWarpY;
/* What location we last saw the cursor move to. */
CGFloat lastMoveX;
CGFloat lastMoveY;
} SDL_MouseData;
@interface NSCursor (InvisibleCursor)
+ (NSCursor *)invisibleCursor;
@end
#endif /* SDL_cocoamouse_h_ */

View File

@ -0,0 +1,571 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_COCOA
#include "SDL_cocoamouse.h"
#include "SDL_cocoavideo.h"
#include "../../events/SDL_mouse_c.h"
/* #define DEBUG_COCOAMOUSE */
#ifdef DEBUG_COCOAMOUSE
#define DLog(fmt, ...) printf("%s: " fmt "\n", __func__, ##__VA_ARGS__)
#else
#define DLog(...) \
do { \
} while (0)
#endif
@implementation NSCursor (InvisibleCursor)
+ (NSCursor *)invisibleCursor
{
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
};
NSData *cursorData = [NSData dataWithBytesNoCopy:&cursorBytes[0]
length:sizeof(cursorBytes)
freeWhenDone:NO];
NSImage *cursorImage = [[NSImage alloc] initWithData:cursorData];
invisibleCursor = [[NSCursor alloc] initWithImage:cursorImage
hotSpot:NSZeroPoint];
}
return invisibleCursor;
}
@end
static SDL_Cursor *Cocoa_CreateDefaultCursor(void)
{
@autoreleasepool {
NSCursor *nscursor;
SDL_Cursor *cursor = NULL;
nscursor = [NSCursor arrowCursor];
if (nscursor) {
cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
cursor->driverdata = (void *)CFBridgingRetain(nscursor);
}
}
return cursor;
}
}
static SDL_Cursor *Cocoa_CreateCursor(SDL_Surface *surface, 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->driverdata = (void *)CFBridgingRetain(nscursor);
}
}
return cursor;
}
}
/* there are .pdf files of some of the cursors we need, installed by default on macOS, but not available through NSCursor.
If we can load them ourselves, use them, otherwise fallback to something standard but not super-great.
Since these are under /System, they should be available even to sandboxed apps. */
static NSCursor *LoadHiddenSystemCursor(NSString *cursorName, SEL fallback)
{
NSString *cursorPath = [@"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/Resources/cursors" stringByAppendingPathComponent:cursorName];
NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[cursorPath stringByAppendingPathComponent:@"info.plist"]];
/* we can't do animation atm. :/ */
const int frames = (int)[[info valueForKey:@"frames"] integerValue];
NSCursor *cursor;
NSImage *image = [[NSImage alloc] initWithContentsOfFile:[cursorPath stringByAppendingPathComponent:@"cursor.pdf"]];
if ((image == nil) || (image.isValid == NO)) {
return [NSCursor performSelector:fallback];
}
if (frames > 1) {
#ifdef MAC_OS_VERSION_12_0 /* same value as deprecated symbol. */
const NSCompositingOperation operation = NSCompositingOperationCopy;
#else
const NSCompositingOperation operation = NSCompositeCopy;
#endif
const NSSize cropped_size = NSMakeSize(image.size.width, (int)(image.size.height / frames));
NSImage *cropped = [[NSImage alloc] initWithSize:cropped_size];
if (cropped == nil) {
return [NSCursor performSelector:fallback];
}
[cropped lockFocus];
{
const NSRect cropped_rect = NSMakeRect(0, 0, cropped_size.width, cropped_size.height);
[image drawInRect:cropped_rect fromRect:cropped_rect operation:operation fraction:1];
}
[cropped unlockFocus];
image = cropped;
}
cursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint([[info valueForKey:@"hotx"] doubleValue], [[info valueForKey:@"hoty"] doubleValue])];
return cursor;
}
static SDL_Cursor *Cocoa_CreateSystemCursor(SDL_SystemCursor id)
{
@autoreleasepool {
NSCursor *nscursor = NULL;
SDL_Cursor *cursor = NULL;
switch (id) {
case SDL_SYSTEM_CURSOR_ARROW:
nscursor = [NSCursor arrowCursor];
break;
case SDL_SYSTEM_CURSOR_IBEAM:
nscursor = [NSCursor IBeamCursor];
break;
case SDL_SYSTEM_CURSOR_CROSSHAIR:
nscursor = [NSCursor crosshairCursor];
break;
case SDL_SYSTEM_CURSOR_WAIT: /* !!! FIXME: this is more like WAITARROW */
nscursor = LoadHiddenSystemCursor(@"busybutclickable", @selector(arrowCursor));
break;
case SDL_SYSTEM_CURSOR_WAITARROW: /* !!! FIXME: this is meant to be animated */
nscursor = LoadHiddenSystemCursor(@"busybutclickable", @selector(arrowCursor));
break;
case SDL_SYSTEM_CURSOR_SIZENWSE:
nscursor = LoadHiddenSystemCursor(@"resizenorthwestsoutheast", @selector(closedHandCursor));
break;
case SDL_SYSTEM_CURSOR_SIZENESW:
nscursor = LoadHiddenSystemCursor(@"resizenortheastsouthwest", @selector(closedHandCursor));
break;
case SDL_SYSTEM_CURSOR_SIZEWE:
nscursor = LoadHiddenSystemCursor(@"resizeeastwest", @selector(resizeLeftRightCursor));
break;
case SDL_SYSTEM_CURSOR_SIZENS:
nscursor = LoadHiddenSystemCursor(@"resizenorthsouth", @selector(resizeUpDownCursor));
break;
case SDL_SYSTEM_CURSOR_SIZEALL:
nscursor = LoadHiddenSystemCursor(@"move", @selector(closedHandCursor));
break;
case SDL_SYSTEM_CURSOR_NO:
nscursor = [NSCursor operationNotAllowedCursor];
break;
case SDL_SYSTEM_CURSOR_HAND:
nscursor = [NSCursor pointingHandCursor];
break;
default:
SDL_assert(!"Unknown system cursor");
return NULL;
}
if (nscursor) {
cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
/* We'll free it later, so retain it here */
cursor->driverdata = (void *)CFBridgingRetain(nscursor);
}
}
return cursor;
}
}
static void Cocoa_FreeCursor(SDL_Cursor *cursor)
{
@autoreleasepool {
CFBridgingRelease(cursor->driverdata);
SDL_free(cursor);
}
}
static int Cocoa_ShowCursor(SDL_Cursor *cursor)
{
@autoreleasepool {
SDL_VideoDevice *device = SDL_GetVideoDevice();
SDL_Window *window = (device ? device->windows : NULL);
for (; window != NULL; window = window->next) {
SDL_Mouse *mouse = SDL_GetMouse();
if(mouse->focus) {
if (mouse->cursor_shown && mouse->cur_cursor && !mouse->relative_mode) {
[(__bridge NSCursor*)mouse->cur_cursor->driverdata set];
} else {
[[NSCursor invisibleCursor] set];
}
} else {
[[NSCursor arrowCursor] set];
}
}
return 0;
}
}
static SDL_Window *SDL_FindWindowAtPoint(const float x, const float y)
{
const SDL_FPoint pt = { x, y };
SDL_Window *i;
for (i = SDL_GetVideoDevice()->windows; i; i = i->next) {
const SDL_FRect r = { (float)i->x, (float)i->y, (float)i->w, (float)i->h };
if (SDL_PointInRectFloat(&pt, &r)) {
return i;
}
}
return NULL;
}
static int Cocoa_WarpMouseGlobal(float x, float y)
{
CGPoint point;
SDL_Mouse *mouse = SDL_GetMouse();
if (mouse->focus) {
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)mouse->focus->driverdata;
if ([data.listener isMovingOrFocusClickPending]) {
DLog("Postponing warp, window being moved or focused.");
[data.listener setPendingMoveX:x Y:y];
return 0;
}
}
point = CGPointMake(x, y);
Cocoa_HandleMouseWarp(point.x, point.y);
CGWarpMouseCursorPosition(point);
/* CGWarpMouse causes a short delay by default, which is preventable by
* Calling this directly after. CGSetLocalEventsSuppressionInterval can also
* prevent it, but it's deprecated as macOS 10.6.
*/
if (!mouse->relative_mode) {
CGAssociateMouseAndMouseCursorPosition(YES);
}
/* CGWarpMouseCursorPosition doesn't generate a window event, unlike our
* other implementations' APIs. Send what's appropriate.
*/
if (!mouse->relative_mode) {
SDL_Window *win = SDL_FindWindowAtPoint(x, y);
SDL_SetMouseFocus(win);
if (win) {
SDL_assert(win == mouse->focus);
SDL_SendMouseMotion(0, win, mouse->mouseID, 0, x - win->x, y - win->y);
}
}
return 0;
}
static int Cocoa_WarpMouse(SDL_Window *window, float x, float y)
{
return Cocoa_WarpMouseGlobal(window->x + x, window->y + y);
}
static int Cocoa_SetRelativeMouseMode(SDL_bool enabled)
{
SDL_Window *window = SDL_GetKeyboardFocus();
CGError result;
SDL_CocoaWindowData *data;
if (enabled) {
if (window) {
/* make sure the mouse isn't at the corner of the window, as this can confuse things if macOS thinks a window resize is happening on the first click. */
const CGPoint point = CGPointMake((float)(window->x + (window->w / 2)), (float)(window->y + (window->h / 2)));
Cocoa_HandleMouseWarp(point.x, point.y);
CGWarpMouseCursorPosition(point);
}
DLog("Turning on.");
result = CGAssociateMouseAndMouseCursorPosition(NO);
} else {
DLog("Turning off.");
result = CGAssociateMouseAndMouseCursorPosition(YES);
}
if (result != kCGErrorSuccess) {
return SDL_SetError("CGAssociateMouseAndMouseCursorPosition() failed");
}
/* We will re-apply the non-relative mode when the window gets focus, if it
* doesn't have focus right now.
*/
if (!window) {
return 0;
}
/* We will re-apply the non-relative mode when the window finishes being moved,
* if it is being moved right now.
*/
data = (__bridge SDL_CocoaWindowData *)window->driverdata;
if ([data.listener isMovingOrFocusClickPending]) {
return 0;
}
/* The hide/unhide calls are redundant most of the time, but they fix
* https://bugzilla.libsdl.org/show_bug.cgi?id=2550
*/
if (enabled) {
[NSCursor hide];
} else {
[NSCursor unhide];
}
return 0;
}
static int Cocoa_CaptureMouse(SDL_Window *window)
{
/* our Cocoa event code already tracks the mouse outside the window,
so all we have to do here is say "okay" and do what we always do. */
return 0;
}
static Uint32 Cocoa_GetGlobalMouseState(float *x, float *y)
{
const NSUInteger cocoaButtons = [NSEvent pressedMouseButtons];
const NSPoint cocoaLocation = [NSEvent mouseLocation];
Uint32 retval = 0;
*x = cocoaLocation.x;
*y = (CGDisplayPixelsHigh(kCGDirectMainDisplay) - cocoaLocation.y);
retval |= (cocoaButtons & (1 << 0)) ? SDL_BUTTON_LMASK : 0;
retval |= (cocoaButtons & (1 << 1)) ? SDL_BUTTON_RMASK : 0;
retval |= (cocoaButtons & (1 << 2)) ? SDL_BUTTON_MMASK : 0;
retval |= (cocoaButtons & (1 << 3)) ? SDL_BUTTON_X1MASK : 0;
retval |= (cocoaButtons & (1 << 4)) ? SDL_BUTTON_X2MASK : 0;
return retval;
}
int Cocoa_InitMouse(SDL_VideoDevice *_this)
{
NSPoint location;
SDL_Mouse *mouse = SDL_GetMouse();
SDL_MouseData *driverdata = (SDL_MouseData *)SDL_calloc(1, sizeof(SDL_MouseData));
if (driverdata == NULL) {
return SDL_OutOfMemory();
}
mouse->driverdata = driverdata;
mouse->CreateCursor = Cocoa_CreateCursor;
mouse->CreateSystemCursor = Cocoa_CreateSystemCursor;
mouse->ShowCursor = Cocoa_ShowCursor;
mouse->FreeCursor = Cocoa_FreeCursor;
mouse->WarpMouse = Cocoa_WarpMouse;
mouse->WarpMouseGlobal = Cocoa_WarpMouseGlobal;
mouse->SetRelativeMouseMode = Cocoa_SetRelativeMouseMode;
mouse->CaptureMouse = Cocoa_CaptureMouse;
mouse->GetGlobalMouseState = Cocoa_GetGlobalMouseState;
SDL_SetDefaultCursor(Cocoa_CreateDefaultCursor());
location = [NSEvent mouseLocation];
driverdata->lastMoveX = location.x;
driverdata->lastMoveY = location.y;
return 0;
}
static void Cocoa_HandleTitleButtonEvent(SDL_VideoDevice *_this, NSEvent *event)
{
SDL_Window *window;
NSWindow *nswindow = [event window];
/* You might land in this function before SDL_Init if showing a message box.
Don't dereference a NULL pointer if that happens. */
if (_this == NULL) {
return;
}
for (window = _this->windows; window; window = window->next) {
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->driverdata;
if (data && data.nswindow == nswindow) {
switch ([event type]) {
case NSEventTypeLeftMouseDown:
case NSEventTypeRightMouseDown:
case NSEventTypeOtherMouseDown:
[data.listener setFocusClickPending:[event buttonNumber]];
break;
case NSEventTypeLeftMouseUp:
case NSEventTypeRightMouseUp:
case NSEventTypeOtherMouseUp:
[data.listener clearFocusClickPending:[event buttonNumber]];
break;
default:
break;
}
break;
}
}
}
void Cocoa_HandleMouseEvent(SDL_VideoDevice *_this, NSEvent *event)
{
SDL_Mouse *mouse;
SDL_MouseData *driverdata;
SDL_MouseID mouseID;
NSPoint location;
CGFloat lastMoveX, lastMoveY;
float deltaX, deltaY;
SDL_bool seenWarp;
switch ([event type]) {
case NSEventTypeMouseMoved:
case NSEventTypeLeftMouseDragged:
case NSEventTypeRightMouseDragged:
case NSEventTypeOtherMouseDragged:
break;
case NSEventTypeLeftMouseDown:
case NSEventTypeLeftMouseUp:
case NSEventTypeRightMouseDown:
case NSEventTypeRightMouseUp:
case NSEventTypeOtherMouseDown:
case NSEventTypeOtherMouseUp:
if ([event window]) {
NSRect windowRect = [[[event window] contentView] frame];
if (!NSMouseInRect([event locationInWindow], windowRect, NO)) {
Cocoa_HandleTitleButtonEvent(_this, event);
return;
}
}
return;
default:
/* Ignore any other events. */
return;
}
mouse = SDL_GetMouse();
driverdata = (SDL_MouseData *)mouse->driverdata;
if (!driverdata) {
return; /* can happen when returning from fullscreen Space on shutdown */
}
mouseID = mouse ? mouse->mouseID : 0;
seenWarp = driverdata->seenWarp;
driverdata->seenWarp = NO;
location = [NSEvent mouseLocation];
lastMoveX = driverdata->lastMoveX;
lastMoveY = driverdata->lastMoveY;
driverdata->lastMoveX = location.x;
driverdata->lastMoveY = location.y;
DLog("Last seen mouse: (%g, %g)", location.x, location.y);
/* Non-relative movement is handled in -[Cocoa_WindowListener mouseMoved:] */
if (!mouse->relative_mode) {
return;
}
/* Ignore events that aren't inside the client area (i.e. title bar.) */
if ([event window]) {
NSRect windowRect = [[[event window] contentView] frame];
if (!NSMouseInRect([event locationInWindow], windowRect, NO)) {
return;
}
}
deltaX = [event deltaX];
deltaY = [event deltaY];
if (seenWarp) {
deltaX += (lastMoveX - driverdata->lastWarpX);
deltaY += ((CGDisplayPixelsHigh(kCGDirectMainDisplay) - lastMoveY) - driverdata->lastWarpY);
DLog("Motion was (%g, %g), offset to (%g, %g)", [event deltaX], [event deltaY], deltaX, deltaY);
}
SDL_SendMouseMotion(Cocoa_GetEventTimestamp([event timestamp]), mouse->focus, mouseID, 1, deltaX, deltaY);
}
void Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event)
{
SDL_MouseID mouseID;
SDL_MouseWheelDirection direction;
CGFloat x, y;
SDL_Mouse *mouse = SDL_GetMouse();
if (!mouse) {
return;
}
mouseID = mouse->mouseID;
x = -[event deltaX];
y = [event deltaY];
direction = SDL_MOUSEWHEEL_NORMAL;
if ([event isDirectionInvertedFromDevice] == YES) {
direction = SDL_MOUSEWHEEL_FLIPPED;
}
/* For discrete scroll events from conventional mice, always send a full tick.
For continuous scroll events from trackpads, send fractional deltas for smoother scrolling. */
if (![event hasPreciseScrollingDeltas]) {
if (x > 0) {
x = SDL_ceil(x);
} else if (x < 0) {
x = SDL_floor(x);
}
if (y > 0) {
y = SDL_ceil(y);
} else if (y < 0) {
y = SDL_floor(y);
}
}
SDL_SendMouseWheel(Cocoa_GetEventTimestamp([event timestamp]), window, mouseID, x, y, direction);
}
void Cocoa_HandleMouseWarp(CGFloat x, CGFloat y)
{
/* This makes Cocoa_HandleMouseEvent ignore the delta caused by the warp,
* since it gets included in the next movement event.
*/
SDL_MouseData *driverdata = (SDL_MouseData *)SDL_GetMouse()->driverdata;
driverdata->lastWarpX = x;
driverdata->lastWarpY = y;
driverdata->seenWarp = SDL_TRUE;
DLog("(%g, %g)", x, y);
}
void Cocoa_QuitMouse(SDL_VideoDevice *_this)
{
SDL_Mouse *mouse = SDL_GetMouse();
if (mouse) {
if (mouse->driverdata) {
SDL_free(mouse->driverdata);
mouse->driverdata = NULL;
}
}
}
#endif /* SDL_VIDEO_DRIVER_COCOA */

View File

@ -0,0 +1,89 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_cocoaopengl_h_
#define SDL_cocoaopengl_h_
#ifdef SDL_VIDEO_OPENGL_CGL
#import <Cocoa/Cocoa.h>
#import <QuartzCore/CVDisplayLink.h>
/* We still support OpenGL as long as Apple offers it, deprecated or not, so disable deprecation warnings about it. */
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
struct SDL_GLDriverData
{
int initialized;
};
@interface SDLOpenGLContext : NSOpenGLContext
{
SDL_AtomicInt dirty;
SDL_Window *window;
CVDisplayLinkRef displayLink;
@public
SDL_Mutex *swapIntervalMutex;
@public
SDL_Condition *swapIntervalCond;
@public
SDL_AtomicInt swapIntervalSetting;
@public
SDL_AtomicInt swapIntervalsPassed;
}
- (id)initWithFormat:(NSOpenGLPixelFormat *)format
shareContext:(NSOpenGLContext *)share;
- (void)scheduleUpdate;
- (void)updateIfNeeded;
- (void)movedToNewScreen;
- (void)setWindow:(SDL_Window *)window;
- (SDL_Window *)window;
- (void)explicitUpdate;
- (void)cleanup;
@property(retain, nonatomic) NSOpenGLPixelFormat *openglPixelFormat; // macOS 10.10 has -[NSOpenGLContext pixelFormat] but this handles older OS releases.
@end
/* OpenGL functions */
extern int Cocoa_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path);
extern SDL_FunctionPointer Cocoa_GL_GetProcAddress(SDL_VideoDevice *_this, const char *proc);
extern void Cocoa_GL_UnloadLibrary(SDL_VideoDevice *_this);
extern SDL_GLContext Cocoa_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
extern int Cocoa_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window,
SDL_GLContext context);
extern int Cocoa_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval);
extern int Cocoa_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval);
extern int Cocoa_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int Cocoa_GL_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context);
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif /* SDL_VIDEO_OPENGL_CGL */
#endif /* SDL_cocoaopengl_h_ */

View File

@ -0,0 +1,541 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
/* NSOpenGL implementation of SDL OpenGL support */
#ifdef SDL_VIDEO_OPENGL_CGL
#include "SDL_cocoavideo.h"
#include "SDL_cocoaopengl.h"
#include "SDL_cocoaopengles.h"
#include <OpenGL/CGLTypes.h>
#include <OpenGL/OpenGL.h>
#include <OpenGL/CGLRenderers.h>
#include <SDL3/SDL_opengl.h>
#include "../../SDL_hints_c.h"
#define DEFAULT_OPENGL "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
/* We still support OpenGL as long as Apple offers it, deprecated or not, so disable deprecation warnings about it. */
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
/* _Nullable is available starting Xcode 7 */
#ifdef __has_feature
#if __has_feature(nullability)
#define HAS_FEATURE_NULLABLE
#endif
#endif
#ifndef HAS_FEATURE_NULLABLE
#define _Nullable
#endif
static SDL_bool SDL_opengl_async_dispatch = SDL_FALSE;
static void SDLCALL SDL_OpenGLAsyncDispatchChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
SDL_opengl_async_dispatch = SDL_GetStringBoolean(hint, SDL_FALSE);
}
static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext)
{
SDLOpenGLContext *nscontext = (__bridge SDLOpenGLContext *)displayLinkContext;
/*printf("DISPLAY LINK! %u\n", (unsigned int) SDL_GetTicks()); */
const int setting = SDL_AtomicGet(&nscontext->swapIntervalSetting);
if (setting != 0) { /* nothing to do if vsync is disabled, don't even lock */
SDL_LockMutex(nscontext->swapIntervalMutex);
SDL_AtomicAdd(&nscontext->swapIntervalsPassed, 1);
SDL_SignalCondition(nscontext->swapIntervalCond);
SDL_UnlockMutex(nscontext->swapIntervalMutex);
}
return kCVReturnSuccess;
}
@implementation SDLOpenGLContext : NSOpenGLContext
- (id)initWithFormat:(NSOpenGLPixelFormat *)format
shareContext:(NSOpenGLContext *)share
{
self = [super initWithFormat:format shareContext:share];
if (self) {
self.openglPixelFormat = format;
SDL_AtomicSet(&self->dirty, 0);
self->window = NULL;
SDL_AtomicSet(&self->swapIntervalSetting, 0);
SDL_AtomicSet(&self->swapIntervalsPassed, 0);
self->swapIntervalCond = SDL_CreateCondition();
self->swapIntervalMutex = SDL_CreateMutex();
if (!self->swapIntervalCond || !self->swapIntervalMutex) {
return nil;
}
/* !!! FIXME: check return values. */
CVDisplayLinkCreateWithActiveCGDisplays(&self->displayLink);
CVDisplayLinkSetOutputCallback(self->displayLink, &DisplayLinkCallback, (__bridge void *_Nullable)self);
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(self->displayLink, [self CGLContextObj], [format CGLPixelFormatObj]);
CVDisplayLinkStart(displayLink);
}
SDL_AddHintCallback(SDL_HINT_MAC_OPENGL_ASYNC_DISPATCH, SDL_OpenGLAsyncDispatchChanged, NULL);
return self;
}
- (void)movedToNewScreen
{
if (self->displayLink) {
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(self->displayLink, [self CGLContextObj], [[self openglPixelFormat] CGLPixelFormatObj]);
}
}
- (void)scheduleUpdate
{
SDL_AtomicAdd(&self->dirty, 1);
}
/* This should only be called on the thread on which a user is using the context. */
- (void)updateIfNeeded
{
const int value = SDL_AtomicSet(&self->dirty, 0);
if (value > 0) {
/* We call the real underlying update here, since -[SDLOpenGLContext update] just calls us. */
[self explicitUpdate];
}
}
/* This should only be called on the thread on which a user is using the context. */
- (void)update
{
/* This ensures that regular 'update' calls clear the atomic dirty flag. */
[self scheduleUpdate];
[self updateIfNeeded];
}
/* Updates the drawable for the contexts and manages related state. */
- (void)setWindow:(SDL_Window *)newWindow
{
if (self->window) {
SDL_CocoaWindowData *oldwindowdata = (__bridge SDL_CocoaWindowData *)self->window->driverdata;
/* Make sure to remove us from the old window's context list, or we'll get scheduled updates from it too. */
NSMutableArray *contexts = oldwindowdata.nscontexts;
@synchronized(contexts) {
[contexts removeObject:self];
}
}
self->window = newWindow;
if (newWindow) {
SDL_CocoaWindowData *windowdata = (__bridge SDL_CocoaWindowData *)newWindow->driverdata;
NSView *contentview = windowdata.sdlContentView;
/* Now sign up for scheduled updates for the new window. */
NSMutableArray *contexts = windowdata.nscontexts;
@synchronized(contexts) {
[contexts addObject:self];
}
if ([self view] != contentview) {
if ([NSThread isMainThread]) {
[self setView:contentview];
} else {
dispatch_sync(dispatch_get_main_queue(), ^{
[self setView:contentview];
});
}
if (self == [NSOpenGLContext currentContext]) {
[self explicitUpdate];
} else {
[self scheduleUpdate];
}
}
} else {
if ([NSThread isMainThread]) {
[self setView:nil];
} else {
dispatch_sync(dispatch_get_main_queue(), ^{ [self setView:nil]; });
}
}
}
- (SDL_Window *)window
{
return self->window;
}
- (void)explicitUpdate
{
if ([NSThread isMainThread]) {
[super update];
} else {
if (SDL_opengl_async_dispatch) {
dispatch_async(dispatch_get_main_queue(), ^{
[super update];
});
} else {
dispatch_sync(dispatch_get_main_queue(), ^{
[super update];
});
}
}
}
- (void)cleanup
{
[self setWindow:NULL];
SDL_DelHintCallback(SDL_HINT_MAC_OPENGL_ASYNC_DISPATCH, SDL_OpenGLAsyncDispatchChanged, NULL);
if (self->displayLink) {
CVDisplayLinkRelease(self->displayLink);
self->displayLink = nil;
}
if (self->swapIntervalCond) {
SDL_DestroyCondition(self->swapIntervalCond);
self->swapIntervalCond = NULL;
}
if (self->swapIntervalMutex) {
SDL_DestroyMutex(self->swapIntervalMutex);
self->swapIntervalMutex = NULL;
}
}
@end
int Cocoa_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
/* Load the OpenGL library */
if (path == NULL) {
path = SDL_getenv("SDL_OPENGL_LIBRARY");
}
if (path == NULL) {
path = DEFAULT_OPENGL;
}
_this->gl_config.dll_handle = SDL_LoadObject(path);
if (!_this->gl_config.dll_handle) {
return -1;
}
SDL_strlcpy(_this->gl_config.driver_path, path,
SDL_arraysize(_this->gl_config.driver_path));
return 0;
}
SDL_FunctionPointer Cocoa_GL_GetProcAddress(SDL_VideoDevice *_this, const char *proc)
{
return SDL_LoadFunction(_this->gl_config.dll_handle, proc);
}
void Cocoa_GL_UnloadLibrary(SDL_VideoDevice *_this)
{
SDL_UnloadObject(_this->gl_config.dll_handle);
_this->gl_config.dll_handle = NULL;
}
SDL_GLContext Cocoa_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
{
@autoreleasepool {
SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window);
SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata;
NSOpenGLPixelFormatAttribute attr[32];
NSOpenGLPixelFormat *fmt;
SDLOpenGLContext *context;
SDL_GLContext sdlcontext;
NSOpenGLContext *share_context = nil;
int i = 0;
const char *glversion;
int glversion_major;
int glversion_minor;
NSOpenGLPixelFormatAttribute profile;
int interval;
int opaque;
if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) {
#ifdef SDL_VIDEO_OPENGL_EGL
/* Switch to EGL based functions */
Cocoa_GL_UnloadLibrary(_this);
_this->GL_LoadLibrary = Cocoa_GLES_LoadLibrary;
_this->GL_GetProcAddress = Cocoa_GLES_GetProcAddress;
_this->GL_UnloadLibrary = Cocoa_GLES_UnloadLibrary;
_this->GL_CreateContext = Cocoa_GLES_CreateContext;
_this->GL_MakeCurrent = Cocoa_GLES_MakeCurrent;
_this->GL_SetSwapInterval = Cocoa_GLES_SetSwapInterval;
_this->GL_GetSwapInterval = Cocoa_GLES_GetSwapInterval;
_this->GL_SwapWindow = Cocoa_GLES_SwapWindow;
_this->GL_DeleteContext = Cocoa_GLES_DeleteContext;
if (Cocoa_GLES_LoadLibrary(_this, NULL) != 0) {
return NULL;
}
return Cocoa_GLES_CreateContext(_this, window);
#else
SDL_SetError("SDL not configured with EGL support");
return NULL;
#endif
}
attr[i++] = NSOpenGLPFAAllowOfflineRenderers;
profile = NSOpenGLProfileVersionLegacy;
if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_CORE) {
profile = NSOpenGLProfileVersion3_2Core;
}
attr[i++] = NSOpenGLPFAOpenGLProfile;
attr[i++] = profile;
attr[i++] = NSOpenGLPFAColorSize;
attr[i++] = SDL_BYTESPERPIXEL(display->current_mode->format) * 8;
attr[i++] = NSOpenGLPFADepthSize;
attr[i++] = _this->gl_config.depth_size;
if (_this->gl_config.double_buffer) {
attr[i++] = NSOpenGLPFADoubleBuffer;
}
if (_this->gl_config.stereo) {
attr[i++] = NSOpenGLPFAStereo;
}
if (_this->gl_config.stencil_size) {
attr[i++] = NSOpenGLPFAStencilSize;
attr[i++] = _this->gl_config.stencil_size;
}
if ((_this->gl_config.accum_red_size +
_this->gl_config.accum_green_size +
_this->gl_config.accum_blue_size +
_this->gl_config.accum_alpha_size) > 0) {
attr[i++] = NSOpenGLPFAAccumSize;
attr[i++] = _this->gl_config.accum_red_size + _this->gl_config.accum_green_size + _this->gl_config.accum_blue_size + _this->gl_config.accum_alpha_size;
}
if (_this->gl_config.multisamplebuffers) {
attr[i++] = NSOpenGLPFASampleBuffers;
attr[i++] = _this->gl_config.multisamplebuffers;
}
if (_this->gl_config.multisamplesamples) {
attr[i++] = NSOpenGLPFASamples;
attr[i++] = _this->gl_config.multisamplesamples;
attr[i++] = NSOpenGLPFANoRecovery;
}
if (_this->gl_config.floatbuffers) {
attr[i++] = NSOpenGLPFAColorFloat;
}
if (_this->gl_config.accelerated >= 0) {
if (_this->gl_config.accelerated) {
attr[i++] = NSOpenGLPFAAccelerated;
} else {
attr[i++] = NSOpenGLPFARendererID;
attr[i++] = kCGLRendererGenericFloatID;
}
}
attr[i++] = NSOpenGLPFAScreenMask;
attr[i++] = CGDisplayIDToOpenGLDisplayMask(displaydata->display);
attr[i] = 0;
fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
if (fmt == nil) {
SDL_SetError("Failed creating OpenGL pixel format");
return NULL;
}
if (_this->gl_config.share_with_current_context) {
share_context = (__bridge NSOpenGLContext *)SDL_GL_GetCurrentContext();
}
context = [[SDLOpenGLContext alloc] initWithFormat:fmt shareContext:share_context];
if (context == nil) {
SDL_SetError("Failed creating OpenGL context");
return NULL;
}
sdlcontext = (SDL_GLContext)CFBridgingRetain(context);
/* vsync is handled separately by synchronizing with a display link. */
interval = 0;
[context setValues:&interval forParameter:NSOpenGLCPSwapInterval];
opaque = (window->flags & SDL_WINDOW_TRANSPARENT) ? 0 : 1;
[context setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
if (Cocoa_GL_MakeCurrent(_this, window, sdlcontext) < 0) {
SDL_GL_DeleteContext(sdlcontext);
SDL_SetError("Failed making OpenGL context current");
return NULL;
}
if (_this->gl_config.major_version < 3 &&
_this->gl_config.profile_mask == 0 &&
_this->gl_config.flags == 0) {
/* This is a legacy profile, so to match other backends, we're done. */
} else {
const GLubyte *(APIENTRY * glGetStringFunc)(GLenum);
glGetStringFunc = (const GLubyte *(APIENTRY *)(GLenum))SDL_GL_GetProcAddress("glGetString");
if (!glGetStringFunc) {
SDL_GL_DeleteContext(sdlcontext);
SDL_SetError("Failed getting OpenGL glGetString entry point");
return NULL;
}
glversion = (const char *)glGetStringFunc(GL_VERSION);
if (glversion == NULL) {
SDL_GL_DeleteContext(sdlcontext);
SDL_SetError("Failed getting OpenGL context version");
return NULL;
}
if (SDL_sscanf(glversion, "%d.%d", &glversion_major, &glversion_minor) != 2) {
SDL_GL_DeleteContext(sdlcontext);
SDL_SetError("Failed parsing OpenGL context version");
return NULL;
}
if ((glversion_major < _this->gl_config.major_version) ||
((glversion_major == _this->gl_config.major_version) && (glversion_minor < _this->gl_config.minor_version))) {
SDL_GL_DeleteContext(sdlcontext);
SDL_SetError("Failed creating OpenGL context at version requested");
return NULL;
}
/* In the future we'll want to do this, but to match other platforms
we'll leave the OpenGL version the way it is for now
*/
/*_this->gl_config.major_version = glversion_major;*/
/*_this->gl_config.minor_version = glversion_minor;*/
}
return sdlcontext;
}
}
int Cocoa_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context)
{
@autoreleasepool {
if (context) {
SDLOpenGLContext *nscontext = (__bridge SDLOpenGLContext *)context;
if ([nscontext window] != window) {
[nscontext setWindow:window];
[nscontext updateIfNeeded];
}
[nscontext makeCurrentContext];
} else {
[NSOpenGLContext clearCurrentContext];
}
return 0;
}
}
int Cocoa_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval)
{
@autoreleasepool {
SDLOpenGLContext *nscontext = (__bridge SDLOpenGLContext *)SDL_GL_GetCurrentContext();
int status;
if (nscontext == nil) {
status = SDL_SetError("No current OpenGL context");
} else {
SDL_LockMutex(nscontext->swapIntervalMutex);
SDL_AtomicSet(&nscontext->swapIntervalsPassed, 0);
SDL_AtomicSet(&nscontext->swapIntervalSetting, interval);
SDL_UnlockMutex(nscontext->swapIntervalMutex);
status = 0;
}
return status;
}
}
int Cocoa_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval)
{
@autoreleasepool {
SDLOpenGLContext *nscontext = (__bridge SDLOpenGLContext *)SDL_GL_GetCurrentContext();
if (nscontext) {
*interval = SDL_AtomicGet(&nscontext->swapIntervalSetting);
return 0;
} else {
return SDL_SetError("no OpenGL context");
}
}
}
int Cocoa_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
@autoreleasepool {
SDLOpenGLContext *nscontext = (__bridge SDLOpenGLContext *)SDL_GL_GetCurrentContext();
SDL_CocoaVideoData *videodata = (__bridge SDL_CocoaVideoData *)_this->driverdata;
const int setting = SDL_AtomicGet(&nscontext->swapIntervalSetting);
if (setting == 0) {
/* nothing to do if vsync is disabled, don't even lock */
} else if (setting < 0) { /* late swap tearing */
SDL_LockMutex(nscontext->swapIntervalMutex);
while (SDL_AtomicGet(&nscontext->swapIntervalsPassed) == 0) {
SDL_WaitCondition(nscontext->swapIntervalCond, nscontext->swapIntervalMutex);
}
SDL_AtomicSet(&nscontext->swapIntervalsPassed, 0);
SDL_UnlockMutex(nscontext->swapIntervalMutex);
} else {
SDL_LockMutex(nscontext->swapIntervalMutex);
do { /* always wait here so we know we just hit a swap interval. */
SDL_WaitCondition(nscontext->swapIntervalCond, nscontext->swapIntervalMutex);
} while ((SDL_AtomicGet(&nscontext->swapIntervalsPassed) % setting) != 0);
SDL_AtomicSet(&nscontext->swapIntervalsPassed, 0);
SDL_UnlockMutex(nscontext->swapIntervalMutex);
}
/*{ static Uint64 prev = 0; const Uint64 now = SDL_GetTicks(); const unsigned int diff = (unsigned int) (now - prev); prev = now; printf("GLSWAPBUFFERS TICKS %u\n", diff); }*/
/* on 10.14 ("Mojave") and later, this deadlocks if two contexts in two
threads try to swap at the same time, so put a mutex around it. */
SDL_LockMutex(videodata.swaplock);
[nscontext flushBuffer];
[nscontext updateIfNeeded];
SDL_UnlockMutex(videodata.swaplock);
return 0;
}
}
int Cocoa_GL_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context)
{
@autoreleasepool {
SDLOpenGLContext *nscontext = (__bridge SDLOpenGLContext *)context;
[nscontext cleanup];
CFRelease(context);
}
return 0;
}
/* We still support OpenGL as long as Apple offers it, deprecated or not, so disable deprecation warnings about it. */
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif /* SDL_VIDEO_OPENGL_CGL */

View File

@ -0,0 +1,48 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_cocoaopengles_h_
#define SDL_cocoaopengles_h_
#ifdef SDL_VIDEO_OPENGL_EGL
#include "../SDL_sysvideo.h"
#include "../SDL_egl_c.h"
/* OpenGLES functions */
#define Cocoa_GLES_GetAttribute SDL_EGL_GetAttribute
#define Cocoa_GLES_GetProcAddress SDL_EGL_GetProcAddressInternal
#define Cocoa_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
#define Cocoa_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
#define Cocoa_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
extern int Cocoa_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path);
extern SDL_GLContext Cocoa_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
extern int Cocoa_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int Cocoa_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
extern int Cocoa_GLES_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context);
extern int Cocoa_GLES_SetupWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern SDL_EGLSurface Cocoa_GLES_GetEGLSurface(SDL_VideoDevice *_this, SDL_Window *window);
#endif /* SDL_VIDEO_OPENGL_EGL */
#endif /* SDL_cocoaopengles_h_ */

View File

@ -0,0 +1,156 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_DRIVER_COCOA) && defined(SDL_VIDEO_OPENGL_EGL)
#include "SDL_cocoavideo.h"
#include "SDL_cocoaopengles.h"
#include "SDL_cocoaopengl.h"
/* EGL implementation of SDL OpenGL support */
int Cocoa_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
/* If the profile requested is not GL ES, switch over to WIN_GL functions */
if (_this->gl_config.profile_mask != SDL_GL_CONTEXT_PROFILE_ES) {
#ifdef SDL_VIDEO_OPENGL_CGL
Cocoa_GLES_UnloadLibrary(_this);
_this->GL_LoadLibrary = Cocoa_GL_LoadLibrary;
_this->GL_GetProcAddress = Cocoa_GL_GetProcAddress;
_this->GL_UnloadLibrary = Cocoa_GL_UnloadLibrary;
_this->GL_CreateContext = Cocoa_GL_CreateContext;
_this->GL_MakeCurrent = Cocoa_GL_MakeCurrent;
_this->GL_SetSwapInterval = Cocoa_GL_SetSwapInterval;
_this->GL_GetSwapInterval = Cocoa_GL_GetSwapInterval;
_this->GL_SwapWindow = Cocoa_GL_SwapWindow;
_this->GL_DeleteContext = Cocoa_GL_DeleteContext;
_this->GL_GetEGLSurface = NULL;
return Cocoa_GL_LoadLibrary(_this, path);
#else
return SDL_SetError("SDL not configured with OpenGL/CGL support");
#endif
}
if (_this->egl_data == NULL) {
return SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, _this->gl_config.egl_platform);
}
return 0;
}
SDL_GLContext Cocoa_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
{
@autoreleasepool {
SDL_GLContext context;
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->driverdata;
#ifdef SDL_VIDEO_OPENGL_CGL
if (_this->gl_config.profile_mask != SDL_GL_CONTEXT_PROFILE_ES) {
/* Switch to CGL based functions */
Cocoa_GLES_UnloadLibrary(_this);
_this->GL_LoadLibrary = Cocoa_GL_LoadLibrary;
_this->GL_GetProcAddress = Cocoa_GL_GetProcAddress;
_this->GL_UnloadLibrary = Cocoa_GL_UnloadLibrary;
_this->GL_CreateContext = Cocoa_GL_CreateContext;
_this->GL_MakeCurrent = Cocoa_GL_MakeCurrent;
_this->GL_SetSwapInterval = Cocoa_GL_SetSwapInterval;
_this->GL_GetSwapInterval = Cocoa_GL_GetSwapInterval;
_this->GL_SwapWindow = Cocoa_GL_SwapWindow;
_this->GL_DeleteContext = Cocoa_GL_DeleteContext;
_this->GL_GetEGLSurface = NULL;
if (Cocoa_GL_LoadLibrary(_this, NULL) != 0) {
return NULL;
}
return Cocoa_GL_CreateContext(_this, window);
}
#endif
context = SDL_EGL_CreateContext(_this, data.egl_surface);
return context;
}
}
int Cocoa_GLES_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context)
{
@autoreleasepool {
SDL_EGL_DeleteContext(_this, context);
}
return 0;
}
int Cocoa_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
@autoreleasepool {
return SDL_EGL_SwapBuffers(_this, ((__bridge SDL_CocoaWindowData *)window->driverdata).egl_surface);
}
}
int Cocoa_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context)
{
@autoreleasepool {
return SDL_EGL_MakeCurrent(_this, window ? ((__bridge SDL_CocoaWindowData *)window->driverdata).egl_surface : EGL_NO_SURFACE, context);
}
}
int Cocoa_GLES_SetupWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
@autoreleasepool {
NSView *v;
/* The current context is lost in here; save it and reset it. */
SDL_CocoaWindowData *windowdata = (__bridge SDL_CocoaWindowData *)window->driverdata;
SDL_Window *current_win = SDL_GL_GetCurrentWindow();
SDL_GLContext current_ctx = SDL_GL_GetCurrentContext();
if (_this->egl_data == NULL) {
/* !!! FIXME: commenting out this assertion is (I think) incorrect; figure out why driver_loaded is wrong for ANGLE instead. --ryan. */
#if 0 /* When hint SDL_HINT_OPENGL_ES_DRIVER is set to "1" (e.g. for ANGLE support), _this->gl_config.driver_loaded can be 1, while the below lines function. */
SDL_assert(!_this->gl_config.driver_loaded);
#endif
if (SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY, _this->gl_config.egl_platform) < 0) {
SDL_EGL_UnloadLibrary(_this);
return -1;
}
_this->gl_config.driver_loaded = 1;
}
/* Create the GLES window surface */
v = windowdata.nswindow.contentView;
windowdata.egl_surface = SDL_EGL_CreateSurface(_this, window, (__bridge NativeWindowType)[v layer]);
if (windowdata.egl_surface == EGL_NO_SURFACE) {
return SDL_SetError("Could not create GLES window surface");
}
return Cocoa_GLES_MakeCurrent(_this, current_win, current_ctx);
}
}
SDL_EGLSurface Cocoa_GLES_GetEGLSurface(SDL_VideoDevice *_this, SDL_Window *window)
{
@autoreleasepool {
return ((__bridge SDL_CocoaWindowData *)window->driverdata).egl_surface;
}
}
#endif /* SDL_VIDEO_DRIVER_COCOA && SDL_VIDEO_OPENGL_EGL */

View File

@ -0,0 +1,38 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_cocoashape_h_
#define SDL_cocoashape_h_
#include "../SDL_shape_internals.h"
@interface SDL_ShapeData : NSObject
@property(nonatomic) NSGraphicsContext *context;
@property(nonatomic) SDL_bool saved;
@property(nonatomic) SDL_ShapeTree *shape;
@end
extern SDL_WindowShaper *Cocoa_CreateShaper(SDL_Window *window);
extern int Cocoa_SetWindowShape(SDL_WindowShaper *shaper, SDL_Surface *shape, SDL_WindowShapeMode *shape_mode);
#endif /* SDL_cocoashape_h_ */

View File

@ -0,0 +1,115 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_COCOA
#include "SDL_cocoavideo.h"
#include "SDL_cocoashape.h"
#include "../SDL_sysvideo.h"
@implementation SDL_ShapeData
@end
@interface SDL_CocoaClosure : NSObject
@property(nonatomic) NSView *view;
@property(nonatomic) NSBezierPath *path;
@property(nonatomic) SDL_Window *window;
@end
@implementation SDL_CocoaClosure
@end
SDL_WindowShaper *Cocoa_CreateShaper(SDL_Window *window)
{
@autoreleasepool {
SDL_WindowShaper *result;
SDL_ShapeData *data;
SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)window->driverdata;
result = (SDL_WindowShaper *)SDL_malloc(sizeof(SDL_WindowShaper));
if (!result) {
SDL_OutOfMemory();
return NULL;
}
[windata.nswindow setOpaque:NO];
[windata.nswindow setStyleMask:NSWindowStyleMaskBorderless];
result->window = window;
result->mode.mode = ShapeModeDefault;
result->mode.parameters.binarizationCutoff = 1;
window->shaper = result;
data = [[SDL_ShapeData alloc] init];
data.context = [windata.nswindow graphicsContext];
data.saved = SDL_FALSE;
data.shape = NULL;
/* TODO: There's no place to release this... */
result->driverdata = (void *)CFBridgingRetain(data);
return result;
}
}
void ConvertRects(SDL_ShapeTree *tree, void *closure)
{
SDL_CocoaClosure *data = (__bridge SDL_CocoaClosure *)closure;
if (tree->kind == OpaqueShape) {
NSRect rect = NSMakeRect(tree->data.shape.x, data.window->h - tree->data.shape.y, tree->data.shape.w, tree->data.shape.h);
[data.path appendBezierPathWithRect:[data.view convertRect:rect toView:nil]];
}
}
int Cocoa_SetWindowShape(SDL_WindowShaper *shaper, SDL_Surface *shape, SDL_WindowShapeMode *shape_mode)
{
@autoreleasepool {
SDL_ShapeData *data = (__bridge SDL_ShapeData *)shaper->driverdata;
SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)shaper->window->driverdata;
SDL_CocoaClosure *closure;
if (data.saved == SDL_TRUE) {
[data.context restoreGraphicsState];
data.saved = SDL_FALSE;
}
/*[data.context saveGraphicsState];*/
/*data.saved = SDL_TRUE;*/
[NSGraphicsContext setCurrentContext:data.context];
[[NSColor clearColor] set];
NSRectFill([windata.sdlContentView frame]);
data.shape = SDL_CalculateShapeTree(*shape_mode, shape);
closure = [[SDL_CocoaClosure alloc] init];
closure.view = windata.sdlContentView;
closure.path = [NSBezierPath bezierPath];
closure.window = shaper->window;
SDL_TraverseShapeTree(data.shape, &ConvertRects, (__bridge void *)closure);
[closure.path addClip];
return 0;
}
}
#endif /* SDL_VIDEO_DRIVER_COCOA */

View File

@ -0,0 +1,119 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_cocoavideo_h_
#define SDL_cocoavideo_h_
#include <SDL3/SDL_opengl.h>
#include <ApplicationServices/ApplicationServices.h>
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <Cocoa/Cocoa.h>
#include "../SDL_sysvideo.h"
#include "SDL_cocoaclipboard.h"
#include "SDL_cocoaevents.h"
#include "SDL_cocoakeyboard.h"
#include "SDL_cocoamodes.h"
#include "SDL_cocoamouse.h"
#include "SDL_cocoaopengl.h"
#include "SDL_cocoawindow.h"
#ifndef MAC_OS_X_VERSION_10_12
#define DECLARE_EVENT(name) static const NSEventType NSEventType##name = NS##name
DECLARE_EVENT(LeftMouseDown);
DECLARE_EVENT(LeftMouseUp);
DECLARE_EVENT(RightMouseDown);
DECLARE_EVENT(RightMouseUp);
DECLARE_EVENT(OtherMouseDown);
DECLARE_EVENT(OtherMouseUp);
DECLARE_EVENT(MouseMoved);
DECLARE_EVENT(LeftMouseDragged);
DECLARE_EVENT(RightMouseDragged);
DECLARE_EVENT(OtherMouseDragged);
DECLARE_EVENT(ScrollWheel);
DECLARE_EVENT(KeyDown);
DECLARE_EVENT(KeyUp);
DECLARE_EVENT(FlagsChanged);
#undef DECLARE_EVENT
static const NSEventMask NSEventMaskAny = NSAnyEventMask;
#define DECLARE_MODIFIER_FLAG(name) static const NSUInteger NSEventModifierFlag##name = NS##name##KeyMask
DECLARE_MODIFIER_FLAG(Shift);
DECLARE_MODIFIER_FLAG(Control);
DECLARE_MODIFIER_FLAG(Command);
DECLARE_MODIFIER_FLAG(NumericPad);
DECLARE_MODIFIER_FLAG(Help);
DECLARE_MODIFIER_FLAG(Function);
#undef DECLARE_MODIFIER_FLAG
static const NSUInteger NSEventModifierFlagCapsLock = NSAlphaShiftKeyMask;
static const NSUInteger NSEventModifierFlagOption = NSAlternateKeyMask;
#define DECLARE_WINDOW_MASK(name) static const unsigned int NSWindowStyleMask##name = NS##name##WindowMask
DECLARE_WINDOW_MASK(Borderless);
DECLARE_WINDOW_MASK(Titled);
DECLARE_WINDOW_MASK(Closable);
DECLARE_WINDOW_MASK(Miniaturizable);
DECLARE_WINDOW_MASK(Resizable);
DECLARE_WINDOW_MASK(TexturedBackground);
DECLARE_WINDOW_MASK(UnifiedTitleAndToolbar);
DECLARE_WINDOW_MASK(FullScreen);
/*DECLARE_WINDOW_MASK(FullSizeContentView);*/ /* Not used, fails compile on older SDKs */
static const unsigned int NSWindowStyleMaskUtilityWindow = NSUtilityWindowMask;
static const unsigned int NSWindowStyleMaskDocModalWindow = NSDocModalWindowMask;
static const unsigned int NSWindowStyleMaskHUDWindow = NSHUDWindowMask;
#undef DECLARE_WINDOW_MASK
#define DECLARE_ALERT_STYLE(name) static const NSUInteger NSAlertStyle##name = NS##name##AlertStyle
DECLARE_ALERT_STYLE(Warning);
DECLARE_ALERT_STYLE(Informational);
DECLARE_ALERT_STYLE(Critical);
#undef DECLARE_ALERT_STYLE
#endif
/* Private display data */
@class SDLTranslatorResponder;
@interface SDL_CocoaVideoData : NSObject
@property(nonatomic) int allow_spaces;
@property(nonatomic) int trackpad_is_touch_only;
@property(nonatomic) unsigned int modifierFlags;
@property(nonatomic) void *key_layout;
@property(nonatomic) SDLTranslatorResponder *fieldEdit;
@property(nonatomic) NSInteger clipboard_count;
@property(nonatomic) IOPMAssertionID screensaver_assertion;
@property(nonatomic) SDL_Mutex *swaplock;
@end
/* Utility functions */
extern SDL_SystemTheme Cocoa_GetSystemTheme(void);
extern NSImage *Cocoa_CreateImage(SDL_Surface *surface);
/* Fix build with the 10.11 SDK */
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
#define NSEventSubtypeMouseEvent NSMouseEventSubtype
#endif
#endif /* SDL_cocoavideo_h_ */

View File

@ -0,0 +1,314 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_COCOA
#if !__has_feature(objc_arc)
#error SDL must be built with Objective-C ARC (automatic reference counting) enabled
#endif
#include "SDL_cocoavideo.h"
#include "SDL_cocoashape.h"
#include "SDL_cocoavulkan.h"
#include "SDL_cocoametalview.h"
#include "SDL_cocoaopengles.h"
@implementation SDL_CocoaVideoData
@end
/* Initialization/Query functions */
static int Cocoa_VideoInit(SDL_VideoDevice *_this);
static void Cocoa_VideoQuit(SDL_VideoDevice *_this);
/* Cocoa driver bootstrap functions */
static void Cocoa_DeleteDevice(SDL_VideoDevice *device)
{
@autoreleasepool {
if (device->wakeup_lock) {
SDL_DestroyMutex(device->wakeup_lock);
}
CFBridgingRelease(device->driverdata);
SDL_free(device);
}
}
static SDL_VideoDevice *Cocoa_CreateDevice(void)
{
@autoreleasepool {
SDL_VideoDevice *device;
SDL_CocoaVideoData *data;
Cocoa_RegisterApp();
/* Initialize all variables that we clean on shutdown */
device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
if (device) {
data = [[SDL_CocoaVideoData alloc] init];
} else {
data = nil;
}
if (!data) {
SDL_OutOfMemory();
SDL_free(device);
return NULL;
}
device->driverdata = (SDL_VideoData *)CFBridgingRetain(data);
device->wakeup_lock = SDL_CreateMutex();
device->system_theme = Cocoa_GetSystemTheme();
/* Set the function pointers */
device->VideoInit = Cocoa_VideoInit;
device->VideoQuit = Cocoa_VideoQuit;
device->GetDisplayBounds = Cocoa_GetDisplayBounds;
device->GetDisplayUsableBounds = Cocoa_GetDisplayUsableBounds;
device->GetDisplayModes = Cocoa_GetDisplayModes;
device->SetDisplayMode = Cocoa_SetDisplayMode;
device->PumpEvents = Cocoa_PumpEvents;
device->WaitEventTimeout = Cocoa_WaitEventTimeout;
device->SendWakeupEvent = Cocoa_SendWakeupEvent;
device->SuspendScreenSaver = Cocoa_SuspendScreenSaver;
device->CreateSDLWindow = Cocoa_CreateWindow;
device->CreateSDLWindowFrom = Cocoa_CreateWindowFrom;
device->SetWindowTitle = Cocoa_SetWindowTitle;
device->SetWindowIcon = Cocoa_SetWindowIcon;
device->SetWindowPosition = Cocoa_SetWindowPosition;
device->SetWindowSize = Cocoa_SetWindowSize;
device->SetWindowMinimumSize = Cocoa_SetWindowMinimumSize;
device->SetWindowMaximumSize = Cocoa_SetWindowMaximumSize;
device->SetWindowOpacity = Cocoa_SetWindowOpacity;
device->GetWindowSizeInPixels = Cocoa_GetWindowSizeInPixels;
device->ShowWindow = Cocoa_ShowWindow;
device->HideWindow = Cocoa_HideWindow;
device->RaiseWindow = Cocoa_RaiseWindow;
device->MaximizeWindow = Cocoa_MaximizeWindow;
device->MinimizeWindow = Cocoa_MinimizeWindow;
device->RestoreWindow = Cocoa_RestoreWindow;
device->SetWindowBordered = Cocoa_SetWindowBordered;
device->SetWindowResizable = Cocoa_SetWindowResizable;
device->SetWindowAlwaysOnTop = Cocoa_SetWindowAlwaysOnTop;
device->SetWindowFullscreen = Cocoa_SetWindowFullscreen;
device->GetWindowICCProfile = Cocoa_GetWindowICCProfile;
device->GetDisplayForWindow = Cocoa_GetDisplayForWindow;
device->SetWindowMouseRect = Cocoa_SetWindowMouseRect;
device->SetWindowMouseGrab = Cocoa_SetWindowMouseGrab;
device->SetWindowKeyboardGrab = Cocoa_SetWindowKeyboardGrab;
device->DestroyWindow = Cocoa_DestroyWindow;
device->GetWindowWMInfo = Cocoa_GetWindowWMInfo;
device->SetWindowHitTest = Cocoa_SetWindowHitTest;
device->AcceptDragAndDrop = Cocoa_AcceptDragAndDrop;
device->FlashWindow = Cocoa_FlashWindow;
device->shape_driver.CreateShaper = Cocoa_CreateShaper;
device->shape_driver.SetWindowShape = Cocoa_SetWindowShape;
#ifdef SDL_VIDEO_OPENGL_CGL
device->GL_LoadLibrary = Cocoa_GL_LoadLibrary;
device->GL_GetProcAddress = Cocoa_GL_GetProcAddress;
device->GL_UnloadLibrary = Cocoa_GL_UnloadLibrary;
device->GL_CreateContext = Cocoa_GL_CreateContext;
device->GL_MakeCurrent = Cocoa_GL_MakeCurrent;
device->GL_SetSwapInterval = Cocoa_GL_SetSwapInterval;
device->GL_GetSwapInterval = Cocoa_GL_GetSwapInterval;
device->GL_SwapWindow = Cocoa_GL_SwapWindow;
device->GL_DeleteContext = Cocoa_GL_DeleteContext;
device->GL_GetEGLSurface = NULL;
#endif
#ifdef SDL_VIDEO_OPENGL_EGL
#ifdef SDL_VIDEO_OPENGL_CGL
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, SDL_FALSE)) {
#endif
device->GL_LoadLibrary = Cocoa_GLES_LoadLibrary;
device->GL_GetProcAddress = Cocoa_GLES_GetProcAddress;
device->GL_UnloadLibrary = Cocoa_GLES_UnloadLibrary;
device->GL_CreateContext = Cocoa_GLES_CreateContext;
device->GL_MakeCurrent = Cocoa_GLES_MakeCurrent;
device->GL_SetSwapInterval = Cocoa_GLES_SetSwapInterval;
device->GL_GetSwapInterval = Cocoa_GLES_GetSwapInterval;
device->GL_SwapWindow = Cocoa_GLES_SwapWindow;
device->GL_DeleteContext = Cocoa_GLES_DeleteContext;
device->GL_GetEGLSurface = Cocoa_GLES_GetEGLSurface;
#ifdef SDL_VIDEO_OPENGL_CGL
}
#endif
#endif
#ifdef SDL_VIDEO_VULKAN
device->Vulkan_LoadLibrary = Cocoa_Vulkan_LoadLibrary;
device->Vulkan_UnloadLibrary = Cocoa_Vulkan_UnloadLibrary;
device->Vulkan_GetInstanceExtensions = Cocoa_Vulkan_GetInstanceExtensions;
device->Vulkan_CreateSurface = Cocoa_Vulkan_CreateSurface;
#endif
#ifdef SDL_VIDEO_METAL
device->Metal_CreateView = Cocoa_Metal_CreateView;
device->Metal_DestroyView = Cocoa_Metal_DestroyView;
device->Metal_GetLayer = Cocoa_Metal_GetLayer;
#endif
device->StartTextInput = Cocoa_StartTextInput;
device->StopTextInput = Cocoa_StopTextInput;
device->SetTextInputRect = Cocoa_SetTextInputRect;
device->SetClipboardData = Cocoa_SetClipboardData;
device->GetClipboardData = Cocoa_GetClipboardData;
device->HasClipboardData = Cocoa_HasClipboardData;
device->free = Cocoa_DeleteDevice;
device->quirk_flags = VIDEO_DEVICE_QUIRK_HAS_POPUP_WINDOW_SUPPORT;
return device;
}
}
VideoBootStrap COCOA_bootstrap = {
"cocoa", "SDL Cocoa video driver",
Cocoa_CreateDevice
};
int Cocoa_VideoInit(SDL_VideoDevice *_this)
{
@autoreleasepool {
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
Cocoa_InitModes(_this);
Cocoa_InitKeyboard(_this);
if (Cocoa_InitMouse(_this) < 0) {
return -1;
}
data.allow_spaces = SDL_GetHintBoolean(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, SDL_TRUE);
data.trackpad_is_touch_only = SDL_GetHintBoolean(SDL_HINT_TRACKPAD_IS_TOUCH_ONLY, SDL_FALSE);
data.swaplock = SDL_CreateMutex();
if (!data.swaplock) {
return -1;
}
return 0;
}
}
void Cocoa_VideoQuit(SDL_VideoDevice *_this)
{
@autoreleasepool {
SDL_CocoaVideoData *data = (__bridge SDL_CocoaVideoData *)_this->driverdata;
Cocoa_QuitModes(_this);
Cocoa_QuitKeyboard(_this);
Cocoa_QuitMouse(_this);
SDL_DestroyMutex(data.swaplock);
data.swaplock = NULL;
}
}
/* This function assumes that it's called from within an autorelease pool */
SDL_SystemTheme Cocoa_GetSystemTheme(void)
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400 /* Added in the 10.14.0 SDK. */
if ([[NSApplication sharedApplication] respondsToSelector:@selector(effectiveAppearance)]) {
NSAppearance* appearance = [[NSApplication sharedApplication] effectiveAppearance];
if ([appearance.name containsString: @"Dark"]) {
return SDL_SYSTEM_THEME_DARK;
}
}
#endif
return SDL_SYSTEM_THEME_LIGHT;
}
/* This function assumes that it's called from within an autorelease pool */
NSImage *Cocoa_CreateImage(SDL_Surface *surface)
{
SDL_Surface *converted;
NSBitmapImageRep *imgrep;
Uint8 *pixels;
int i;
NSImage *img;
converted = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_RGBA32);
if (!converted) {
return nil;
}
imgrep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:converted->w
pixelsHigh:converted->h
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:converted->pitch
bitsPerPixel:converted->format->BitsPerPixel];
if (imgrep == nil) {
SDL_DestroySurface(converted);
return nil;
}
/* Copy the pixels */
pixels = [imgrep bitmapData];
SDL_memcpy(pixels, converted->pixels, (size_t)converted->h * converted->pitch);
SDL_DestroySurface(converted);
/* Premultiply the alpha channel */
for (i = (surface->h * surface->w); i--;) {
Uint8 alpha = pixels[3];
pixels[0] = (Uint8)(((Uint16)pixels[0] * alpha) / 255);
pixels[1] = (Uint8)(((Uint16)pixels[1] * alpha) / 255);
pixels[2] = (Uint8)(((Uint16)pixels[2] * alpha) / 255);
pixels += 4;
}
img = [[NSImage alloc] initWithSize:NSMakeSize(surface->w, surface->h)];
if (img != nil) {
[img addRepresentation:imgrep];
}
return img;
}
/*
* macOS log support.
*
* This doesn't really have anything to do with the interfaces of the SDL video
* subsystem, but we need to stuff this into an Objective-C source code file.
*
* NOTE: This is copypasted in src/video/uikit/SDL_uikitvideo.m! Be sure both
* versions remain identical!
*/
void SDL_NSLog(const char *prefix, const char *text)
{
@autoreleasepool {
NSString *nsText = [NSString stringWithUTF8String:text];
if (prefix) {
NSString *nsPrefix = [NSString stringWithUTF8String:prefix];
NSLog(@"%@: %@", nsPrefix, nsText);
} else {
NSLog(@"%@", nsText);
}
}
}
#endif /* SDL_VIDEO_DRIVER_COCOA */

View File

@ -0,0 +1,49 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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.
*/
/*
* @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's
* SDL_x11vulkan.h.
*/
#include "SDL_internal.h"
#ifndef SDL_cocoavulkan_h_
#define SDL_cocoavulkan_h_
#include "../SDL_vulkan_internal.h"
#include "../SDL_sysvideo.h"
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_COCOA)
int Cocoa_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
void Cocoa_Vulkan_UnloadLibrary(SDL_VideoDevice *_this);
SDL_bool Cocoa_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
unsigned *count,
const char **names);
SDL_bool Cocoa_Vulkan_CreateSurface(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
VkSurfaceKHR *surface);
#endif
#endif /* SDL_cocoavulkan_h_ */

View File

@ -0,0 +1,304 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 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.
*/
/*
* @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's
* SDL_x11vulkan.c.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_COCOA)
#include "SDL_cocoavideo.h"
#include "SDL_cocoawindow.h"
#include "SDL_cocoametalview.h"
#include "SDL_cocoavulkan.h"
#include <SDL3/SDL_syswm.h>
#include <dlfcn.h>
const char *defaultPaths[] = {
"vulkan.framework/vulkan",
"libvulkan.1.dylib",
"libvulkan.dylib",
"MoltenVK.framework/MoltenVK",
"libMoltenVK.dylib"
};
/* Since libSDL is most likely a .dylib, need RTLD_DEFAULT not RTLD_SELF. */
#define DEFAULT_HANDLE RTLD_DEFAULT
int Cocoa_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
VkExtensionProperties *extensions = NULL;
Uint32 extensionCount = 0;
SDL_bool hasSurfaceExtension = SDL_FALSE;
SDL_bool hasMetalSurfaceExtension = SDL_FALSE;
SDL_bool hasMacOSSurfaceExtension = SDL_FALSE;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
if (_this->vulkan_config.loader_handle) {
return SDL_SetError("Vulkan Portability library is already loaded.");
}
/* Load the Vulkan loader library */
if (!path) {
path = SDL_getenv("SDL_VULKAN_LIBRARY");
}
if (!path) {
/* Handle the case where Vulkan Portability is linked statically. */
vkGetInstanceProcAddr =
(PFN_vkGetInstanceProcAddr)dlsym(DEFAULT_HANDLE,
"vkGetInstanceProcAddr");
}
if (vkGetInstanceProcAddr) {
_this->vulkan_config.loader_handle = DEFAULT_HANDLE;
} else {
const char **paths;
const char *foundPath = NULL;
int numPaths;
int i;
if (path) {
paths = &path;
numPaths = 1;
} else {
/* Look for framework or .dylib packaged with the application
* instead. */
paths = defaultPaths;
numPaths = SDL_arraysize(defaultPaths);
}
for (i = 0; i < numPaths && _this->vulkan_config.loader_handle == NULL; i++) {
foundPath = paths[i];
_this->vulkan_config.loader_handle = SDL_LoadObject(foundPath);
}
if (_this->vulkan_config.loader_handle == NULL) {
return SDL_SetError("Failed to load Vulkan Portability library");
}
SDL_strlcpy(_this->vulkan_config.loader_path, foundPath,
SDL_arraysize(_this->vulkan_config.loader_path));
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction(
_this->vulkan_config.loader_handle, "vkGetInstanceProcAddr");
}
if (!vkGetInstanceProcAddr) {
SDL_SetError("Failed to find %s in either executable or %s: %s",
"vkGetInstanceProcAddr",
_this->vulkan_config.loader_path,
(const char *)dlerror());
goto fail;
}
_this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr;
_this->vulkan_config.vkEnumerateInstanceExtensionProperties =
(void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)(
VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties");
if (!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) {
goto fail;
}
extensions = SDL_Vulkan_CreateInstanceExtensionsList(
(PFN_vkEnumerateInstanceExtensionProperties)
_this->vulkan_config.vkEnumerateInstanceExtensionProperties,
&extensionCount);
if (!extensions) {
goto fail;
}
for (Uint32 i = 0; i < extensionCount; i++) {
if (SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
hasSurfaceExtension = SDL_TRUE;
} else if (SDL_strcmp(VK_EXT_METAL_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
hasMetalSurfaceExtension = SDL_TRUE;
} else if (SDL_strcmp(VK_MVK_MACOS_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
hasMacOSSurfaceExtension = SDL_TRUE;
}
}
SDL_free(extensions);
if (!hasSurfaceExtension) {
SDL_SetError("Installed Vulkan Portability library doesn't implement the " VK_KHR_SURFACE_EXTENSION_NAME " extension");
goto fail;
} else if (!hasMetalSurfaceExtension && !hasMacOSSurfaceExtension) {
SDL_SetError("Installed Vulkan Portability library doesn't implement the " VK_EXT_METAL_SURFACE_EXTENSION_NAME " or " VK_MVK_MACOS_SURFACE_EXTENSION_NAME " extensions");
goto fail;
}
return 0;
fail:
SDL_UnloadObject(_this->vulkan_config.loader_handle);
_this->vulkan_config.loader_handle = NULL;
return -1;
}
void Cocoa_Vulkan_UnloadLibrary(SDL_VideoDevice *_this)
{
if (_this->vulkan_config.loader_handle) {
if (_this->vulkan_config.loader_handle != DEFAULT_HANDLE) {
SDL_UnloadObject(_this->vulkan_config.loader_handle);
}
_this->vulkan_config.loader_handle = NULL;
}
}
SDL_bool Cocoa_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
unsigned *count,
const char **names)
{
static const char *const extensionsForCocoa[] = {
VK_KHR_SURFACE_EXTENSION_NAME, VK_EXT_METAL_SURFACE_EXTENSION_NAME
};
if (!_this->vulkan_config.loader_handle) {
SDL_SetError("Vulkan is not loaded");
return SDL_FALSE;
}
return SDL_Vulkan_GetInstanceExtensions_Helper(
count, names, SDL_arraysize(extensionsForCocoa),
extensionsForCocoa);
}
static SDL_bool Cocoa_Vulkan_CreateSurfaceViaMetalView(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
VkSurfaceKHR *surface,
PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT,
PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK)
{
VkResult result;
SDL_MetalView metalview = Cocoa_Metal_CreateView(_this, window);
if (metalview == NULL) {
return SDL_FALSE;
}
if (vkCreateMetalSurfaceEXT) {
VkMetalSurfaceCreateInfoEXT createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
createInfo.pNext = NULL;
createInfo.flags = 0;
createInfo.pLayer = (__bridge const CAMetalLayer *)
Cocoa_Metal_GetLayer(_this, metalview);
result = vkCreateMetalSurfaceEXT(instance, &createInfo, NULL, surface);
if (result != VK_SUCCESS) {
Cocoa_Metal_DestroyView(_this, metalview);
SDL_SetError("vkCreateMetalSurfaceEXT failed: %s",
SDL_Vulkan_GetResultString(result));
return SDL_FALSE;
}
} else {
VkMacOSSurfaceCreateInfoMVK createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
createInfo.pNext = NULL;
createInfo.flags = 0;
createInfo.pView = (const void *)metalview;
result = vkCreateMacOSSurfaceMVK(instance, &createInfo,
NULL, surface);
if (result != VK_SUCCESS) {
Cocoa_Metal_DestroyView(_this, metalview);
SDL_SetError("vkCreateMacOSSurfaceMVK failed: %s",
SDL_Vulkan_GetResultString(result));
return SDL_FALSE;
}
}
/* Unfortunately there's no SDL_Vulkan_DestroySurface function we can call
* Metal_DestroyView from. Right now the metal view's ref count is +2 (one
* from returning a new view object in CreateView, and one because it's
* a subview of the window.) If we release the view here to make it +1, it
* will be destroyed when the window is destroyed. */
CFBridgingRelease(metalview);
return SDL_TRUE;
}
SDL_bool Cocoa_Vulkan_CreateSurface(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
VkSurfaceKHR *surface)
{
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
(PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT =
(PFN_vkCreateMetalSurfaceEXT)vkGetInstanceProcAddr(
instance,
"vkCreateMetalSurfaceEXT");
PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK =
(PFN_vkCreateMacOSSurfaceMVK)vkGetInstanceProcAddr(
instance,
"vkCreateMacOSSurfaceMVK");
VkResult result;
if (!_this->vulkan_config.loader_handle) {
SDL_SetError("Vulkan is not loaded");
return SDL_FALSE;
}
if (!vkCreateMetalSurfaceEXT && !vkCreateMacOSSurfaceMVK) {
SDL_SetError(VK_EXT_METAL_SURFACE_EXTENSION_NAME " or " VK_MVK_MACOS_SURFACE_EXTENSION_NAME
" extensions are not enabled in the Vulkan instance.");
return SDL_FALSE;
}
if (window->flags & SDL_WINDOW_FOREIGN) {
@autoreleasepool {
SDL_CocoaWindowData *data = (__bridge SDL_CocoaWindowData *)window->driverdata;
if (![data.sdlContentView.layer isKindOfClass:[CAMetalLayer class]]) {
[data.sdlContentView setLayer:[CAMetalLayer layer]];
}
if (vkCreateMetalSurfaceEXT) {
VkMetalSurfaceCreateInfoEXT createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
createInfo.pNext = NULL;
createInfo.flags = 0;
createInfo.pLayer = (CAMetalLayer *)data.sdlContentView.layer;
result = vkCreateMetalSurfaceEXT(instance, &createInfo, NULL, surface);
if (result != VK_SUCCESS) {
SDL_SetError("vkCreateMetalSurfaceEXT failed: %s",
SDL_Vulkan_GetResultString(result));
return SDL_FALSE;
}
} else {
VkMacOSSurfaceCreateInfoMVK createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
createInfo.pNext = NULL;
createInfo.flags = 0;
createInfo.pView = (__bridge const void *)data.sdlContentView;
result = vkCreateMacOSSurfaceMVK(instance, &createInfo,
NULL, surface);
if (result != VK_SUCCESS) {
SDL_SetError("vkCreateMacOSSurfaceMVK failed: %s",
SDL_Vulkan_GetResultString(result));
return SDL_FALSE;
}
}
}
} else {
return Cocoa_Vulkan_CreateSurfaceViaMetalView(_this, window, instance, surface, vkCreateMetalSurfaceEXT, vkCreateMacOSSurfaceMVK);
}
return SDL_TRUE;
}
#endif

View File

@ -0,0 +1,173 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_cocoawindow_h_
#define SDL_cocoawindow_h_
#import <Cocoa/Cocoa.h>
#ifdef SDL_VIDEO_OPENGL_EGL
#include "../SDL_egl_c.h"
#endif
@class SDL_CocoaWindowData;
typedef enum
{
PENDING_OPERATION_NONE,
PENDING_OPERATION_ENTER_FULLSCREEN,
PENDING_OPERATION_LEAVE_FULLSCREEN,
PENDING_OPERATION_MINIMIZE
} PendingWindowOperation;
@interface Cocoa_WindowListener : NSResponder <NSWindowDelegate>
{
/* SDL_CocoaWindowData owns this Listener and has a strong reference to it.
* To avoid reference cycles, we could have either a weak or an
* unretained ref to the WindowData. */
__weak SDL_CocoaWindowData *_data;
BOOL observingVisible;
BOOL wasCtrlLeft;
BOOL wasVisible;
BOOL isFullscreenSpace;
BOOL inFullscreenTransition;
PendingWindowOperation pendingWindowOperation;
BOOL isMoving;
NSInteger focusClickPending;
float pendingWindowWarpX, pendingWindowWarpY;
BOOL isDragAreaRunning;
}
- (BOOL)isTouchFromTrackpad:(NSEvent *)theEvent;
- (void)listen:(SDL_CocoaWindowData *)data;
- (void)pauseVisibleObservation;
- (void)resumeVisibleObservation;
- (BOOL)setFullscreenSpace:(BOOL)state;
- (BOOL)isInFullscreenSpace;
- (BOOL)isInFullscreenSpaceTransition;
- (void)addPendingWindowOperation:(PendingWindowOperation)operation;
- (void)close;
- (BOOL)isMoving;
- (BOOL)isMovingOrFocusClickPending;
- (void)setFocusClickPending:(NSInteger)button;
- (void)clearFocusClickPending:(NSInteger)button;
- (void)setPendingMoveX:(float)x Y:(float)y;
- (void)windowDidFinishMoving;
- (void)onMovingOrFocusClickPendingStateCleared;
/* Window delegate functionality */
- (BOOL)windowShouldClose:(id)sender;
- (void)windowDidExpose:(NSNotification *)aNotification;
- (void)windowDidMove:(NSNotification *)aNotification;
- (void)windowDidResize:(NSNotification *)aNotification;
- (void)windowDidMiniaturize:(NSNotification *)aNotification;
- (void)windowDidDeminiaturize:(NSNotification *)aNotification;
- (void)windowDidBecomeKey:(NSNotification *)aNotification;
- (void)windowDidResignKey:(NSNotification *)aNotification;
- (void)windowDidChangeBackingProperties:(NSNotification *)aNotification;
- (void)windowDidChangeScreenProfile:(NSNotification *)aNotification;
- (void)windowDidChangeScreen:(NSNotification *)aNotification;
- (void)windowWillEnterFullScreen:(NSNotification *)aNotification;
- (void)windowDidEnterFullScreen:(NSNotification *)aNotification;
- (void)windowWillExitFullScreen:(NSNotification *)aNotification;
- (void)windowDidExitFullScreen:(NSNotification *)aNotification;
- (NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions;
/* See if event is in a drag area, toggle on window dragging. */
- (BOOL)processHitTest:(NSEvent *)theEvent;
/* Window event handling */
- (void)mouseDown:(NSEvent *)theEvent;
- (void)rightMouseDown:(NSEvent *)theEvent;
- (void)otherMouseDown:(NSEvent *)theEvent;
- (void)mouseUp:(NSEvent *)theEvent;
- (void)rightMouseUp:(NSEvent *)theEvent;
- (void)otherMouseUp:(NSEvent *)theEvent;
- (void)mouseMoved:(NSEvent *)theEvent;
- (void)mouseDragged:(NSEvent *)theEvent;
- (void)rightMouseDragged:(NSEvent *)theEvent;
- (void)otherMouseDragged:(NSEvent *)theEvent;
- (void)scrollWheel:(NSEvent *)theEvent;
- (void)touchesBeganWithEvent:(NSEvent *)theEvent;
- (void)touchesMovedWithEvent:(NSEvent *)theEvent;
- (void)touchesEndedWithEvent:(NSEvent *)theEvent;
- (void)touchesCancelledWithEvent:(NSEvent *)theEvent;
/* Touch event handling */
- (void)handleTouches:(NSTouchPhase)phase withEvent:(NSEvent *)theEvent;
@end
/* *INDENT-ON* */
@class SDLOpenGLContext;
@class SDL_CocoaVideoData;
@interface SDL_CocoaWindowData : NSObject
@property(nonatomic) SDL_Window *window;
@property(nonatomic) NSWindow *nswindow;
@property(nonatomic) NSView *sdlContentView;
@property(nonatomic) NSMutableArray *nscontexts;
@property(nonatomic) SDL_bool created;
@property(nonatomic) SDL_bool inWindowFullscreenTransition;
@property(nonatomic) NSInteger window_number;
@property(nonatomic) NSInteger flash_request;
@property(nonatomic) SDL_Window *keyboard_focus;
@property(nonatomic) Cocoa_WindowListener *listener;
@property(nonatomic) SDL_CocoaVideoData *videodata;
#ifdef SDL_VIDEO_OPENGL_EGL
@property(nonatomic) EGLSurface egl_surface;
#endif
@end
extern int Cocoa_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int Cocoa_CreateWindowFrom(SDL_VideoDevice *_this, SDL_Window *window,
const void *data);
extern void Cocoa_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
extern int Cocoa_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon);
extern int Cocoa_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window);
extern void Cocoa_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window);
extern void Cocoa_SetWindowMinimumSize(SDL_VideoDevice *_this, SDL_Window *window);
extern void Cocoa_SetWindowMaximumSize(SDL_VideoDevice *_this, SDL_Window *window);
extern void Cocoa_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h);
extern int Cocoa_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opacity);
extern void Cocoa_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void Cocoa_HideWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void Cocoa_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void Cocoa_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void Cocoa_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void Cocoa_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void Cocoa_SetWindowBordered(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool bordered);
extern void Cocoa_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool resizable);
extern void Cocoa_SetWindowAlwaysOnTop(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool on_top);
extern void Cocoa_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen);
extern void *Cocoa_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t *size);
extern SDL_DisplayID Cocoa_GetDisplayForWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void Cocoa_SetWindowMouseRect(SDL_VideoDevice *_this, SDL_Window *window);
extern void Cocoa_SetWindowMouseGrab(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed);
extern void Cocoa_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int Cocoa_GetWindowWMInfo(SDL_VideoDevice *_this, SDL_Window *window, struct SDL_SysWMinfo *info);
extern int Cocoa_SetWindowHitTest(SDL_Window *window, SDL_bool enabled);
extern void Cocoa_AcceptDragAndDrop(SDL_Window *window, SDL_bool accept);
extern int Cocoa_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
#endif /* SDL_cocoawindow_h_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,38 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_DUMMY
/* Being a null driver, there's no event stream. We just define stubs for
most of the API. */
#include "../../events/SDL_events_c.h"
#include "SDL_nullvideo.h"
#include "SDL_nullevents_c.h"
void DUMMY_PumpEvents(SDL_VideoDevice *_this)
{
/* do nothing. */
}
#endif /* SDL_VIDEO_DRIVER_DUMMY */

View File

@ -0,0 +1,31 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_nullevents_c_h_
#define SDL_nullevents_c_h_
#include "SDL_internal.h"
#include "SDL_nullvideo.h"
extern void DUMMY_PumpEvents(SDL_VideoDevice *_this);
#endif /* SDL_nullevents_c_h_ */

View File

@ -0,0 +1,82 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_DUMMY
#include "../SDL_sysvideo.h"
#include "SDL_nullframebuffer_c.h"
#define DUMMY_SURFACE "_SDL_DummySurface"
int SDL_DUMMY_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, Uint32 *format, void **pixels, int *pitch)
{
SDL_Surface *surface;
const Uint32 surface_format = SDL_PIXELFORMAT_XRGB8888;
int w, h;
/* Free the old framebuffer surface */
SDL_DUMMY_DestroyWindowFramebuffer(_this, window);
/* Create a new one */
SDL_GetWindowSizeInPixels(window, &w, &h);
surface = SDL_CreateSurface(w, h, surface_format);
if (surface == NULL) {
return -1;
}
/* Save the info and return! */
SDL_SetWindowData(window, DUMMY_SURFACE, surface);
*format = surface_format;
*pixels = surface->pixels;
*pitch = surface->pitch;
return 0;
}
int SDL_DUMMY_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rects, int numrects)
{
static int frame_number;
SDL_Surface *surface;
surface = (SDL_Surface *)SDL_GetWindowData(window, DUMMY_SURFACE);
if (surface == NULL) {
return SDL_SetError("Couldn't find dummy surface for window");
}
/* Send the data to the display */
if (SDL_getenv("SDL_VIDEO_DUMMY_SAVE_FRAMES")) {
char file[128];
(void)SDL_snprintf(file, sizeof(file), "SDL_window%" SDL_PRIu32 "-%8.8d.bmp",
SDL_GetWindowID(window), ++frame_number);
SDL_SaveBMP(surface, file);
}
return 0;
}
void SDL_DUMMY_DestroyWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_Surface *surface;
surface = (SDL_Surface *)SDL_SetWindowData(window, DUMMY_SURFACE, NULL);
SDL_DestroySurface(surface);
}
#endif /* SDL_VIDEO_DRIVER_DUMMY */

View File

@ -0,0 +1,31 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_nullframebuffer_c_h_
#define SDL_nullframebuffer_c_h_
#include "SDL_internal.h"
extern int SDL_DUMMY_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, Uint32 *format, void **pixels, int *pitch);
extern int SDL_DUMMY_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rects, int numrects);
extern void SDL_DUMMY_DestroyWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window);
#endif /* SDL_nullframebuffer_c_h_ */

View File

@ -0,0 +1,166 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_DUMMY
/* Dummy SDL video driver implementation; this is just enough to make an
* SDL-based application THINK it's got a working video driver, for
* applications that call SDL_Init(SDL_INIT_VIDEO) when they don't need it,
* and also for use as a collection of stubs when porting SDL to a new
* platform for which you haven't yet written a valid video driver.
*
* This is also a great way to determine bottlenecks: if you think that SDL
* is a performance problem for a given platform, enable this driver, and
* then see if your application runs faster without video overhead.
*
* Initial work by Ryan C. Gordon (icculus@icculus.org). A good portion
* of this was cut-and-pasted from Stephane Peter's work in the AAlib
* SDL video driver. Renamed to "DUMMY" by Sam Lantinga.
*/
#include "../SDL_sysvideo.h"
#include "../SDL_pixels_c.h"
#include "../../events/SDL_events_c.h"
#ifdef SDL_INPUT_LINUXEV
#include "../../core/linux/SDL_evdev.h"
#endif
#include "SDL_nullvideo.h"
#include "SDL_nullevents_c.h"
#include "SDL_nullframebuffer_c.h"
#define DUMMYVID_DRIVER_NAME "dummy"
#define DUMMYVID_DRIVER_EVDEV_NAME "evdev"
/* Initialization/Query functions */
static int DUMMY_VideoInit(SDL_VideoDevice *_this);
static void DUMMY_VideoQuit(SDL_VideoDevice *_this);
/* DUMMY driver bootstrap functions */
static int DUMMY_Available(const char *enable_hint)
{
const char *hint = SDL_GetHint(SDL_HINT_VIDEO_DRIVER);
if (hint) {
if (SDL_strcmp(hint, enable_hint) == 0) {
return 1;
}
}
return 0;
}
static void DUMMY_DeleteDevice(SDL_VideoDevice *device)
{
SDL_free(device);
}
static SDL_VideoDevice *DUMMY_InternalCreateDevice(const char *enable_hint)
{
SDL_VideoDevice *device;
if (!DUMMY_Available(enable_hint)) {
return 0;
}
/* Initialize all variables that we clean on shutdown */
device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
if (device == NULL) {
SDL_OutOfMemory();
return 0;
}
device->is_dummy = SDL_TRUE;
/* Set the function pointers */
device->VideoInit = DUMMY_VideoInit;
device->VideoQuit = DUMMY_VideoQuit;
device->PumpEvents = DUMMY_PumpEvents;
device->CreateWindowFramebuffer = SDL_DUMMY_CreateWindowFramebuffer;
device->UpdateWindowFramebuffer = SDL_DUMMY_UpdateWindowFramebuffer;
device->DestroyWindowFramebuffer = SDL_DUMMY_DestroyWindowFramebuffer;
device->free = DUMMY_DeleteDevice;
return device;
}
static SDL_VideoDevice *DUMMY_CreateDevice(void)
{
return DUMMY_InternalCreateDevice(DUMMYVID_DRIVER_NAME);
}
VideoBootStrap DUMMY_bootstrap = {
DUMMYVID_DRIVER_NAME, "SDL dummy video driver",
DUMMY_CreateDevice
};
#ifdef SDL_INPUT_LINUXEV
static void DUMMY_EVDEV_Poll(SDL_VideoDevice *_this)
{
(void)_this;
SDL_EVDEV_Poll();
}
static SDL_VideoDevice *DUMMY_EVDEV_CreateDevice(void)
{
SDL_VideoDevice *device = DUMMY_InternalCreateDevice(DUMMYVID_DRIVER_EVDEV_NAME);
if (device) {
device->PumpEvents = DUMMY_EVDEV_Poll;
}
return device;
}
VideoBootStrap DUMMY_evdev_bootstrap = {
DUMMYVID_DRIVER_EVDEV_NAME, "SDL dummy video driver with evdev",
DUMMY_EVDEV_CreateDevice
};
#endif /* SDL_INPUT_LINUXEV */
int DUMMY_VideoInit(SDL_VideoDevice *_this)
{
SDL_DisplayMode mode;
/* Use a fake 32-bpp desktop mode */
SDL_zero(mode);
mode.format = SDL_PIXELFORMAT_XRGB8888;
mode.w = 1024;
mode.h = 768;
if (SDL_AddBasicVideoDisplay(&mode) == 0) {
return -1;
}
#ifdef SDL_INPUT_LINUXEV
SDL_EVDEV_Init();
#endif
/* We're done! */
return 0;
}
void DUMMY_VideoQuit(SDL_VideoDevice *_this)
{
#ifdef SDL_INPUT_LINUXEV
SDL_EVDEV_Quit();
#endif
}
#endif /* SDL_VIDEO_DRIVER_DUMMY */

View File

@ -0,0 +1,28 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_nullvideo_h_
#define SDL_nullvideo_h_
#include "../SDL_sysvideo.h"
#endif /* SDL_nullvideo_h_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,31 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_emscriptenevents_h_
#define SDL_emscriptenevents_h_
#include "SDL_emscriptenvideo.h"
extern void Emscripten_RegisterEventHandlers(SDL_WindowData *data);
extern void Emscripten_UnregisterEventHandlers(SDL_WindowData *data);
extern EM_BOOL Emscripten_HandleCanvasResize(int eventType, const void *reserved, void *userData);
#endif /* SDL_emscriptenevents_h_ */

View File

@ -0,0 +1,161 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_EMSCRIPTEN
#include "SDL_emscriptenvideo.h"
#include "SDL_emscriptenframebuffer.h"
#include <emscripten/threading.h>
int Emscripten_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, Uint32 *format, void **pixels, int *pitch)
{
SDL_Surface *surface;
const Uint32 surface_format = SDL_PIXELFORMAT_XBGR8888;
int w, h;
/* Free the old framebuffer surface */
SDL_WindowData *data = window->driverdata;
surface = data->surface;
SDL_DestroySurface(surface);
/* Create a new one */
SDL_GetWindowSizeInPixels(window, &w, &h);
surface = SDL_CreateSurface(w, h, surface_format);
if (surface == NULL) {
return -1;
}
/* Save the info and return! */
data->surface = surface;
*format = surface_format;
*pixels = surface->pixels;
*pitch = surface->pitch;
return 0;
}
int Emscripten_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rects, int numrects)
{
SDL_Surface *surface;
SDL_WindowData *data = window->driverdata;
surface = data->surface;
if (surface == NULL) {
return SDL_SetError("Couldn't find framebuffer surface for window");
}
/* Send the data to the display */
/* *INDENT-OFF* */ /* clang-format off */
MAIN_THREAD_EM_ASM({
var w = $0;
var h = $1;
var pixels = $2;
var canvasId = UTF8ToString($3);
var canvas = document.querySelector(canvasId);
//TODO: this should store a context per canvas
if (!Module['SDL3']) Module['SDL3'] = {};
var SDL3 = Module['SDL3'];
if (SDL3.ctxCanvas !== canvas) {
SDL3.ctx = Module['createContext'](canvas, false, true);
SDL3.ctxCanvas = canvas;
}
if (SDL3.w !== w || SDL3.h !== h || SDL3.imageCtx !== SDL3.ctx) {
SDL3.image = SDL3.ctx.createImageData(w, h);
SDL3.w = w;
SDL3.h = h;
SDL3.imageCtx = SDL3.ctx;
}
var data = SDL3.image.data;
var src = pixels >> 2;
var dst = 0;
var num;
if (SDL3.data32Data !== data) {
SDL3.data32 = new Int32Array(data.buffer);
SDL3.data8 = new Uint8Array(data.buffer);
SDL3.data32Data = data;
}
var data32 = SDL3.data32;
num = data32.length;
// logically we need to do
// while (dst < num) {
// data32[dst++] = HEAP32[src++] | 0xff000000
// }
// the following code is faster though, because
// .set() is almost free - easily 10x faster due to
// native SDL_memcpy efficiencies, and the remaining loop
// just stores, not load + store, so it is faster
data32.set(HEAP32.subarray(src, src + num));
var data8 = SDL3.data8;
var i = 3;
var j = i + 4*num;
if (num % 8 == 0) {
// unrolling gives big speedups
while (i < j) {
data8[i] = 0xff;
i = i + 4 | 0;
data8[i] = 0xff;
i = i + 4 | 0;
data8[i] = 0xff;
i = i + 4 | 0;
data8[i] = 0xff;
i = i + 4 | 0;
data8[i] = 0xff;
i = i + 4 | 0;
data8[i] = 0xff;
i = i + 4 | 0;
data8[i] = 0xff;
i = i + 4 | 0;
data8[i] = 0xff;
i = i + 4 | 0;
}
} else {
while (i < j) {
data8[i] = 0xff;
i = i + 4 | 0;
}
}
SDL3.ctx.putImageData(SDL3.image, 0, 0);
}, surface->w, surface->h, surface->pixels, data->canvas_id);
/* *INDENT-ON* */ /* clang-format on */
if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, SDL_TRUE)) {
/* give back control to browser for screen refresh */
emscripten_sleep(0);
}
return 0;
}
void Emscripten_DestroyWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
SDL_DestroySurface(data->surface);
data->surface = NULL;
}
#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */

View File

@ -0,0 +1,30 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_emscriptenframebuffer_h_
#define SDL_emscriptenframebuffer_h_
extern int Emscripten_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, Uint32 *format, void **pixels, int *pitch);
extern int Emscripten_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rects, int numrects);
extern void Emscripten_DestroyWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window);
#endif /* SDL_emscriptenframebuffer_h_ */

View File

@ -0,0 +1,251 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_EMSCRIPTEN
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
#include <emscripten/threading.h>
#include "SDL_emscriptenmouse.h"
#include "SDL_emscriptenvideo.h"
#include "../../events/SDL_mouse_c.h"
static SDL_Cursor *Emscripten_CreateCursorFromString(const char *cursor_str, SDL_bool is_custom)
{
SDL_Cursor *cursor;
Emscripten_CursorData *curdata;
cursor = SDL_calloc(1, sizeof(SDL_Cursor));
if (cursor) {
curdata = (Emscripten_CursorData *)SDL_calloc(1, sizeof(*curdata));
if (curdata == NULL) {
SDL_OutOfMemory();
SDL_free(cursor);
return NULL;
}
curdata->system_cursor = cursor_str;
curdata->is_custom = is_custom;
cursor->driverdata = curdata;
} else {
SDL_OutOfMemory();
}
return cursor;
}
static SDL_Cursor *Emscripten_CreateDefaultCursor()
{
return Emscripten_CreateCursorFromString("default", SDL_FALSE);
}
EM_JS_DEPS(sdlmouse, "$stringToUTF8,$UTF8ToString");
static SDL_Cursor *Emscripten_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
{
const char *cursor_url = NULL;
SDL_Surface *conv_surf;
conv_surf = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888);
if (conv_surf == NULL) {
return NULL;
}
/* *INDENT-OFF* */ /* clang-format off */
cursor_url = (const char *)MAIN_THREAD_EM_ASM_INT({
var w = $0;
var h = $1;
var hot_x = $2;
var hot_y = $3;
var pixels = $4;
var canvas = document.createElement("canvas");
canvas.width = w;
canvas.height = h;
var ctx = canvas.getContext("2d");
var image = ctx.createImageData(w, h);
var data = image.data;
var src = pixels >> 2;
var data32 = new Int32Array(data.buffer);
data32.set(HEAP32.subarray(src, src + data32.length));
ctx.putImageData(image, 0, 0);
var url = hot_x === 0 && hot_y === 0
? "url(" + canvas.toDataURL() + "), auto"
: "url(" + canvas.toDataURL() + ") " + hot_x + " " + hot_y + ", auto";
var urlBuf = _malloc(url.length + 1);
stringToUTF8(url, urlBuf, url.length + 1);
return urlBuf;
}, surface->w, surface->h, hot_x, hot_y, conv_surf->pixels);
/* *INDENT-ON* */ /* clang-format on */
SDL_DestroySurface(conv_surf);
return Emscripten_CreateCursorFromString(cursor_url, SDL_TRUE);
}
static SDL_Cursor *Emscripten_CreateSystemCursor(SDL_SystemCursor id)
{
const char *cursor_name = NULL;
switch (id) {
case SDL_SYSTEM_CURSOR_ARROW:
cursor_name = "default";
break;
case SDL_SYSTEM_CURSOR_IBEAM:
cursor_name = "text";
break;
case SDL_SYSTEM_CURSOR_WAIT:
cursor_name = "wait";
break;
case SDL_SYSTEM_CURSOR_CROSSHAIR:
cursor_name = "crosshair";
break;
case SDL_SYSTEM_CURSOR_WAITARROW:
cursor_name = "progress";
break;
case SDL_SYSTEM_CURSOR_SIZENWSE:
cursor_name = "nwse-resize";
break;
case SDL_SYSTEM_CURSOR_SIZENESW:
cursor_name = "nesw-resize";
break;
case SDL_SYSTEM_CURSOR_SIZEWE:
cursor_name = "ew-resize";
break;
case SDL_SYSTEM_CURSOR_SIZENS:
cursor_name = "ns-resize";
break;
case SDL_SYSTEM_CURSOR_SIZEALL:
cursor_name = "move";
break;
case SDL_SYSTEM_CURSOR_NO:
cursor_name = "not-allowed";
break;
case SDL_SYSTEM_CURSOR_HAND:
cursor_name = "pointer";
break;
default:
SDL_assert(0);
return NULL;
}
return Emscripten_CreateCursorFromString(cursor_name, SDL_FALSE);
}
static void Emscripten_FreeCursor(SDL_Cursor *cursor)
{
Emscripten_CursorData *curdata;
if (cursor) {
curdata = (Emscripten_CursorData *)cursor->driverdata;
if (curdata != NULL) {
if (curdata->is_custom) {
SDL_free((char *)curdata->system_cursor);
}
SDL_free(cursor->driverdata);
}
SDL_free(cursor);
}
}
static int Emscripten_ShowCursor(SDL_Cursor *cursor)
{
Emscripten_CursorData *curdata;
if (SDL_GetMouseFocus() != NULL) {
if (cursor && cursor->driverdata) {
curdata = (Emscripten_CursorData *)cursor->driverdata;
if (curdata->system_cursor) {
/* *INDENT-OFF* */ /* clang-format off */
MAIN_THREAD_EM_ASM({
if (Module['canvas']) {
Module['canvas'].style['cursor'] = UTF8ToString($0);
}
}, curdata->system_cursor);
/* *INDENT-ON* */ /* clang-format on */
}
} else {
/* *INDENT-OFF* */ /* clang-format off */
MAIN_THREAD_EM_ASM(
if (Module['canvas']) {
Module['canvas'].style['cursor'] = 'none';
}
);
/* *INDENT-ON* */ /* clang-format on */
}
}
return 0;
}
static int Emscripten_SetRelativeMouseMode(SDL_bool enabled)
{
SDL_Window *window;
SDL_WindowData *window_data;
/* TODO: pointer lock isn't actually enabled yet */
if (enabled) {
window = SDL_GetMouseFocus();
if (window == NULL) {
return -1;
}
window_data = window->driverdata;
if (emscripten_request_pointerlock(window_data->canvas_id, 1) >= EMSCRIPTEN_RESULT_SUCCESS) {
return 0;
}
} else {
if (emscripten_exit_pointerlock() >= EMSCRIPTEN_RESULT_SUCCESS) {
return 0;
}
}
return -1;
}
void Emscripten_InitMouse()
{
SDL_Mouse *mouse = SDL_GetMouse();
mouse->CreateCursor = Emscripten_CreateCursor;
mouse->ShowCursor = Emscripten_ShowCursor;
mouse->FreeCursor = Emscripten_FreeCursor;
mouse->CreateSystemCursor = Emscripten_CreateSystemCursor;
mouse->SetRelativeMouseMode = Emscripten_SetRelativeMouseMode;
SDL_SetDefaultCursor(Emscripten_CreateDefaultCursor());
}
void Emscripten_FiniMouse()
{
}
#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */

View File

@ -0,0 +1,37 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_emscriptenmouse_h_
#define SDL_emscriptenmouse_h_
typedef struct _Emscripten_CursorData
{
const char *system_cursor;
SDL_bool is_custom;
} Emscripten_CursorData;
extern void
Emscripten_InitMouse();
extern void
Emscripten_FiniMouse();
#endif /* SDL_emscriptenmouse_h_ */

View File

@ -0,0 +1,158 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_EMSCRIPTEN
#include <emscripten/emscripten.h>
#include <emscripten/html5_webgl.h>
#include <GLES2/gl2.h>
#include "SDL_emscriptenvideo.h"
#include "SDL_emscriptenopengles.h"
int Emscripten_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
return 0;
}
void Emscripten_GLES_UnloadLibrary(SDL_VideoDevice *_this)
{
}
SDL_FunctionPointer Emscripten_GLES_GetProcAddress(SDL_VideoDevice *_this, const char *proc)
{
return emscripten_webgl_get_proc_address(proc);
}
int Emscripten_GLES_SetSwapInterval(SDL_VideoDevice *_this, int interval)
{
if (interval < 0) {
return SDL_SetError("Late swap tearing currently unsupported");
} else if (interval == 0) {
emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, 0);
} else {
emscripten_set_main_loop_timing(EM_TIMING_RAF, interval);
}
return 0;
}
int Emscripten_GLES_GetSwapInterval(SDL_VideoDevice *_this, int *interval)
{
int mode, value;
emscripten_get_main_loop_timing(&mode, &value);
if (mode == EM_TIMING_RAF) {
*interval = value;
return 0;
} else {
*interval = 0;
return 0;
}
}
SDL_GLContext Emscripten_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *window_data;
EmscriptenWebGLContextAttributes attribs;
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context;
emscripten_webgl_init_context_attributes(&attribs);
attribs.alpha = _this->gl_config.alpha_size > 0;
attribs.depth = _this->gl_config.depth_size > 0;
attribs.stencil = _this->gl_config.stencil_size > 0;
attribs.antialias = _this->gl_config.multisamplebuffers == 1;
if (_this->gl_config.major_version == 3)
attribs.majorVersion = 2; /* WebGL 2.0 ~= GLES 3.0 */
window_data = window->driverdata;
if (window_data->gl_context) {
SDL_SetError("Cannot create multiple webgl contexts per window");
return NULL;
}
context = emscripten_webgl_create_context(window_data->canvas_id, &attribs);
if (context < 0) {
SDL_SetError("Could not create webgl context");
return NULL;
}
if (emscripten_webgl_make_context_current(context) != EMSCRIPTEN_RESULT_SUCCESS) {
emscripten_webgl_destroy_context(context);
return NULL;
}
window_data->gl_context = (SDL_GLContext)context;
return (SDL_GLContext)context;
}
int Emscripten_GLES_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context)
{
SDL_Window *window;
/* remove the context from its window */
for (window = _this->windows; window != NULL; window = window->next) {
SDL_WindowData *window_data = window->driverdata;
if (window_data->gl_context == context) {
window_data->gl_context = NULL;
}
}
emscripten_webgl_destroy_context((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)context);
return 0;
}
int Emscripten_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, SDL_TRUE)) {
/* give back control to browser for screen refresh */
emscripten_sleep(0);
}
return 0;
}
int Emscripten_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context)
{
/* it isn't possible to reuse contexts across canvases */
if (window && context) {
SDL_WindowData *window_data = window->driverdata;
if (context != window_data->gl_context) {
return SDL_SetError("Cannot make context current to another window");
}
}
if (emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)context) != EMSCRIPTEN_RESULT_SUCCESS) {
return SDL_SetError("Unable to make context current");
}
return 0;
}
#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */

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